regexs for poker

J

J. J. Cale

Hi all
I'm using a strict doctype and testing in IE6 and Mozilla
I understand the basics of regexs but not the subtleties
(is that spelled right?).
I'm trying to evaluate poker hands that are saved as an object
with an array of cards. I checked John Stockton's archives
and searched google but did'nt find anything I could or would
convert or use. If someone knows where to find the routines
I need a pointer would be fine thank you. For the regex
heavyweights in this group, how would I use them to test
my card array for pairs, two pairs, three etc.

<script type="text/javascript">
function Hand(name) {
this.name = name;
this.cards = new Array();
this.suits = new Array();
this.handValue = 0;
}
var handsArr = new Array();
handsArr[0] = new Hand('dealer');
handsArr[1] = new Hand('player');
</script>
The game is stud poker and initially two cards are
dealt to 'dealer' and 'player' from a shuffled deck
of 52 cards. The cards are displayed and at this
point the above arrays are populated. The obj.cards
array holds numbers from 1 - 13
after the deck[ind] returns a number from 1 - 52
I filter it for suit and convert the number (num % 13).
I haven't decided how to populate the suit array.
Probably numbers 0 1 2 3 or 1 2 3 4
If strings would be less complicated I can do that.
At this point I intend to create strings from the arrays
and test.

if(/^exp$/.test(myCardString)) return 'pair','straight' etc;

straight == true && /^exp$/.test(mySuitString)? return 'stflush':
return 'straight';
and so on.

Any help would be appreciated. TIA
Jimbo
 
M

Mick White

J. J. Cale said:
Hi all
I'm using a strict doctype and testing in IE6 and Mozilla
I understand the basics of regexs but not the subtleties.
I'm trying to evaluate p For the regex
heavyweights in this group, how would I use them to test
my card array for pairs, two pairs, three etc. [...]

if(/^exp$/.test(myCardString)) return 'pair','straight' etc;

straight == true && /^exp$/.test(mySuitString)? return 'stflush':
return 'straight';
and so on.
I have done some work in this area:
http://www.mickweb.com/javascript/arrays/userDefinedSortingArrays4.html
As far as regex, you must first decide in which form the card is
represented. In my case it;s hA, h2, h3 ... (Ace of hearts, deuce, trey...)
Mick
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Sat, 1 Jan 2005
09:58:27, seen in J. J. Cale
For the regex
heavyweights in this group, how would I use them to test
my card array for pairs, two pairs, three etc.

<script type="text/javascript">
function Hand(name) {
this.name = name;
this.cards = new Array();
this.suits = new Array();
this.handValue = 0;
}
var handsArr = new Array();
handsArr[0] = new Hand('dealer');
handsArr[1] = new Hand('player');
</script>

I'd not use RegExps for testing.

You need to think very carefully about how to store the information
about the cards. Consider the general case of a one-deck game.

You have four suits of 13 cards, plus two jokers. Each card may be
absent, or in one of several sites, in some visibility state; and the
order of the cards on a site may matter.

So you could have a deck object holding all the card objects, each
knowing its state. That way, you should never be able to lose a card
(no up-the-sleeve state).

Or you could have an object for each site, holding card objects and
their order and state.

Or you could store the information as strings, each holding some of
CA C2..CK, DA D2..DK, HA H2..HK, SA S2..SK, J, j.

ISTM that it would be difficult to scan such strings in all the
necessary fashions with RegExps, and considerably easier to scan each
hand with the cards stored in an Object or an array.

Because the cards of a suit can be ordered, an Array may be better than
a mere Object; but there's little difference between them.
 
J

J. J. Cale

Mick thanks. I have my own routines for dealing,shuffling etc.
Dr Stockton I was hoping I'd get your attention. Thanks for
the advice although I don't think it is that complicated.
Even if there are 7 hands this would be straight forward. The
hand value won't change whether the card face or back is
displayed. The key to making this easy for regex seems to be
1. sorting the cards array. 2. reducing numbers 10,11,12,13
to one digit. (T J Q K) (I chose hex);
AFAICS checking for a straight is best done in
the original array as dealt from the deck and converted.(see OP).
Flushes and straight flushes are simple since I have
separated the card value from the suit in two separate arrays
in the Hand object (OP). As I said I convert the cards array
and suits array from the object to strings for regex testing.
Ok. Here's what I have so far.
I have hard wired the arrays for this example.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Regex test</TITLE></HEAD>
<BODY>
<script type="text/javascript">
// someone have a better sort function?
function mySort(arrayName) {
var length = arrayName.length;
for (var i=0; i<(length-1); i++)
for (var j=i+1; j<length; j++)
if (arrayName[j] < arrayName) {
var dummy = arrayName;
arrayName = arrayName[j];
arrayName[j] = dummy;
}
}
function getHex(num) { // could be T J Q K
switch(num) {
case 10: return "A";
case 11: return "B";
case 12: return "C";
case 13: return "D";
default: return num;
}
}
// hard wired straight
var cards= new Array(10,8,11,9,7);
// after sort should = 7,8,9,10,11
var flag = false;
mySort(cards);
// test for straight
for (var i = 0; i < cards.length - 1; i++) {
if(cards + 1 != cards[i+1]) {
flag = false;
break;
}
flag = true;
}
if (flag) alert('straight is true');
// ace high will need to be checked separately :>)

