parsecards.txt version 1.1
arfer <arfer.minute@gmail.com>
operation of parsecards.tcl

parsecards.tcl is not a script in its own right, rather it is called/utilised by other
scripts in order to derive/recognise the best 5 card poker hand from a string
representation of between 5 and 9 cards

parsecards.tcl should be loaded before any other script that uses it

any procedure in the namespace nParseCards can be called from within your script.
to pass the string representation of cards to the parsing engine you could typically
use statements akin to the following :-

set x "Ah Td 4c 3s Js 7h"
set y [nParseCards::pParseCards $x]

the above statements pass the string representation of cards held in the variable x to
pParseCards procedure within nParseCards namespace. the return value is stored in the
variable y

the return value has 3 components :-

1. a string representaion of the best 5 card poker hand
2. the plain english poker name for this 5 card poker hand
3. an enumerated ranking system for this 5 card poker hand (more on this later)

the 3 components are returned in a single string seperated by the character '|', so the
above code would yield a return value (stored in variable y) as follows :-

"Ah Js Td 7h 4c|Ace High, Jack Kicker|10 1 4 5 8 11"

the components can be split from the return value typically using statements such as the
following to place each component in a separate string variable :-

set z1 [join [lindex [split $y "\|"] 0]]; # z1 stores the hand itself
set z2 [join [lindex [split $y "\|"] 1]]; # z2 stores the name of the hand
set z3 [join [lindex [split $y "\|"] 2]]; # z3 stores the enumerated ranking of the hand

the demonstration script pokerdemo.tcl will allow you to confirm the above. a string of
cards such as that in x above can be input or the script will, in fact, generate a random
string of cards automatically. the 3 components, split into seperate variables, will be
output to the irc channel. full instructions for using pokerdemo.tcl are contained
within the script itself

parsecards.tcl simply parses the card string through a series of procedures in order of
major poker hand ranking (see http://www.pagat.com/vying/pokerrank.html) until a hand is
recognised. the card string is first passed through one of two procedures that puts the
cards in suit or value order, whichever is appropriate to recognition of a specific hand
type. once a non zero return value occurs, the parsing stops. for example, there is
little point searching for a flush once a straight flush has been detected. it is the
highest ranking hand that matters. the procedures/major ranks are as follows :-

1   Royal Flush
2   Straight Flush
2   Straight Flush Ace Low
3   Four Of A Kind
4   Full House
5   Flush
6   Straight
6   Straight Ace Low
7   Three Of A Kind
8   Two Pair
9   One Pair
10  High Card

note that straight flush and straight flush ace low have the same major ranking. likewise
a straight and a straight ace low. they are separated above simply because they are dealt
with separately in parsecards.tcl

the number to the left of the major poker hand ranking above is the first number in the
enumerated hand ranking. for example, the enumerated hand ranking for a pair of threes
(or any other single pair for that matter) would always start with 9

the remaining five numbers in the enumerated hand ranking represent the five cards in
value order as follows :-

Ace = 1
King = 2
Queen = 3
Jack = 4
Ten = 5
Nine = 6
Eight = 7
Seven = 8
Six = 9
Five = 10
Four = 11
Three = 12
Two = 13

using the above example stored in variable z3, namely 10 1 4 5 8 11 :-

10 = High Card
1 = Ace
4 = Jack
5 = Ten
8 = Seven
11 = Four

so we can sort of reverse deduce from this that the hand was Ace High, Jack Kicker
followed by a ten, seven and four

note that where similar hands in poker exist, they are not usually separated by suit.
for example, it doesn't matter whether a flush is in hearts, clubs, diamonds or spades.
it is the successive card values that are used to determine the best flush from two or
more with the same high card

there is one oddity that perhaps deviates slightly from the norm in respect of enumerated
hand ranking, that is in the case of a straight with ace low or a straight flush with ace
low. for example 5h 4h 3h 2h Ah. in the enumerated ranking, ace would still be
represented by 1 but it would be last in the sequence of numbers rather than immediatelly
following the major hand rank (2 for a straight flush)

5h 4h 3h 2h Ah equates to 2 10 11 12 13 1

the enumerated ranking could be used to simplify the process of finding a winner from two
or more similar hands in a multiuser game simply by examining each number in turn to find
which player's hand has the lowest. for example :-

Player 1 has Ah Qc Td 5d 3s (Ace High, Queen Kicker) which equates to 10 1 3 5 10 12
Player 2 has Ad Qs Tc 6h 2c (Ace High, Queen Kicker) which equates to 10 1 3 5 9 13

examining the numbers one by one we see that the 5th number in the sequences is lower
(representing a higher card) for player 2, hence he is the winner. we need not take any
interest in subsequent number(s). if all the numbers were equal, then the hands would be
tied

although the intent was to provide a mechanism for simplifying hand comparison in a
multiuser game environment, it turns out that basic tcl does not have a min or max
function within the scope of expr, which would clearly have been of use. these functions
exist in the extended tclx but this is not included in the version used in
eggdrop/windrop bots (at least not at present as far as I know)

there remains one minor problem area with parsecards.tcl that restricts it's use to the
parsing of not more than 9 cards. I count it as minor because it's difficult to envision
a poker game where more than 9 cards are needed, yet I guess it remains a bit of an
annoyance. the problem concerns recognition of the best flush. consider the following
ten cards :-

5c 6h Qc Jc Qh Th 8h 2c 3c 7h

there are two queen flushes Qh Th 8h 7h 6h and Qc Jc 5c 3c 2c. the winning flush is
discerned by looking at the minor cards in value order. since Jc beats Th then the queen
flush in clubs is the highest (winning) hand. however, parsecards.tcl would return the
queen flush in hearts

the flush procedure in parsecards.tcl functions by looking for an ace flush in hearts
then an ace flush in clubs then an ace flush in diamonds then an ace flush in spades,
stopping once an ace flush is found. if an ace flush is not found, then it continues in
the same way looking for a king flush then a queen flush etc etc. it would therefore find
the queen flush in hearts and stop, without ever looking for a queen flush in clubs

this procedure would need to be changed such that it firstly collected ALL the ace
flushes should one or more exist. if one exists it is returned, if more than one exists
then the best one is found and that returned, whilst if none exist then it moves on to
kings, then queens etc in the same manner. this difficulty does not effect any other hand
type. if the procedure was changed in the manner described then parsecards.tcl could be
used for any number of input cards, all the pack if you wish (though I can't think why,
since this would always return a royal flush in hearts - because again it looks for
hearts first and the suit makes no difference to the hand value). it goes without saying
that there can't be more than one flush (in different suits) in 9 cards or less.

this is the point where i discovered the lack of support in the scope of expr for min and
max functions, so i thought i'd publish it 'as is' and leave the tricky flush issue to
somebody rather more expert than me. if the reader feels up to the task, run a few card
strings similar to the ten cards above through pokerdemo.tcl, just to confirm it works

most irc users neither know nor care about the workings of tcl. they just want
functioning scripts. for this reason i have included in pokerstuff1.0.zip a full game
script that emulates a poker slot machine using parsecards.tcl. full instructions can be
found within the script itself.

have fun!
