def straight_and_highcards(self, straights, highcards): """ Unique five card sets. Straights and highcards. Reuses bit sequences from flush calculations. """ rank = LookupTable.MAX_FLUSH + 1 for s in straights: prime_product = Card.prime_product_from_rankbits(s) self.unsuited_lookup[prime_product] = rank rank += 1 rank = LookupTable.MAX_PAIR + 1 for h in highcards: prime_product = Card.prime_product_from_rankbits(h) self.unsuited_lookup[prime_product] = rank rank += 1
def _five(self, cards): """ Performs an evalution given cards in integer form, mapping them to a rank in the range [1, 7462], with lower ranks being more powerful. Variant of Cactus Kev's 5 card evaluator, though I saved a lot of memory space using a hash table and condensing some of the calculations. """ # if flush if cards[0] & cards[1] & cards[2] & cards[3] & cards[4] & 0xF000: handOR = (cards[0] | cards[1] | cards[2] | cards[3] | cards[4]) >> 16 prime = Card.prime_product_from_rankbits(handOR) return self.table.flush_lookup[prime] # otherwise else: prime = Card.prime_product_from_hand(cards) return self.table.unsuited_lookup[prime]
def flushes(self): """ Straight flushes and flushes. Lookup is done on 13 bit integer (2^13 > 7462): xxxbbbbb bbbbbbbb => integer hand index """ # straight flushes in rank order straight_flushes = [ 7936, # int('0b1111100000000', 2), # royal flush 3968, # int('0b111110000000', 2), 1984, # int('0b11111000000', 2), 992, # int('0b1111100000', 2), 496, # int('0b111110000', 2), 248, # int('0b11111000', 2), 124, # int('0b1111100', 2), 62, # int('0b111110', 2), 31, # int('0b11111', 2), 4111 # int('0b1000000001111', 2) # 5 high ] # now we'll dynamically generate all the other # flushes (including straight flushes) flushes = [] gen = self.get_lexographically_next_bit_sequence(int('0b11111', 2)) # 1277 = number of high cards # 1277 + len(str_flushes) is number of hands with all cards unique rank for i in range(1277 + len(straight_flushes) - 1): # we also iterate over SFs # pull the next flush pattern from our generator f = next(gen) # if this flush matches perfectly any # straight flush, do not add it notSF = True for sf in straight_flushes: # if f XOR sf == 0, then bit pattern # is same, and we should not add if not f ^ sf: notSF = False if notSF: flushes.append(f) # we started from the lowest straight pattern, now we want to start ranking from # the most powerful hands, so we reverse flushes.reverse() # now add to the lookup map: # start with straight flushes and the rank of 1 # since theyit is the best hand in poker # rank 1 = Royal Flush! rank = 1 for sf in straight_flushes: prime_product = Card.prime_product_from_rankbits(sf) self.flush_lookup[prime_product] = rank rank += 1 # we start the counting for flushes on max full house, which # is the worst rank that a full house can have (2,2,2,3,3) rank = LookupTable.MAX_FULL_HOUSE + 1 for f in flushes: prime_product = Card.prime_product_from_rankbits(f) self.flush_lookup[prime_product] = rank rank += 1 # we can reuse these bit sequences for straights # and high cards since they are inherently related # and differ only by context self.straight_and_highcards(straight_flushes, flushes)