// test for pair
cards= [12,3,8,10,3];
// after sort should be 3,3,8,10,12
mySort(cards);
var myStr = '';
// first reduce numbers 10 -13
for (i = 0; i < cards.length; i++)
myStr += getHex(cards) + '';
var feed = new Array(1,2,3,4,5,6,7,8,9,"A","B","C","D");
for (i = 0; i < feed.length; i++) {
// I test for a pair but obviously one would
// test for four, then three then pair
var rx = new RegExp(feed + "{2,2}");
alert(rx.test(myStr) + '\n' + feed);
}
</script></BODY></HTML>
 
M

Mick White

J. J. Cale said:
Mick thanks. I have my own routines for dealing,shuffling etc.
Dr Stockton I was hoping I'd get your attention. Thanks for
the advice although I don't think it is that complicated.
Even if there are 7 hands this would be straight forward. The
hand value won't change whether the card face or back is
displayed. The key to making this easy for regex seems to be
1. sorting the cards array. 2. reducing numbers 10,11,12,13
to one digit. (T J Q K) (I chose hex);

As far as sorting card rank:

Array.prototype.getIndex=function(val){
for(i=0;i<this.length;i++){
if(this==val) return i;
}
return -1;
}

S=["&hearts;","&diams;","&clubs;","&spades;"];
N=[2,3,4,5,6,7,8,9,10,"J","Q","K","A"];

var aceRank=N.getIndex("A") // ==12

As Dr. Stockton suggests, it may be easier or more efficient to convert
the hand to an array and then sort the hand.

