dealer3 language reference — engine 1.1.0 ========================================= Every function, operator and statement dealer3 accepts. Generated from the engine's own vocabulary, so it cannot list something the parser rejects, or leave out something it accepts. Run it: https://bridge-craftwork.com/dealer3/ Source: https://github.com/bridge-craftwork/dealer3 Same content as https://bridge-craftwork.com/dealer3/reference STATEMENTS ---------- condition Form: condition Summary: Keep a deal when the expression is anything other than zero. Example: condition hcp(north) >= 15 && shape(north, any 5332) Note: One condition applies to the whole script: a second `condition` replaces the first rather than adding to it. Join tests with `&&` instead. produce Form: produce Summary: Stop once this many deals have matched. Example: produce 25 Note: The command line's `-p` overrides this. generate Form: generate Summary: Stop after dealing this many hands, however few matched. Example: generate 100000 Note: Whichever limit is reached first ends the run, so this is the guard against a condition so narrow that nothing satisfies it. The command line's `-g` overrides it. action Form: action , , ... Summary: What to do with each matching deal: a print format, and any averages or frequencies to accumulate. Example: action printoneline, average "hcp" hcp(north) Note: With no `action`, the deals are printed. printes Form: printes( | "string" | \n, ...) Summary: Print a line of your own for each matching deal, from expressions and literal text. Example: printes("N=", hcp(north), \n) Note: Nothing is added between terms and no line ends unless you ask for one. A line ending is a bare `\n` in the list, not an escape inside a string: the original's lexer reads no escapes between quotes, so "\n" there is a backslash and an `n`. print Form: print(, ...) Summary: Lay out one seat's hands at the end of the run, four boards to a page. Example: print(north) Note: A line-printer format from the original: twenty columns a board, spades down to clubs, a form feed after each seat. Seats come out north, east, south, west whatever order they are named in. average Form: average ["label"] Summary: Report the mean of the expression over the deals that matched. Example: average "north hcp" hcp(north) Note: Valid on its own, or inside an `action` list. frequency Form: frequency ["label"] (, , [, , , ]) Summary: Report a histogram of the expression over the deals that matched, counting from low to high inclusive. A second expression and range makes it a two-dimensional table instead. Example: frequency "north hcp" (hcp(north), 10, 20) Note: Values outside a range are still counted, as the Low and High rows. With a second expression the report becomes a cross-tabulation: the first expression down the rows, the second across the columns, a Low and a High on each axis, and marginal sums along the right and the bottom. `frequency "hcp vs spades" (hcp(north), 8, 12, spades(north), 3, 5)` is the original's own form, and the table dealer3 prints is byte-for-byte the one dealer.exe prints for the same deals. pointcount Form: pointcount ... Summary: Re-scale the high card points. Values run from the ace downwards, and ranks not reached score nothing. Example: pointcount 6 4 2 1 Note: That example is the 6-4-2-1 scale: ace 6, king 4, queen 2, jack 1, everything else 0. At most thirteen values, one per rank. altcount Form: altcount ... Summary: Re-scale one of the other counts, the same way `pointcount` re-scales the high card points. Example: altcount 2 1 1 1 Note: The number is a row of the original's count table, and **it is not the `ptN` number**: row 0 is `hcp`, row 1 is `controls`, and row 2 is `pt0`. So `altcount 2` sets `tens`, and `altcount 0` overwrites `hcp`. Rows run 0 to 11. `losers` reads the `controls` and `top3` rows, so redefining either moves the loser count with it. dealer Form: dealer Summary: Records who dealt. Affects the output only, never which deals are produced. Example: dealer south vulnerable Form: vulnerable none | ns | ew | all Summary: Records the vulnerability. Affects the output only, never which deals are produced. Example: vulnerable ns title Form: title "" Summary: Names the run, filling the `[Event]` tag of PBN output. `-T` wins when both are given. Example: title "Weak two openings" Note: DealerV2_4's. Nearly every script written for it opens with one, which is why dealer3 accepts it as well as the switch. seed Form: seed Summary: Fixes the random seed, so the run reproduces. `-s` wins when both are given. Example: seed 42 Note: DealerV2_4's. Before dealer3 accepted it the word parsed as a variable and the number as an expression, so the seed a script asked for was silently ignored. predeal Form: predeal , , ... [ , ...] Summary: Places cards in a hand before shuffling; the rest of the deal is dealt around them. A holding is a suit letter followed by its ranks, using T for the ten. One statement may name several seats: the holdings of a seat are separated by commas and the seats are not. Example: predeal north SAKQ,HT98 south SJ32 Note: The original dealer also restricts a suit's length by writing `spades(north) == 5` in a `predeal`; dealer3 does not, so put that in the `condition` instead. csvrpt Form: csvrpt(, , ...) Summary: Writes one comma-separated row per matching deal. A term is an expression, a quoted string, a compass for that hand, `ns` or `ew` for a partnership's two hands, the word `deal` for all four, or `trix(...)` for double-dummy tricks. Example: csvrpt(deal, hcp(north), "north") Note: Command-line only: the browser app has nowhere to write a file. `trix(compass)` adds five columns — the tricks that seat takes in clubs, diamonds, hearts, spades and notrump — and `trix(deal)` adds twenty, four seats in the order `deal` uses. It is a term rather than a function because it is more than one number. The solving is the same work `tricks()` does and is remembered per deal, so naming both costs one search each, not two. printrpt Form: printrpt(, , ...) Summary: Writes one comma-separated row per matching deal to the screen. The terms are `csvrpt`'s: an expression, a quoted string, a compass for that hand, `ns` or `ew` for a partnership's two hands, the word `deal` for all four, or `trix(...)`. Example: printrpt("deal ", deal, hcp(south)) Note: DealerV2_4's screen counterpart of `csvrpt`, and the same row — so the two share a renderer here rather than merely resembling one another. Thirteen of its regression scripts use it. Unlike `csvrpt` it works in the browser, where the rows appear in the Text view with `printes` output. 6.25, 3.0, .5 Form: 6.25, 3.0, .5 Summary: A decimal is sugar for a hundred times itself: `6.25` is 625, `.5` is 50. DealerV2_4 calls these dotnums and computes them the same way. Example: altcount 8 6.25 4.25 1.5 0.75 .25 Note: **Not a fraction.** Nothing tracks a scale, so a plain `6` is still 6 and `6.25 + 6` is 631. Keeping the units straight is the script's job, and DealerV2_4's own scripts do it by redefining the counts in the same scale: after `pointcount 4.5 3.0 1.5 0.75 .25` the `hcp()` of an ace-king is 750, and only then does `11.00 <= hcp(west)` mean what it looks like. Written against the ordinary scale it is `1100 <= hcp(west)`, which is never true. At most two digits either side of the point, which is DealerV2_4's limit and not an arbitrary one: `123.45` is not a number there but `123` followed by `.45`, and a syntax error. dealer.exe has no decimals at all — its lexer has only `[0-9]+` — so any script using one is a script that will not run on BBO. = Form: = Summary: Names an expression so a long condition can be written in pieces. The name stands for the expression and is worked out afresh for every deal. Example: fit = spades(north) + spades(south) Form: Summary: An expression on its own is the condition, so the `condition` keyword can be left off. Example: hcp(north) >= 20 Note: As with `condition`, only the last one in the script counts. FUNCTIONS --------- [Hand evaluation] hcp Signature: hcp(compass) · hcp(compass, suit) Summary: High card points on the 4-3-2-1 scale: ace 4, king 3, queen 2, jack 1. With a suit, only that suit's cards are counted. Example: hcp(north) >= 12 && hcp(north, spades) >= 4 Note: The 4-3-2-1 scale is the default, not a fixture: a `pointcount` statement replaces it for the whole script. controls Signature: controls(compass) · controls(compass, suit) Summary: Controls: each ace counts 2 and each king 1. Example: controls(north) >= 5 losers Signature: losers(compass) · losers(compass, suit) Summary: Losing trick count: a void is 0; a singleton is 0 holding the ace and 1 otherwise; a doubleton is 0 holding A-K, 1 holding the ace or the king and 2 otherwise; three cards or more is 3 minus the number of A, K and Q held. Example: losers(south) <= 6 quality Signature: quality(compass, suit) Summary: Quality of one suit, by the algorithm published in The Bridge World, October 1982, multiplied by 100 — so 450 means 4.50. Example: quality(north, spades) >= 400 Note: Each honour is worth a multiple of ten times the suit length — ace 4×, king 3×, queen 2×, jack 1× — with an extra allowance for length beyond six cards, and for the ten and nine when they are supported. dealer3's implementation follows the original `c4.c` line for line, and was checked against dealer.exe's own output. cccc Signature: cccc(compass) Summary: Whole-hand evaluation by the algorithm published in The Bridge World, October 1982, multiplied by 100 — a minimum opening bid is around 1200. Example: cccc(north) >= 1200 Note: Honours are valued by suit with penalties for short or unsupported ones, each suit's `quality` is added, and short suits contribute shape points. dealer3's implementation follows the original `c4.c` line for line, and was checked against dealer.exe's own output. hcps Signature: hcps(compass) · hcps(compass, suit) Alias of: hcp Summary: Plural spelling of `hcp`. Example: hcps(north) >= 12 control Signature: control(compass) · control(compass, suit) Alias of: controls Summary: Singular spelling of `controls`. Example: control(north) >= 5 loser Signature: loser(compass) · loser(compass, suit) Alias of: losers Summary: Singular spelling of `losers`. Example: loser(south) <= 6 [Suit length] spades Signature: spades(compass) Summary: Number of spades held. Example: spades(north) + spades(south) >= 8 hearts Signature: hearts(compass) Summary: Number of hearts held. Example: hearts(north) + hearts(south) >= 8 diamonds Signature: diamonds(compass) Summary: Number of diamonds held. Example: diamonds(west) >= 6 clubs Signature: clubs(compass) Summary: Number of clubs held. Example: clubs(east) <= 2 spade Signature: spade(compass) Alias of: spades Summary: Singular spelling of `spades`. Example: spade(north) >= 5 heart Signature: heart(compass) Alias of: hearts Summary: Singular spelling of `hearts`. Example: heart(north) >= 5 diamond Signature: diamond(compass) Alias of: diamonds Summary: Singular spelling of `diamonds`. Example: diamond(north) >= 5 club Signature: club(compass) Alias of: clubs Summary: Singular spelling of `clubs`. Example: club(north) >= 5 [Shape and cards] shape Signature: shape(compass, pattern) Summary: True when the hand matches the pattern. Four digits are lengths in spades, hearts, diamonds, clubs order; `x` matches any length; `any` allows the suits in any order; `+` adds a pattern and `-` excludes one. Example: shape(north, any 4333 + any 4432 + any 5332) Note: Matching is a table lookup over all 560 shapes, so a long pattern list costs no more than a short one. **Braces instead of parentheses** take François Dellacherie's shape language, which says the same things far more briefly: `5+` is at least five, `2-` at most two, `[3-5]` a range, `(431)` the remaining suits in any order, `M` either major and `m` either minor, and `:` attaches a condition on the suit lengths `s h d c`, with `,` for and. So `shape{north, 4M(3+3+2+)}` is the twelve patterns above, and it is expanded before the script is parsed. A `+` or `-` joining two patterns needs a space on both sides, which is what keeps the one in `h+s>=10` inside its condition; and only one `M` and one `m` fit in a pattern, two of a colour needing `(...)`. A script parameter may stand anywhere inside one, since `--param` fills it in before the shape is read. hascard Signature: hascard(compass, card) Summary: True when the hand holds exactly that card, written rank then suit — `TC` is the ten of clubs. Example: hascard(east, TC) && hascard(east, AS) [Honour counts] tens Signature: tens(compass) · tens(compass, suit) Summary: Number of tens held. Example: tens(north) >= 2 jacks Signature: jacks(compass) · jacks(compass, suit) Summary: Number of jacks held. Example: jacks(north) >= 2 queens Signature: queens(compass) · queens(compass, suit) Summary: Number of queens held. Example: queens(north) >= 2 kings Signature: kings(compass) · kings(compass, suit) Summary: Number of kings held. Example: kings(north) >= 2 aces Signature: aces(compass) · aces(compass, suit) Summary: Number of aces held. Example: aces(north) >= 2 top2 Signature: top2(compass) · top2(compass, suit) Summary: Number of the top two honours held: ace, king. Example: top2(north, spades) == 2 top3 Signature: top3(compass) · top3(compass, suit) Summary: Number of the top three honours held: ace, king, queen. Example: top3(north, hearts) >= 2 top4 Signature: top4(compass) · top4(compass, suit) Summary: Number of the top four honours held: ace, king, queen, jack. Example: top4(north, hearts) >= 3 top5 Signature: top5(compass) · top5(compass, suit) Summary: Number of the top five honours held: ace, king, queen, jack, ten. Example: top5(east, spades) >= 3 c13 Signature: c13(compass) · c13(compass, suit) Summary: C13 points: ace 6, king 4, queen 2, jack 1. Example: c13(north) >= 18 ten Signature: ten(compass) · ten(compass, suit) Alias of: tens Summary: Singular spelling of `tens`. Example: ten(north) >= 2 jack Signature: jack(compass) · jack(compass, suit) Alias of: jacks Summary: Singular spelling of `jacks`. Example: jack(north) >= 2 queen Signature: queen(compass) · queen(compass, suit) Alias of: queens Summary: Singular spelling of `queens`. Example: queen(north) >= 2 king Signature: king(compass) · king(compass, suit) Alias of: kings Summary: Singular spelling of `kings`. Example: king(north) >= 2 ace Signature: ace(compass) · ace(compass, suit) Alias of: aces Summary: Singular spelling of `aces`. Example: ace(north) >= 2 pt0 Signature: pt0(compass) · pt0(compass, suit) Alias of: tens Summary: Another spelling of `tens`. Example: pt0(north) >= 2 pt1 Signature: pt1(compass) · pt1(compass, suit) Alias of: jacks Summary: Another spelling of `jacks`. Example: pt1(north) >= 2 pt2 Signature: pt2(compass) · pt2(compass, suit) Alias of: queens Summary: Another spelling of `queens`. Example: pt2(north) >= 2 pt3 Signature: pt3(compass) · pt3(compass, suit) Alias of: kings Summary: Another spelling of `kings`. Example: pt3(north) >= 2 pt4 Signature: pt4(compass) · pt4(compass, suit) Alias of: aces Summary: Another spelling of `aces`. Example: pt4(north) >= 2 pt5 Signature: pt5(compass) · pt5(compass, suit) Alias of: top2 Summary: Another spelling of `top2`. Example: pt5(north, spades) == 2 pt6 Signature: pt6(compass) · pt6(compass, suit) Alias of: top3 Summary: Another spelling of `top3`. Example: pt6(north, spades) >= 2 pt7 Signature: pt7(compass) · pt7(compass, suit) Alias of: top4 Summary: Another spelling of `top4`. Example: pt7(north, spades) >= 3 pt8 Signature: pt8(compass) · pt8(compass, suit) Alias of: top5 Summary: Another spelling of `top5`. Example: pt8(north, spades) >= 3 pt9 Signature: pt9(compass) · pt9(compass, suit) Alias of: c13 Summary: Another spelling of `c13`. Example: pt9(north) >= 18 [Double-dummy and scoring] tricks Signature: tricks(compass, strain) Summary: Tricks that compass takes as declarer in that strain with every hand seen — the double-dummy result. Strain is a suit name, or a number: 0 clubs, 1 diamonds, 2 hearts, 3 spades, 4 notrump. Example: tricks(south, spades) >= 10 Note: Notrump is `notrump`, `notrumps`, or the number 4 — the original's spelling and dealer3's number are the same value. Solving a deal is far slower than any other function here, so a script using `tricks` wants a tight `condition` ahead of it. score Signature: score(vulnerable, contract, tricks) Summary: Declarer's score for a contract played at that vulnerability and making that many tricks. `vulnerable` is the word `nv` or `vul`; `contract` is a word such as `x3N`; `tricks` is 0 to 13. Example: score(nv, x3N, 9) == 400 Note: A contract is one word: a lowercase `x`, the level, and the strain as an uppercase letter of CDHSN. The `x` is a sigil rather than a meaning — it is what lets the word be told from a number — so doubling is written as a suffix: `x4Hx` is four hearts doubled and `x4Hxx` redoubled. `z` may be used in place of the leading `x`, as in DealerV2_4, and means exactly the same thing. Both the case and the level range are the references' own, so a word that runs here runs on BBO. Either argument may also be written as the number it stands for, which is what a `--param` can supply: 0 or 1 for the vulnerability, and level × 5 + strain for the contract, plus 40 for each level of doubling. Strain numbers match `tricks`: 0 clubs, 1 diamonds, 2 hearts, 3 spades, 4 notrump. So `x3N` is 19, `x4S` is 23, `x4Sx` is 63 and `x4Sxx` is 103. imps Signature: imps(scoredifference) Summary: Converts a difference between two scores into IMPs, by the standard table. Example: imps(score(nv, x4S, 10) - score(nv, x3N, 9)) >= 1 par Signature: par(side) Summary: The par score to that side: what the deal is worth with both sides bidding and defending perfectly. `side` is `ns` or `ew`, or a compass for the side that seat is on. Example: par(ns) >= 400 Note: Worked out from all twenty double-dummy results, which cost the same searches `tricks()` does and are remembered per deal — so `par()` beside a `tricks()` condition is close to free. The two sides are opposites: `par(ew)` is `-par(ns)`, and a passed-out deal is zero. Vulnerability is the run's own — `--vulnerable`, or the `vulnerable` statement — and neither side is vulnerable when a script names none. It is deliberately not the rotation `printpbn` applies to an unnamed vulnerability: par is a property of the cards and the vulnerability the run was given, not of where a board sits in a set. DealerV2_4 instead has a `-P` switch of its own for this. rnd Signature: rnd(bound) Summary: A random whole number from zero up to, but not including, the bound. Example: rnd(10) == 3 Note: Every mention draws again, including through a variable: `r = rnd(4)` used twice is two draws, as in the original. Drawn from a stream of its own, seeded from the deal, so the same seed gives the same answers however many threads are running; the original shares the generator it shuffles with, so calling it there changes the deals. `--rnd-seed` shifts the stream. Beware locally built dealer binaries: `rnd` divides by `RAND_MAX`, which describes `rand()` rather than the generator it actually calls, so a build without `STD_RAND` returns values far outside the bound, or negative ones. BBO's own build is correct. dds Signature: dds(compass, strain) Alias of: tricks Summary: DealerV2_4's spelling of `tricks`. Example: dds(south, notrump) >= 9 Note: There it reaches the DDS library where `tricks` reaches GIB's solver; dealer3 solves everything through bridge-solver, so the two are one function with two names. Ten of DealerV2_4's regression scripts use it. trick Signature: trick(compass, strain) Alias of: tricks Summary: Singular spelling of `tricks`. Example: trick(south, spades) >= 10 imp Signature: imp(scoredifference) Alias of: imps Summary: Singular spelling of `imps`. Example: imp(score(nv, x4S, 10) - score(nv, x3N, 9)) >= 1 OPERATORS --------- Grouped by precedence, tightest binding first. [precedence 1] ! (not) Summary: True when its operand is zero, and false otherwise. Example: not hcp(north) >= 12 Note: `!` appears at two strengths. Written in front of a whole comparison it applies to the comparison, so `not hcp(north) >= 12` means `not (hcp(north) >= 12)`. Written inside an arithmetic operand it binds as tightly as a minus sign, so `100 * not x` means `100 * (not x)`. [precedence 2] * Summary: Multiplication. Example: hcp(north) * 2 >= 30 / Summary: Division. Whole numbers throughout, so the remainder is discarded. Example: hcp(north) / 2 >= 6 % Summary: Remainder after division. Example: hcp(north) % 2 == 0 [precedence 3] + Summary: Addition. Example: hcp(north) + hcp(south) >= 25 - Summary: Subtraction, and negation when written in front of a single value. Example: hcp(north) - hcp(south) >= 5 Note: Negation binds as tightly as `!`, tighter than `*`. [precedence 4] < Summary: Less than. Example: hcp(east) < 10 <= Summary: Less than or equal to. Example: losers(north) <= 6 > Summary: Greater than. Example: hcp(north) > 15 >= Summary: Greater than or equal to. Example: hcp(north) >= 15 == Summary: Equal to. Note the two signs: a single `=` assigns a variable instead. Example: spades(north) == 5 Note: Comparisons chain: `a == b == c` is read as `a == b && b == c`, rather than comparing the result of the first comparison against `c`. != Summary: Not equal to. Example: spades(north) != 4 [precedence 5] && (and) Summary: True when both sides are true. The right side is skipped when the left is false. Example: hcp(north) >= 12 && spades(north) >= 5 [precedence 6] || (or) Summary: True when either side is true. The right side is skipped when the left is true. Example: spades(north) >= 5 || hearts(north) >= 5 [precedence 7] ? Summary: First half of the three-way choice `test ? when_true : when_false`. Example: (hcp(north) >= 12 ? spades(north) : hearts(north)) >= 5 : Summary: Second half of the three-way choice `test ? when_true : when_false`. Example: (hcp(north) >= 12 ? spades(north) : hearts(north)) >= 5 [precedence 8] = Summary: Gives a name to an expression. This is a statement, not something that can appear inside a larger expression. Example: fit = spades(north) + spades(south) Note: The name stands for the expression, which is re-evaluated for every deal. ACTIONS ------- printall Summary: All four hands, laid out around the compass. This is what happens with no action given. printew Summary: East and West only, West on the left. Note: The same action as `printside(ew)`. printns Summary: North and South only, South on the left. Note: The counterpart of `printew`, and the same action as `printside(ns)`. South sits left for the reason West does in `printew`: the pair reads as one auction, and the hand that speaks first goes on the left. From DealerV2_4. printside Summary: One partnership's two hands: `printside(ns)` or `printside(ew)`. Note: DealerV2_4's one action for both partnerships. `printside(ns)` and `printns` are the same thing, as are `printside(ew)` and `printew`. printpbn Summary: PBN, the record format other bridge programs read. printcompact Summary: Four lines per deal. printoneline Summary: One line per deal. WORDS ----- Compass north, south, east, west Also n, s, e, w — though a variable of the same name takes precedence. Vulnerability none, ns, ew, all Other keywords any, deal, notrump, notrumps NOT SUPPORTED ------------- evalcontract Instead: The original parses it and then aborts on an assertion, so there is nothing to be compatible with. Use `score` and `tricks`.