Back to Deal Top Page.
Plane Dealing image

Deal 2.0

Reference Guide

Covering:
  • Command line arguments
  • Additive Functions
  • Shape Functions and Classes
  • String Boxes and formatting
  • Often used Tcl features
  • Library routines

Command Line Options

-e expr
Evaluate the Tcl expression expr. Not very useful, but occasionally good for setting variables which affect the user's script, like:
deal -i userscript -e "set maxnorth 10"
-v
Verbose mode. Lets you know how many hands have been accepted and how many hands have been tried.
-[NSEW] hand-spec
Specifies the cards held by the specified hand. The hand-spec should be of the form: "AK8532 - KQ72 A65". Voids must be represented with a '-' character. hand-spec should be one argument, so the string should be quoted on the command line.
-i file
Source the commands in the file named. The language used is "Tcl". Read the man page for Tcl for help in writing Tcl code. Additions to Tcl specific to deal are listed in this manual.
-f
Instead of dealing new hands, reads hands from standard input. The hands must be in the format put out by "deal -l". You might deal, say, 10,000 hands which satisfy specific criteria, saving them to a file. Then you can use that output for input with deal -f to find out which hands satisfy other constraints.
-t
Print distribution table and exit. The distribution table is an ordered list of all possible hand patterns for a single hand.
-l
Write deals in a "single-line" format. In previous releases this was the default format. It is useful for piping to formatters written in other languages. Most formatting can be defined internally, using Tcl now. Still useful with the "-f" option.

Simple Usage

The most basic usage of the program is to generate random deals with no conditions:
% deal 2
	  S : QJ9
	  H : AJ
	  D : T52
	  C : AKQ84
 S : 752            S : AK83         
 H : T85            H : Q632         
 D : AK8763         D : J4           
 C : 2              C : T96          
	  S: T64
	  H: K974
	  D: Q9
	  C: J753
---------------------------
	  S : QJ9
	  H : 52
	  D : AKJT9
	  C : A86
 S : 763            S : A52          
 H : T763           H : J98          
 D : Q54            D : 876          
 C : T95            C : KQJ7         
	  S: KT84
	  H: AKQ4
	  D: 32
	  C: 432
---------------------------
If you want a raw format, more readable by external programs, use the -l flag, which prints deals in a single-line format:
% deal -l 5
K75 T987 AQT5 95|AQ86 2 943 QJ643|JT32 J43 KJ KT82|94 AKQ65 8762 A7
QJ96 KQ6 T95 K76|T5 J953 A72 AJT9|8432 A7 83 Q8432|AK7 T842 KQJ64 5
K52 QJT9 AKQ K63|AJ AK7542 T732 8|94 3 J965 QJT972|QT8763 86 84 A54
A76 A764 43 KJT2|J9 KJ53 K986 A87|K8543 T82 72 953|QT2 Q9 AQJT5 Q64
Q6 QJ75 3 AJ7642|AT9874 KT963 AT |K32 4 QJ2 KQ9853|J5 A82 K987654 T
This output form is crude; it is meant to be post-processed. Each line is of the form:
"North|East|South|West"
Each hand is specified by:
"Spades Hearts Diamonds Clubs"
where the space character separates each suit. In the examples above, the east hand in the last deal is:
"AT9874 KT963 AT "
which might be written more verbosely as:
S: AT9874   H: KT963   D: AT   C: ---
I've included three formatters with the package, one of which creates a TeX file for the hands generated, the other two simple text files. The formatters are Perl scripts, so if you don't have Perl on your system they won't work. To format, you just run deal with the -l flag, and pipe to the formatter:
% deal -l 5 | perl ./compactdeal
Deal # 1          - AKQT43 AKT65 A3
JT65 82 QJ32 752                    AKQ82 6 94 KJ984
                  9743 J975 87 QT6
------------------------
Deal # 2          3 QJT43 A8742 K4
QT4 86 T93 AJ973                    AK52 2 QJ65 T862
                  J9876 AK975 K Q5
------------------------
Deal # 3          A76 KT9 QJ84 K53
T952 A832 A95 Q8                    J Q76 KT632 J762
                  KQ843 J54 7 AT94
------------------------
Deal # 4          AQ752 J632 - 8652
6 AK74 A863 AKT9                    KJ98 Q95 J752 QJ
                  T43 T8 KQT94 743
------------------------
Deal # 5          A4 AJ72 852 AKQT
63 T9654 QT9 865                    QJ852 Q J764 J94
                  KT97 K83 AK3 732