var hand_1=["hA,"s8","h3","d8","cA"] // dead man's hand

Here is where you can determine flush, straight, 4's, 3's, 2 pair or
pair, but you still need a mechanism to calculate the relative strength
of this hand versus other hands:

var hand_2=["hA,"s7","h3","d7","cA"] is clearly inferior to hand_1,
you'll need to create a "compare two pairs" function.

if(is2pair(hand1,hand2,...){compare2p(hand1, hand2,...)}
// could return an array: ["best hand","...","worst hand"]

And don't forget "bespoke" sort functions, which allow you to sort an
array in any order you choose.

Good luck.
Mick
 
R

RobG

J. J. Cale said:
Hi all
I'm using a strict doctype and testing in IE6 and Mozilla
I understand the basics of regexs but not the subtleties
(is that spelled right?).
I'm trying to evaluate poker hands that are saved as an object
with an array of cards. I checked John Stockton's archives
and searched google but did'nt find anything I could or would
convert or use. If someone knows where to find the routines
I need a pointer would be fine thank you. For the regex
heavyweights in this group, how would I use them to test
my card array for pairs, two pairs, three etc.

<script type="text/javascript">
function Hand(name) {
this.name = name;
this.cards = new Array();
this.suits = new Array();
this.handValue = 0;
}
var handsArr = new Array();
handsArr[0] = new Hand('dealer');
handsArr[1] = new Hand('player');
</script>
The game is stud poker and initially two cards are
dealt to 'dealer' and 'player' from a shuffled deck
of 52 cards. The cards are displayed and at this
point the above arrays are populated. The obj.cards
array holds numbers from 1 - 13
after the deck[ind] returns a number from 1 - 52
I filter it for suit and convert the number (num % 13).
I haven't decided how to populate the suit array.
Probably numbers 0 1 2 3 or 1 2 3 4
If strings would be less complicated I can do that.
At this point I intend to create strings from the arrays
and test.

if(/^exp$/.test(myCardString)) return 'pair','straight' etc;

straight == true && /^exp$/.test(mySuitString)? return 'stflush':
return 'straight';
and so on.

Any help would be appreciated. TIA
Jimbo

Simple scoring algorithm for a one-deck game of 5 card stud.

Each hand can be represented by an array of two-digit values, one
for each hand score and one for each card. The hand-score end of
the array is the left side, the card-score is on the right,
ranking highest to lowest, left to right.

Start with an array of 22 '00' strings (I'll call the 'slots'),
the left 8 for the hand scores and the right 13 for card values
(straight flush and royal flush are combined, see below).

Suit[1] is valuable for one thing only: determining if you have a
flush. So look to see if the hand is a flush, if it is, give it
a "flush" score of the highest card value then ditch the suits.
Now you are dealing with just numbers.

Go thru the hand card by card. First check the value in
the three-of-a-kind (toak) slot. If it matches, you have four of
a kind so put the card value in the four-of-a-kind slot, zero the
toak slot, get next card.

Do the same with the pair slot, except you need two pair slots
incase of two pair. The card value of the higher value pair goes
in the left slot, the other in the right slot.

If the card doesn't match either toak or pair, put the card value
into its card value slot. If there is a value already there, zero
the value and put the card value into a pair slot, checking for
and applying the two pair rule.

Now check for a straight: if there is a pair, toak or foak, then
you can't have a straight. If pass the above test, get the card
values and sort them. If the highest minus lowest is 4, you
have a straight (keep in mind whether aces are usually high).
Put the highest card value into the straight slot. A straight
flush is already allowed for 'cos you set the flush bit up font
so a straight flush will always beat a straight. The kickers are
allowed for by their value in the card value part of the array.

Lastly, look for a full house in the toak and pair slots. If
there is one, put the card value of the toak into the full house
slot.

Now just concatenate the array and turn it into an integer.

Royal flushes are allowed for 'cos they are just an ace-high
straight flush (and a straight flush beats all)

If both hands are the same, it's a tie. You may split a tie by
"looker looses" or some other rule that is independent of the
actual card values.

[1] Suit should not be used to split a tie: poker is a game of
chance and each suit has the same chance of appearing in a hand.

When I have time I'll play with the algorithm a bit more and post
some code.
 
R

RobG

RobG wrote:
[...]
When I have time I'll play with the algorithm a bit more and post
some code.

So here's an implementation. It is generously commented and
could be optimised to use the ordering of the cards better, but I
chose not to depend on it.

The only useful bit is the card scoring algorithm, the rest is
just a test harness to generate hands to score and present the
results. I've used double-digit numbers simply for convenience,
they could be reduced to single digit hex values amongst other
optimisations, but why bother - it scores three hands in less
than 10 milliseconds on my old PIII laptop.

The bit that generates the result does not look for a tie but it
should. It should handle any number of hands, decks or cards in
the hand (five or seven card) but the score values may differ
depending on the rules you are playing.

Have fun with it...

<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>Score poker hands</title>
<meta http-equiv="Content-Type"
content="text/html; charset=windows-1252">
<script type="text/javascript">

/* Gets the hands, creates a result array,
calls the hand scoring function,
puts the hand scores into the results array
returns the scored hands with the winner

Score array elements:

0 Straight flush 00 or 01
1 Four of a kind 00 or card value of foursome
2 Full house 00 or card value of triple
3 flush 00 or 01
4 straight 00 or 01
5 trip (three of a kind 00 or card value of triple
6 two pair (high pair) 00 or card value of high pair
7 pair 00 or card value of (low) pair
8 ace 00 or 14
8 king 00 or 13
8 queen 00 or 12
8 jack 00 or 11
8 ten 00 or 10
8 nine 00 or 09
8 eight 00 or 08
8 seven 00 or 07
8 six 00 or 06
8 five 00 or 05
8 four 00 or 04
8 three 00 or 03
8 two 00 or 12

scores for Chicago poker (not implemented)

one pair 1
two pairs 2
trips (three of a kind) 3
straight 4
flush 5
full house 6
four of a kind 7
straight flush 8
royal straight flush 52
*/
function whoWins() {
var lenArg = arguments.length,
results = [],
msg='';

for (i=0; i<lenArg; i++) {
// Load each hand into an array
var hand = arguments.split(',');

/* Just for debug
msg += 'Hand ' + i + ' '
+ scoreHand(hand) + '\n';
*/
results = scoreHand(hand) + '-' + i;
}

results.sort();
// look for a tie here, I haven't
var winner = results[lenArg-1].split('-')[1];
return results.join('\n')
+ '\n\nHand ' + winner + ' wins.';
}

// Expects hand to be an array of values:
// <Card value>-<suit flag>
// e.g. 03-d is the three of diamonds
// 14-h is the ace of hearts
function scoreHand(hand){
var score = [],
suit = [],
flush = true,
handL = hand.length
slot = '';

// Populate score array - has 21 values
// 8 for hand scores and 13 for card scores
// This makes sure all values are two digits
for (j=0; j<21; j++){
score.push('00')
}

// Test for flush first and
// strip off suit from hand at the same time
for (var i=0; i<handL; i++) {
suit.push(hand.split('-')[1]);

// Remove suit from hand as no longer needed
hand = hand.split('-')[0];

// If suit matches previous card, put 01 into flush slot
if (i>0 && suit[i-1] == suit && flush) {
score[3] = '01';

// Otherwise, set flush slot to 00
} else if (i>0) {
score[3] = '00';
flush = false;
}
}

// Sort the hand - lowest values are on left
hand.sort();

// Now to card scores
for (var k=0; k<handL; k++) {
// Subtract card value from array length + 1
// gives slot number
slot = +score.length + 1 - hand[k];

// Test three of a kind slot
// If matches, have four of a kind
if (score[5] == hand[k]) {
score[1] = hand[k];
score[5] = '00';

// Test high pair slot
// If matches, have full house but set score later
} else if (score[6] == hand[k]) {
score[5] = hand[k];
score[6] = '00';
score[2] = '01';

// Test low pair slot
// If matches, have three of a kind
} else if (score[7] == hand[k]) {
score[5] = hand[k];
score[7] = '00';

// Test card value slot
// If has value, have a pair
} else if (score[slot] != '00') {

if (score[7] != '00' && score[7] < hand[k]) {
score[6] = hand[k];
} else {
score[6] = score[7];
score[7] = hand[k];
}
// Zero card value slot if pair was found
score[slot] = '00';

// If fell through all test, then just put the
// card value in the appropriate slot
} else {
score[slot] = hand[k];
}
}

// Test for full house
if (score[5] != '00' && score[7] != '00') {
score[2] = '01';
}

// Test for straight
if (score[5] == '00' && score[7] == '00') {
hand.sort();
var handMin = hand[0];
var handMax = hand[handL-1];
var dif = hand[handL-1] - hand[0];

// If found a straight
if (dif == '4') {

// Score straight flush if found
if (score[03] !=0) {
score[0] = '01';
score[3] = '00';
} else {

// Otherwise, just score the straight
score[4] = '01';
}
}
}
/* Just for debug
return hand.join(' : ')
+ '\nSuits: ' + suit.join()
+ '\nScore: ' + score.join(' ')
+ '\n';
*/
return score.join('');
}

</script>
</head>
<body>
<form action="">
<label for="hand1">hand 0:
<input type="text" name="hand0" size="50"
value="14-h,02-d,09-c,06-s,14-d">
</label><br>
<label for="hand2">hand 1:
<input type="text" name="hand1" size="50"
value="10-h,10-d,09-s,06-c,02-s">
</label><br>
<label for="hand3">hand 2:
<input type="text" name="hand2" size="50"
value="12-h,11-d,04-s,03-c,02-c">
</label><br>
<input type="button" value="Score hands" onclick="
alert(
whoWins(
this.form.hand0.value,
this.form.hand1.value,
this.form.hand2.value)
);
"><br>
<input type="reset">
</form>
</html>
</body>
 
R

RobG

RobG said:
RobG wrote: [...]
// Test for full house
if (score[5] != '00' && score[7] != '00') {
score[2] = '01';
}

Ooops, this doesn't work if the triple was the high pair, so
change it to:

if (score[5] != '00' &&
(score[7] != '00' || score[6] != '00')) {
score[2] = '01';
}
 
J

J. J. Cale

----- Original Message -----
From: "Mick White" <[email protected]>
Newsgroups: comp.lang.javascript
Sent: Sunday, January 02, 2005 7:18 PM
Subject: Re: regexs for poker


As far as sorting card rank:

Array.prototype.getIndex=function(val){
for(i=0;i<this.length;i++){
if(this==val) return i;
}
return -1;
}

S=["&hearts;","&diams;","&clubs;","&spades;"];
N=[2,3,4,5,6,7,8,9,10,"J","Q","K","A"];

var aceRank=N.getIndex("A") // ==12


Hi Mick thanks for staying with me.
I'm using something similar but might change to above.
At this point I'm evaluating the 5 card hand, kind of
working backwards.
function Hand(name) {
this.name = name;
this.cards = new Array();
this.suits = new Array();
this.handValue = 0;
}
var handsArr = new Array();
handsArr[0] = new Hand('dealer');
handsArr[1] = new Hand('player');

var feed = new Array(1,2,3,4,5,6,7,8,9,"A","B","C","D");
Assume 5 cards have been dealt. The cards array holds numbers from 1 - 13
so it's easier to check for straight and flush and IMO saves
time and work since the pairs etc. can't exist with them.
Then I convert the cards array to a string for regex texting.
The routine below is primitive but does what your (elegant)
function does, mainly identifies the index of the match.
Two hands have been dealt and the calls are simple

getHandValue(handsArr[0].cards);
getHandValue(handsArr[1].cards);

function getHandValue(obj) {
// check for straigth and/or flush then convert to str
var str = '';
// little bubble sort routine
mySort(obj);
// convert array to string
for (var i = 0; i < obj.length; i++)
str += getHex(obj) + '';
// test for 4, 3, or 2 of a kind with regex
for (i = 0; i < feed.length; i++) {
for (var j = 4; j > 1; j--) {
var rx = new RegExp(feed + "{" + j + "," + j + "}");
// j is 4, 3 or2 of a kind - feed is which pair
if(rx.test(str)) {
return (j + ' of ' + feed);
}
}
return 'nada';
}
As Dr. Stockton suggests, it may be easier or more efficient to convert
the hand to an array and then sort the hand.

var hand_1=["hA,"s8","h3","d8","cA"] // dead man's hand

Here is where you can determine flush, straight, 4's, 3's, 2 pair or
pair, but you still need a mechanism to calculate the relative strength
of this hand versus other hands:

I have opted for the flush and straight via the array and the others via
regex test although converting the suits array to a string and using the
same approach seems relatively simple.
e.g. if(/clubs{4,4}/.test(strFromArray)) then it's a flush altough I think
I read where the literal won't work in a loop because it doesn't get
recompiled at runtime so I'll used the new RegExp('clubs' + "{4,4}")
or an array ['clubs','diamonds',etc] and loop through the suits to
populate the regexs. Anyway it seems to work for me and is fairly
compact.
var hand_2=["hA,"s7","h3","d7","cA"] is clearly inferior to hand_1,
you'll need to create a "compare two pairs" function.

My next step is to handle two pair. There can be no duplicity
of value for 3 or 4 of a kind or better. What remains is to solve the
heirarchy when a single card decides the final value as in the
case of pairs straights or bust hands. Again returning an index
from the feed array should help but the original array may be
easier.
if(is2pair(hand1,hand2,...){compare2p(hand1, hand2,...)}
// could return an array: ["best hand","...","worst hand"]

And don't forget "bespoke" sort functions, which allow you to sort an
array in any order you choose.

Good luck.
Mick

Thanks again Mick and I welcome and value your comments on what I have
added here. We seem to be thinking along the same lines.
Jimbo
 
M

Mick White

J. J. Cale wrote:

My next step is to handle two pair. There can be no duplicity
of value for 3 or 4 of a kind or better. What remains is to solve the
heirarchy when a single card decides the final value as in the
case of pairs straights or bust hands.

//To compare non-premium hands :
Hand1=[10,5,8,7,2]
Hand2=[12,10,8,9,2]

function isVanillaHand(hand){
hand.sort(function(a,b){return a-b;});//numerical sort
for(var i=1;i<5;i++){// start at index[1]
if(hand==hand[i-1]) return false;
}
return true;
}

function getHandValue(hand){
var value=0;
for(var k=0;k<5;k++){
value+=Math.pow(2,hand[k])
}
return value;
}
document.write("Hand#1: "+getHandValue(Hand1)+"<BR>Hand#2: "+
getHandValue(Hand2))


//To get trips, or fours.

function getSets(hand){
var t=1;
hand.sort(function(a,b){return a-b;})
for(j=2;j<5;j++){
if(hand[j]==hand[j-1] && hand[j]==hand[j-2]){
x=hand[j]; t++;
}
}
return x?(t+1)+" "+x+"'s":"No trips or fours";
// x is rank of card, t+1 is how many.
// isTrips(hand) change last line to: return t==2;
// isFours(hand) change last line to: return t==3;
}

alert(getSets([5,2,5,5,5]));

// You can compare like hands using getHandValue()
// i.e trips vs. trips, fours vs. fours
// to determine pairs,two pairs and full houses, use a
// variation of getSets()
// I would encapsulate "hand" and add methods and properties via
// the protoype. And of course, don't forget error checking.

Mick
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,999
Messages
2,570,246
Members
46,839
Latest member
MartinaBur

Latest Threads

Top