About bdeal¶
The bdeal is a program that generates (randomly) card distributions that meets given requirements.
bdeal is developed by Piotr Beling and it is a part of the Bridge Calculator.
- The main futures of the program are:
- it is scriptable in the Lua,
- it uses multiple threads to generates and filters distributions of cards,
- it has built-in, fast double-dummy solver,
- it has console-based, shell-script-friendly user interface.
Quick start examples¶
Print 20 random hands distributions¶
To print 20 random hands distributions just run:
$ bdeal -n 20
See Invocation for details.
The chance to win 3NT¶
Suppose that your partner (S) opened 1NT (classical, 16-18 hcp) and you (N) have ♠K42 ♥QT2 ♦K98 ♣J653.
To check how many trick, in average, S can take in NT and what is a chance to win 3NT, call:
$ bdeal nt_script.lua
Where nt_script.lua
is a name of file with Lua script from which bdeal will read all details. It may have the following content:
conf = {
N="K42.QT2.K98.J653", -- fix N hand
num=100 -- finish after accepting 100 deals
}
-- accept only the deals in which S has 1NT opening:
function filter()
return S:nt(16, 18)
end
-- for each accepted deal, calculate number of tricks in NT by S:
function stats()
local t = tricks(S, "NT")
count("NT by S, number of tricks", t)
count("chance to win 3NT by S", t >= 9)
end
See Lua scripts for details about writing scripts.
No one can make 7 tricks¶
This script accept only deals in which it is impossible to win any contract (after optimal defence):
conf = { num = 1 } -- we want to find only one distribution
function filter()
for i1, s in pairs({ 'c', 'd', 'h', 's', 'nt' }) do
for i2, p in pairs({ 'n', 'e', 'w', 's' }) do
if cantake(7, p, s) then
return false
end
end
end
return true
end
Warning
It may take a long time (even few hours) before it accepts any distribution.
The best lead against 3NT¶
Supposed that N opened 1NT (15-18 hcp) and S bid 3NT (10-12 hcp, without major 4). E is on lead and has ♠K873 ♥J1076 ♦A87 ♣Q7.
This script measures the average numbers of tricks E-W can take and the chances to defeat the contract (3NT), after each lead:
conf = { num=2000, E="K873.J1076.A87.Q7" }
function filter()
return N:nt(15, 18) and S:nt(10, 12) and S:spades() < 4 and S:hearts() < 4
end
function stats()
for c in E:cards() do -- for each card c in the hand E:
local t = tricks(N, "NT", c) -- tricks to take by N-S
count("E-W tricks after " .. tostring(c), 13 - t)
count("chance to defeat after " .. tostring(c), t < 9)
end
end
Invocation¶
bdeal is called like this:
$ bdeal [options] <file names...>
where <file names…> are the (zero or more) names of files with Lua scripts.
The bdeal has several options:
-
-r
,
--noremarks
¶
Don’t print remarks provided by calls of remark function.
-
-s
,
--nostats
¶
Don’t print statistics for individual deals.
-
-f
<none|NESW|short|full|PBN|PBNf>
,
--format
<none|NESW|short|full|PBN|PBNf>
¶ Output format, one of: none (do not print), NESW, short (used by default), full, PBN, PBNf (PBN file/full).
-
-W
<cards>
,
--west
<cards>
¶ Fixed cards in WEST hand.
- <cards> should has a format like in examples:
- “AKQJ.AK65.642.94”
- (AKQJ of spades, AK65 of hearts, 642 of diamonds, 94 of clubs)
- “63.6.9.AQ”
- (only 6 cards are fixed, rest will be chosen randomly)
- “Q7.8543..94”
- (8 cards are fixed, 0 in diamonds)
- “..K.”
- (the king of diamonds + 12 random cards)
-
-S
<cards>
,
--south
<cards>
¶ Fixed cards in SOUTH hand.
-
-E
<cards>
,
--east
<cards>
¶ Fixed cards in EAST hand.
-
-N
<cards>
,
--north
<cards>
¶ Fixed cards in NORTH hand.
-
-n
<number of hands>
,
--num
<number of hands>
¶ Number of hands to deal (10 by default).
-
-j
<number of threads>
,
--jobs
<number of threads>
¶ Number of threads to use (by default equals to number of available CPU cores).
If argument is non-positive, it will be increased by number of available CPU cores (0 to use all cores, -1 to use all cores except one).
-
-h
,
--help
¶
Displays usage information and exits.
-
--
,
--ignore_rest
¶
Ignores the rest of the labeled arguments following this flag.
-
--version
¶
Displays version information and exits.
Lua scripts¶
About¶
Bdeal accepts scripts in Lua language.
- The scripts can include (each element is optional):
If more than one script are given, they are read sequentially (from left to right), and each can overwrite abovementioned elements
(i.e. if two scripts provide filter()
function, the one from script given later will be used).
Configuration¶
Some configuration options can be put in Lua script file, in conf
table or in conf
function that returns a table, for instance:
-- N has king of diamond, W has AQ of spades and 9 of clubs, use 2 threads:
conf = { N="..K.", W="AQ...9", jobs=2 }
The following options (keys in the conf
table) are allowed: N
, E
, S
, W
, format
, num
, jobs
.
See Invocation for description of the options.
Filtering¶
- Script can contain
filter
function which describes deal constraints. The function can accept or refuse deal described by the variablesN
,E
,S
,W
and should return: true
to accept the deal,false
to refuse it,- a number in range [0, 1], which will be interpreted as probability of accepting the deal.
Each of the N
, E
, S
, W
represents the sets of cards held by the respective hands.
Functions and operators described in next sections can be used to examine the properties of the hands.
If all given scripts do not include filter()
function, all distributions are accepted.
- Examples:
accept deals in which E has 12 or more honour points, and more than 2 points in diamonds:
function filter() return E:hcp() >= 12 and E:D():hcp() > 2 end
accept deals in which W opens 1 spade and should have 5 or more spades, and 11 or more honour points (but we know that W sometimes, with 10% probability, opens with 4 strong spades – but only if he has less than 5 hearts):
function filter() if W:hcp() < 11 then -- W does not have 11 points? return false -- refuse end -- here, W has 11 or more points local s = W:spades() -- number of spades if s >= 5 then -- has 5 spades? return true -- accept end if s == 4 and W:S():hcp() >= 6 and W:hearts() < 5 then -- 4 strong spades without 5 hearts? return 0.10 -- accept with 10% probability end return false -- everything else is refused, this line can be omitted (if filter returns no value, the deal will be refused) end
see also Quick start examples
Statistics¶
Script can contain stats
function which is called for each deal accepted by filter
function. The stats
function also has access to N
, E
, S
and W
variables.
Typically, this function calls one or more time count
function, which can collect series of numbers and calculates some statistics (average and others).
- Examples:
checking how many spades and honour points does W have in average:
function stats() count("spades in W's hand", W:spades()) count("honour points in W's hand", W:hcp()) end
see also Quick start examples
Cards set operations (operators)¶
Let s1
and s2
be sets of cards. The following operators are available:
s1 + s2
- Sum of the sets, for example:
E:S() + E:H()
represents E majors. s1 * s2
- Product of the sets, for example:
W * C.new("AS AH")
represents W major aces. s1 - s2
- Difference of the sets, for example:
N - N:S()
represents N cards without spades. -s1
- Complement of the set, for example:
-S
represents all 52-13 cards not included in S’s hand. #s1
Number of cards in
s1
, same ascount(s1)
ors1:count()
.For example:
#N:S()
– a number of spades cards in N’s hand.s1 ^ s2
- xor, the set of cards which are in exactly one set
s1
ors2
. s1 == s2
true
only if setss1
ands2
are equals.s1 ~= s2
true
only if setss1
ands2
are not equals.s1 <= s2
true
only if sets1
is included ins2
.s1 < s2
true
only if sets1
is included in but not equal tos2
.
Functions which operates on sets of cards¶
Note
Each function, excluding new
, can be called as C.function_name(arg1, arg2, ..., argN)
or arg1:function_name(arg2, ..., argN)
.
For example C.hcp(N)
is equal to N:hcp()
.
For sets of cards c
, c1
, c2
, …, a function f
, and a string str
:
-
C.
new
(str)¶ Construct a set of cards described by the string
str
(note that there is upper-caseC
here). Accepts many formats.Example usage (all represent the same set of 10 cards):
C.new("AK87.975..QT9")
,C.new("AK87 975 - QT9")
,C.new("SAK87 H975 CQT9")
,C.new("AK87s 975h QT9c")
-
count
(c)¶ A number of cards in the given cards set
c
, same as#c
.
-
spades
(c)¶
-
Scount
(c)¶ A number of spades cards in set of cards
c
.
-
hearts
(c)¶
-
Hcount
(c)¶ A number of hearts cards in set of cards
c
.
-
diamonds
(c)¶
-
Dcount
(c)¶ A number of diamonds cards in set of cards
c
.
-
clubs
(c)¶
-
Ccount
(c)¶ A number of clubs cards in set of cards
c
.
-
S
(c)¶ Subset of
c
which includes only spades.
-
H
(c)¶ Subset of
c
which includes only hearts.
-
D
(c)¶ Subset of
c
which includes only diamonds.
-
C
(c)¶ Subset of
c
which includes only clubs.
-
get
(c, arg)¶ If
arg
is a string, return the subset ofc
which includes only cards of suit pointed byarg
(which can equal to “S”, “H”, “D” or “C”).If
arg
is a positive integer, returnarg
-th lowest card fromc
. Cards are numbered from0
to#c-1
, clubs have number from0
to#c:C()-1
, diamonds from#c:C()
to#c:C()+#c:D()-1
, and so on. Ifarg
is out of range, an empty set is returned.If
arg
is a negative integer, return#c+arg
lowest (-arg
highest) card fromc
.
-
cards
(c)¶ Iterator over cards included in
c
. Each card is represented as a one-element set of cards.Example:
for x in N:cards() do -- for each card x handled by N: -- do something with card x end
-
hcp
(c)¶
-
miltons
(c)¶ Honour points (4 for Ace, 3 for King, 2 for Queen, 1 for Jack) in the given cards set
c
.
-
controls
(c)¶ Controls (2 for Ace, 1 for King) in the given cards set
c
.
-
points
(c, wAce, wKing, ...)¶ Calculate
wAce
* Aces +wKing
* Kings + …, where Aces, Kings, … are the numbers of aces, kings, … inc
.- Examples:
points(N, 4, 3, 2, 1)
equals tohcp(N)
,points(E, 1, 1, 1, 1)
equals to the number of figures owned by E.
-
balanced
(c)¶ Logic value which is
true
only ifc
is balanced.
-
semiBalanced
(c)¶ Logic value which is
true
only ifc
includes minimum 2 cards in all suits, maximum 5 cards in each major and maximum 6 cards in each minor.
-
union
(c1, c2, ...)¶ Union of the sets, same as
c1 + c2 + ...
-
product
(c1, c2, ...)¶ Product of the sets, same as
c1 * c2 * ...
-
complement
(c)¶ Complement of the set
c
, same as-c
.
-
xor
(c1, c2, ...)¶ Same as
c1 ^ c2 ^ ...
-
shape
(c)¶ Return 4 numbers:
spades(c), hearts(c), diamonds(c), clubs(c)
(in the given order).
-
shape
(c, f) Calculate and return
f(spades(c), hearts(c), diamonds(c), clubs(c))
.For example
shape(S, function(s, h, d, c) return s == 5 and h == 5; end)
givestrue
only ifS
has 5-5 in majors.
-
pattern
(c)¶ Return 4 numbers:
spades(c), hearts(c), diamonds(c), clubs(c)
(in non-increasing order, from highest to lowest).
-
pattern
(c, f) Return
f(c1, c2, c3, c4)
, wherec1, c2, c3, c4 = pattern(c)
.For example
pattern(S, function(a, b, c, d) return a == 5 and b == 5; end)
givestrue
only ifS
has any 5-5.
-
hcp_in_range
(c, from, to)¶ Return
true
ifhcp(c)
is in the range [from
,to
], andfalse
if it is not.
-
nt
(c, from, to)¶ Calculate logic value which is
true
only ifc
is balanced andhcp(c)
is in the range [from
,to
].
Tip
Most of the commands can be called with more than one argument and than they return more than one result (one per argument). In such case command(a, b, ...)
is equal to command(a), command(b), ...
. For example you can write:EpS, EpH = C.hcp(E:S(), E:H())
to obtain number of E honour points in spades and hearts.
Functions useful for doing statistical research¶
-
count
(str, n1, n2, ...) Add to the counter named
str
valuesn1
,n2
, …Each value (
n1
,n2
, …) can be a number, a boolean (1 is added if the value istrue
and 0 when it isfalse
) ornil
(then value is ignored).Example:
count("number of spades in E's hand", E:spades())
-
remark
(arg1, arg2, ...)¶ Attach a remark to the deal considered. The remark consists with concatenation of arguments, which are converted to strings. Remarks are printed next to each deal.
Example:
remark("E can take ", tricks(E, "NT"), " tricks in NT.")
-
note
(arg1, arg2, ...)¶ Similar to
remark(arg1, arg2, ...)
but puts spaces between each pair of arguments.Example:
note("E can take", tricks(E, "NT"), "tricks in NT.")
Functions that use double dummy solver¶
-
tricks
(declarer, game[, cmds])¶ Return the number of tricks that
declarer
can take when a trump suit is given bygame
, and a beginning of play is described bycmds
. If game cannot begin fromcmds
, returnnil
.Parameters: - declarer – one of
N
(or'N'
),E
(or'E'
),S
(or'S'
),W
(or'W'
), lower cases are also allowed - game – shows type of the game, is one of:
'NT'
(no trump),'S'
(spades),'H'
(hearts),'D'
(diamonds),'C'
(clubs), lower cases are also allowed. - cmds – (optional) fixes beginning of the play; if it is not possible,
tricks
returnsnil
Return type: number or
nil
(if the game cannot begin fromcmds
)Example:
tricks(N, "NT", "AD x QD")
It returns number of tricks that can be taken by N in no-trump game, after ace of diamond lead, discarding the smallest diamond by the dummy and queen of diamond by the right hand opponent.
nil
will be returned if: N has no ace of diamond, the dummy has no diamonds at all, or RHO has no queen of diamond.Since
count
ignoresnil
, it is save to write:count("NT by N after AD x QD", tricks(N, "NT", "AD x QD"))
- declarer – one of
-
cantake
(target, declarer, game[, cmds])¶ Check if
declarer
can taketarget
tricks when a trump suit is given bygame
, and a beginning of play is described bycmds
.Parameters: - target – number of tricks to take
- declarer – one of
N
(or'N'
),E
(or'E'
),S
(or'S'
),W
(or'W'
), lower cases are also allowed - game – shows type of the game, is one of:
'NT'
(no trump),'S'
(spades),'H'
(hearts),'D'
(diamonds),'C'
(clubs), lower cases are also allowed. - cmds – (optional) fixes beginning of the play, if it is not possible,
cantake
returnsnil
Return type: boolean or
nil
(if the game cannot begin fromcmds
)Example:
count("chance to win 3NT by N", cantake(9, N, "NT"))