------------------------
% deal -l 2 | perl ./formatdeal
Deal 1         S : 75                     |
               H : Q4                     |
               D : QJ962                  |
               C : AT64                   |
     S : KQ63           S : J98           |
     H : K732           H : T985          |
     D : K75            D : A843          |
     C : 83             C : J2            |
               S : AT42                   |
               H : AJ6                    |
               D : T                      |
               C : KQ975                  |
-------------------------------------------
Deal 2         S : AKQJ                   |
               H : J43                    |
               D : KQ4                    |
               C : 762                    |
     S : 73             S : 9865          |
     H : QT76           H : AK82          |
     D : J972           D : T86           |
     C : JT4            C : A9            |
               S : T42                    |
               H : 95                     |
               D : A53                    |
               C : KQ853                  |
-------------------------------------------

Putting Conditions on the Deal

There are two distinct types of conditions which can be placed on a hand.

One is the rigid placement of cards, as in, `South gets the ace of clubs,' or `East is "AK52 AK32 9652 6"'. Card placements are done before any randomnizations.

Card placements are ignored when using deal with the -f option. This is because `deal' is reading already built hands.

The other conditionals are evaluated conditionals, like "South has at least 4 hearts" or "West has 11 to 15 HCP" or "North has exactly one of the ace and king of clubs."

The flow of control is:

  1. Place known cards
  2. Deal rest of the cards at random
  3. Determine whether to accept or reject deal. If rejected, go to 2.
This is less than optimal in many ways. The optimizing problem here is pretty painful, though, and, although I have some ideas for solutions, I'm trying to be careful to do it right; in the meantime, this method will have to do.

Scripts use the Tcl language, with bridge-related additions. To understand these scripts, you should read the Tcl man page.

An example script (ex/1.tcl from the kit):

##############################################
# Look for deals where north has 44 in the majors, a short minor,
# and 11-15 HCP.
# To execute:
#       deal -i ex/1.tcl [num]
##############################################
main {
                                          # Pitch deals
                                          # where north does
                                          # not have four spades
        reject if {[spades north]!=4}

                                          # Pitch deals
                                          # where north does
                                          # not have four hearts
        reject if {[hearts north]!=4}

                                          # Pitch deals
                                          # where north has
                                          # 2 or 3 diamonds
        set d [diamonds north]
        reject if {$d==2} {$d==3}

                                          # Accept deals
                                          # where north has
                                          # 11-15 HCP.
        set hcp_n [north]
        accept if {$hcp_n>=11 && $hcp_n<=15}
}
##############################################
The "main" command defines the expression which is to be evaluated to ascertain whether a deal is accepted or rejected. This occurs after all cards have been dealt. If the hand is never explicitly accepted, the hand is rejected.

We can run this example as:

        % deal -i ex/1.tcl 10
This will produce ten deals where north has a mini-Roman hand with a short minor.

"deal" takes a "-v" flag which lets the user know about progress in the hand generation; how many hands have been searched, and how many have been checked.

% deal -l -v -i ex/1.tcl 5
KJ92 AQ42 7 K842|8 KT9763 A862 95|Q73 J JT94 QJ763|AT654 85 KQ53 AT
Deal 1 found after 61 tries
AJ62 AQ84 9 J764|K84 J2 875 KT932|QT T73 AJ643 Q85|9753 K965 KQT2 A
Deal 2 found after 269 tries
JT86 AQJ8  KQ543|9 T9432 542 A976|K7532 K6 KQJ7 T2|AQ4 75 AT9863 J8
Deal 3 found after 303 tries
A652 AT94 A985 2|3 QJ532 T63 J543|QT74 8 K7 KT9876|KJ98 K76 QJ42 AQ
Deal 4 found after 394 tries
AJ65 9743 K AJT8|T742 T6 T764 972|KQ83 AQ5 Q32 643|9 KJ82 AJ985 KQ5
Deal 5 found after 523 tries
The progress output is sent to "stderr", so you can still pipe the hands to a formatter or file without trouble.

You can specify on the command line that you want South to hold a specific hand:

        % deal -v -i ex/1.tcl -S 'AK52 42 K52 7642' 10
Here are some of the procedures built in to the program which have been added to Tcl for Deal.
accept
Accept the current deal. Use only from "main".
accept if expr [expr...]
Accept the current deal if one of the expressions is true. Use only from "main". Stops evaluating exprs when it finds a true one.
accept unless expr [expr...]
Accept the current deal unless one of the expressions is true. Use only from "main". Stops evaluating exprs when it finds a true one.

reject
Reject the current deal. Use only from "main".
reject if expr [expr...]
Reject the current deal if one of the expressions is true. Use only from "main". Stops evaluating exprs when it finds a true one.
reject unless expr [expr...]
Reject the current deal unless one of the expressions is true. Use only from "main". Stops evaluating exprs when it finds a true one.

spades hand, hearts hand, diamonds hand, clubs hand
Returns the number of cards held in the suit by hand hand

controls hand [suit]
Return the number of controls (A=2, K=1) held in the suit given. If no suit given, the total number of controls.

hand is hand-spec
This places all the cards of one hand. The hand spec looks like:
"AKQ - T642 QT9876"
The format is pretty inflexible. Example:
east is "AKQ AKQ AKQ AKQT"
This is the same as saying:
-E 'AKQ AKQ AKQ AKQT'
on the command line.

hand gets card [card...]
Places individual cards in to the hand. Example:
north gets AC
places the ace of clubs in the north hand.

hand has card [card...]
Checks to see if the hand holds the specified cards, e.g.
if {[north has AC]} {...}

hand shape
Returns a string of the 4 suit lengths, in the order S,H,D,C, e.g.
puts stderr [south shape]
4 3 2 4

hand pattern
Return a string of the 4 suit lengths, sorted in descending order:
puts stderr [south pattern]
4 4 3 2

hand
Return the HCP total for the hand, e.g.
reject if {[north]>=16}
[Design note: this treatment might go away. I have serious problems with making high card points so prominent, and [south] might be better used as a method of extracting a tcl list like: {AK} {QJ65} {T9872} {53} . If I were to do this, I would add a function, hcp. Of course, you can implement the hcp function yourself with defvector. ]
defvector name val [val ...]
A vector is a fast counting procedure. The "vector" for counting HCP is (4,3,2,1,0,0,0,0,0,0,0,0,0). We can define
defvector Hcp 4 3 2 1
and then use "Hcp" as a procedure later:
reject if {[Hcp north]>=16}
Or
defvector Top3 1 1 1
creates a procedure for counting how many aces, kings, and queens are held.

One nice thing about these routines is that they are fast. Clever use of vectors speeds up all sorts of evaluation routines.

vector suit [suit ...]
Counts the hand using the vector. If a list of suits is given, only those suits are counted. Otherwise, all suits are counted. E.g.,
defvector AKQ 3 2 1
AKQ south hearts spades
counts the Ace-King-Queen points held by the south hand in hearts and spades.

shapeclass name { code }
This, like defvector, is an optimization issue. E.g.,
shapeclass michaels {return [expr $h>=5 && $s>=5]}
main { accept if {[michaels north]}}
A shapeclass generates a lookup table the first time it is called, and fast shape matching occurs each time after.

shapecond name { expression }
This is just a shorthand for:
shapeclass name {return [expr expression] }
definedclass hand
Returns true if the hand is in the shape class and false otherwise.

definedclass compile
Returns a string of 0's, 1's and whitespaces for faster shapeclass reuse. Really for my personal use, but included here for completeness.

shapeclass.binary name { bits }
This is how to define the "compiled" form of the shapeclass definitions, only really useful for shape classes which are reused often.

balanced hand
Returns true if the hand is "balanced" in the classical Goren-style: 4333s, 4432s, and 5332s with 5-card minor. This could be implemented as a shapeclass, but there still remains an internal definition which is pretty fast.

losers hand [suit ...]
Returns the number of losing tricks for the hand, or, if suits are given, the number of losing tricks in those suits.

You can, of course, create new routines with Tcl, and then call them from the "main" procedure.

There are many examples in the kit; look them over. There is also a file called "library" which defines some useful procedures.

Hints

Clever use of count vectors can solve many problems efficiently. For example, if you and your partner play that a weak two promises 2 of the top 3 or 3 of the top 5, you could define:
defvector Weak2Quality 2 2 2 1 1
This vector evaluates to 4 or greater whenever the suit has the right quality, so we could check for a weak-two spade suit with:
reject if {[spades north]!=6} {[Weak2Quality north spades]<4}
The program doesn't do much optimization, but you can do some yourself. Try not to use logical conjunctions in "require" and "accept" parameters. It is better to say:
accept unless {[north]<13} {[hearts north]<7}
than to say:
accept if {[north]>=13 && [hearts north]>=7}
That's because the {[hearts north]<7} expressions doesn't get evaluated if {[north]<13} evaluated as true.

It is even better to do:

accept unless {[hearts north]<7} {[north]<13}
Why? Because you are eliminating more hands initially. (Also, the suit-length functions are faster than most since the numbers are incidentally calculated at deal-time.)

Automated optimization is another area which I'm considering for later versions of this program.

Who to Blame

Questions, comments and great thoughts are welcome. Just send me email at the address at the bottom of this page.
Silhouette Thomas Andrews (deal@thomasoandrews.com) Copyright 1996-2005. Deal is covered by the GNU General Public License.