// Filename: eval.cpp // Author: Barry Greenstein // Last updated: Nov 4, 2003 // Purpose: This file contains the function handeval() which accepts an array of // seven cards and returns a value that can be used for ranking poker hands. // Return values less than 10 indicate errors in the seven card hand array. // We use 16 bits to represent each poker hand: the first three bits give us the // nine possible hand types. (There are few enough straight flushes and quads to // use the same value for both.) The last 13 bits distinguish hand values within // each hand type. (The highest 13 bit number is 2 ** 13 - 1, which is 8191.) // All cards are represented by 2 less than their face value, since a Deuce, // the lowest card, is represented by the number 0. #define STRAIGHTFLUSH 0xe000 // 1110000000000000 binary // last 13 bits: 169 * high card of the straight flush #define QUADS 0xe000 // 1110000000000000 binary // last 13 bits: 13 * quad number + kicker #define FULLHOUSE 0xc000 // 1100000000000000 binary // last 13 bits: 13 * trip number + pair number #define FLUSH 0xa000 // 1010000000000000 binary // last 13 bits: turn on the five bits on that represent the cards #define STRAIGHT 0x8000 // 1000000000000000 binary // last 13 bits: high card of the straight #define TRIPS 0x6000 // 0110000000000000 binary // last 13 bits: 169 * trip number + 13 * high kicker + low kicker #define TWOPAIR 0x4000 // 0100000000000000 binary // last 13 bits: 169 * high pair + 13 * low pair + kicker #define ONEPAIR 0x2000 // 0010000000000000 binary // last 13 bits: 286 * pair + combinatorial rank (0 to 285) of the three kickers #define NOPAIR 0 // 0000000000000000 binary // last 13 bits: bit positions of the five cards are set #define TOO_FEW_CARDS 0 // Error if fewer than five cards are given #define DUPLICATE_CARD 1 // Error two cards in the hand are the same #define ILLEGAL_CARD_VALUE 2 // Error for card values greater than 51 #include // necessary so we can print errors if they arise // For flushes and no-pair hands we just set the bits in the positions of the // five cards in the hand. For instance, an AQ962 flush is represented by the // binary number 1011010010010001. The first three bits, 101, denote the flush, // and bits for A, Q, 9, 6, and 2, which are actually bits 12, 10, 7, 4, and 0, // are set to denote those cards. unsigned handeval(int card[]){ unsigned isitstraight(unsigned); // this function will check for straights int suits[4] = {0, 0, 0, 0}; // for each hand this will contain the number of cards in each suit int ranks[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // for each hand this will contain the number of cards in each rank // Card values are 13 * suit + rank, where suits are numbered 0 to 3 // and ranks are 0 to 12. // For example, Ace of spades is card 51 // Seven of hearts is 31, and // deuce of clubs is 0. // When there are only five cards instead of seven, we will use -1 for // the value of the two vacant cards. int flushsuit = -1; // if flush exists, this will be 0,1,2,or 3 corresponding // to clubs, diamonds, hearts, or spades. unsigned rankbits = 0; // this will have bits turned on from 0 to 12 that // correspond to cards in the hand from Deuce to Ace int cardsinhand = 0; // this tracks the number if cards in the hand for (int i = 0; i < 7; i++){ if (card[i] >= 0){ // we skip negative values for cards if (card[i] >= 52) { printf("Illegal card value. Cards %d %d %d %d %d %d %d.", card[0],card[1],card[2],card[3],card[4],card[5],card[6]); return ILLEGAL_CARD_VALUE; } for (int j = 0; j < i; j++) if (card[j] == card[i]){ // duplicate printf("Duplicate card. Cards %d %d %d %d %d %d %d.", card[0],card[1],card[2],card[3],card[4],card[5],card[6]); return DUPLICATE_CARD; } cardsinhand++; if (suits[card[i]/13]++ >= 4) // one more of this suit flushsuit = card[i]/13; // this is at least the fifth of this suit ranks[card[i] % 13]++; // one more of this denomination rankbits |= (1 << (card[i] % 13)); // turn on bit two less than card value // For example, deuces are cards 0, 13, 26, and 39, which are 0 modulo 13 // 1 is shifted left 0 times, and the bitwise "or" turns bit 0 on } } // end of "for" that goes through the seven cards if (cardsinhand < 5){ // not enough cards printf("Not enough cards. Cards %d %d %d %d %d %d %d.", card[0],card[1],card[2],card[3],card[4],card[5],card[6]); return TOO_FEW_CARDS; } if (flushsuit >= 0){ rankbits = 0; // reset since we will only include flush cards for(i = 0; i < 7; i++){ if (card[i] >= 0) // if we have a valid card if (card[i]/13 == flushsuit) // if card is in the flush suit rankbits |= (1 << (card[i] % 13));// set rank position bit if in flush } unsigned straighttopcard = isitstraight(rankbits); // check for straight if (straighttopcard != 0) // is there a straight flush? return STRAIGHTFLUSH + 169 * straighttopcard; int numbitsset = 0; // will use this to track how many cards are of flush suit for (i = 12; i >= 0; i--){ // go from highest rank to lowest rank if (rankbits & (1 << i)) // found a card in the flush if (numbitsset++ >= 5) // already have 5 in flush suit rankbits ^= (1 << i); // remove low flush cards } return FLUSH + rankbits; // bits of five highest flush cards are set } // end of flush "if" unsigned straighttopcard = isitstraight(rankbits); // not a flush; check for straight if (straighttopcard != 0) return STRAIGHT + straighttopcard; // In the statements below, variables are initialized to -1 to indicate // that they are undefined or "yet to be defined" int quadnum = -1; // this will contain the rank of quads, if they are present int tripnum = -1; // this will contain the rank of trips int highpair = -1; // this will contain the rank of the highest pair int lowpair = -1; // this will contain the rank of the second highest pair int kicker1 = -1; // use this with quads, trips, two pairs, and one pair int kicker2 = -1; // second kicker of trips or pair int kicker3 = -1; // third kicker in one pair hands for (i = 12; i >= 0; i--){ switch (ranks[i]){ case 1: if (kicker1 == -1) // any kickers yet? kicker1 = i; // i is highest kicker else if (kicker2 == -1) // is there a second highest kicker? kicker2 = i; // i is second highest kicker else if (kicker3 == -1) // is there a third kicker kicker3 = i; // i is third kicker break; case 2: if (highpair == -1)// if we haven't found a pair highpair = i; else if (lowpair == -1) // we have one pair; is there a second? lowpair = i; else if (kicker1 == -1) // we already have two pair; have we established kicker kicker1 = i; // use third pair rank as kicker for two pair break; case 3: if (tripnum == -1) // if we haven't found trips yet tripnum = i; else // we have two sets of trips highpair = i; // use lower trip for pair in full house break; case 4: quadnum = i; break; } } if (quadnum >= 0){ // quads if (tripnum > 0) // quads and trips kicker1 = tripnum; // use trips as kicker if (highpair > kicker1) kicker1 = highpair; // use pair as kicker return QUADS + 13 * quadnum + kicker1; } if (tripnum >= 0){ // trips or full house if (highpair >= 0) // is it only trips or full house? return FULLHOUSE + 13 * tripnum + highpair; return TRIPS + 169 * tripnum + 13 * kicker1 + kicker2; } if (highpair >= 0){ if (lowpair >= 0) return TWOPAIR + 169 * highpair + 13 * lowpair + kicker1; // We have only one pair and therefore three kickers. // There are (13 choose 3), which is 286, different three-kicker combinations. // (For each pair, there are actually (12 choose 3) combinations, but // it isn't necessary to use that fact here.) // We are doing all of this tricky combination stuff because we are trying // to distinctly represent 4 numbers from 0 to 13 with 13 bits. // If we weren't tricky, we would need to handle numbers up to 13 ** 4. // Unfortunately 13 ** 4 = 28561, which is greater than 8192, so we use combinations. int combnum = 0; // will count combinations until we get to 2, 1, 0 case while (kicker1 != 2){ // we are done when highest kicker is represent by 2 if (kicker3-- == 0) // lower kicker3 until we get to 0 kicker3 = --kicker2 - 1; // after decreasing kicker2, make kicker3 one less if (kicker2 == 0){ // did we lower kicker2 too far? kicker2 = --kicker1 - 1; // after decreasing kicker1, make kicker2 one less kicker3 = kicker2 - 1; // restart kicker3 one less than kicker2 } combnum++; // we have counted another combination } return ONEPAIR + 286 * highpair + combnum; } // only hands with no pair are left int numbitsset = 0; // will use this to track how many cards there are for (i = 12; i >= 0; i--){ // go from highest rank to lowest rank if (rankbits & (1 << i)) // found a card if (numbitsset++ >= 5) // already have five cards rankbits ^= (1 << i); // remove superfluous cards } return NOPAIR + rankbits; } unsigned isitstraight(unsigned rankbits){ // input is a rankbit which represents a five or more card hand // bits are set in the location of the actual card rank minus 2 // the function determines if 5 consecutive bits are set // and returns the highest bit position set in a straight int consecutive = 0; for(int i = 12; i >=0; i--){ if (rankbits & (1 << i)) consecutive++; // one more in a row else consecutive = 0; // start over looking for cards in sequence if (consecutive == 5) // has straight been located? return (unsigned)(i + 4); // highest card in straight } if ((consecutive == 4) && (rankbits & (1 << 12))) // 2,3,4,5 were in hand return 3; // wheel: Five is highest card; Internally a Five is 5 - 2 which is 3 return 0; // no straight }