Contract con_poker_hand_evaluator_v1


Contract Code


  
1 # con_poker_hand_evaluator_v1
2 NUM_CARDS_IN_DECK = 52
3 NUM_VALUES_IN_DECK = 13
4 NUM_SUITS_IN_DECK = 4
5 NUM_CARDS_IN_HAND = 5
6 ACE_VALUE = 2 ** 13
7 STRAIGHT_LOW_ACE_INDICATOR = int("10000000011110", 2)
8 TEN_CARD_POSITION = 8
9 RANK_BASE_VALUE = 10 ** 9
10 RANK_ORDER = [
11 'high_card',
12 'pair',
13 'two_pairs',
14 'trips',
15 'straight',
16 'flush',
17 'full_house',
18 'quads',
19 'straight_flush',
20 'royal_flush',
21 ]
22 DECK = [
23 '2c', '3c', '4c', '5c', '6c', '7c', '8c', '9c', 'Tc', 'Jc', 'Qc', 'Kc', 'Ac',
24 '2d', '3d', '4d', '5d', '6d', '7d', '8d', '9d', 'Td', 'Jd', 'Qd', 'Kd', 'Ad',
25 '2h', '3h', '4h', '5h', '6h', '7h', '8h', '9h', 'Th', 'Jh', 'Qh', 'Kh', 'Ah',
26 '2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', 'Ts', 'Js', 'Qs', 'Ks', 'As',
27 ]
28 RANKS = {
29 '2c': 13, '2d': 13, '2h': 13, '2s': 13,
30 '3c': 12, '3d': 12, '3h': 12, '3s': 12,
31 '4c': 11, '4d': 11, '4h': 11, '4s': 11,
32 '5c': 10, '5d': 10, '5h': 10, '5s': 10,
33 '6c': 9, '6d': 9, '6h': 9, '6s': 9,
34 '7c': 8, '7d': 8, '7h': 8, '7s': 8,
35 '8c': 7, '8d': 7, '8h': 7, '8s': 7,
36 '9c': 6, '9d': 6, '9h': 6, '9s': 6,
37 'Tc': 5, 'Td': 5, 'Th': 5, 'Ts': 5,
38 'Jc': 4, 'Jd': 4, 'Jh': 4, 'Js': 4,
39 'Qc': 3, 'Qd': 3, 'Qh': 3, 'Qs': 3,
40 'Kc': 2, 'Kd': 2, 'Kh': 2, 'Ks': 2,
41 'Ac': 1, 'Ad': 1, 'Ah': 1, 'As': 1,
42 }
43
44 # Python program to illustrate sum of two numbers.
45 def reduce(function, iterable, initializer=None):
46 value = initializer
47 i = 0
48 for element in iterable:
49 value = function(value, element, i)
50 i += 1
51 return value
52
53
54 def rank_value_fn(total, val, index):
55 return total + \
56 ((val == 1 and (2**(index+1))) or 0) + \
57 ((val > 1 and (2**(index+1) * ACE_VALUE * val)) or 0)
58
59
60 def evaluate_5_card_ints(hand: list) -> int:
61 '''
62 A: 8192
63 K: 4096
64 Q: 2048
65 J: 1024
66 T: 512
67 9: 256
68 8: 128
69 7: 64
70 6: 32
71 5: 16
72 4: 8
73 3: 4
74 2: 2
75 A: 1
76
77 10: Royal Flush
78 9: Straight Flush
79 8: Quads (4 of a kind)
80 7: Full House
81 6: Flush
82 5: Straight
83 4: Trips (3 of a kind)
84 3: Two Pairs
85 2: Pair
86 1: High Card
87
88 '''
89 assert len(hand) == 5, 'Invalid number of cards.'
90 suits = [0] * NUM_SUITS_IN_DECK
91 values = [0] * NUM_VALUES_IN_DECK
92
93 for card in hand:
94 suits[card // NUM_VALUES_IN_DECK] += 1
95 values[card % NUM_VALUES_IN_DECK] += 1
96
97 rank_value = reduce(
98 rank_value_fn,
99 values,
100 initializer=0
101 )
102
103 if 1 in values:
104 first_card_index = values.index(1)
105 else:
106 first_card_index = -1
107
108 is_straight = False
109 if first_card_index >= 0:
110 c = values[first_card_index:first_card_index+5]
111 if rank_value == STRAIGHT_LOW_ACE_INDICATOR or \
112 (len(c) == 5 and all([d == 1 for d in c])):
113 is_straight = True
114
115 n_pairs = values.count(2)
116 is_trips = 3 in values
117 ranks = {
118 'royal_flush': False,
119 'straight_flush': False,
120 'quads': 4 in values,
121 'full_house': is_trips and n_pairs == 1,
122 'flush': NUM_CARDS_IN_HAND in suits,
123 'straight': is_straight,
124 'trips': is_trips,
125 'two_pairs': n_pairs == 2,
126 'pair': n_pairs == 1,
127 'high_card': True,
128 }
129 ranks['straight_flush'] = ranks['flush'] and ranks['straight']
130 ranks['royal_flush'] = ranks['straight_flush'] and first_card_index == TEN_CARD_POSITION
131
132 rank_index = 0
133 #rank_description = ""
134 for r in range(len(RANK_ORDER)-1, -1, -1):
135 rank = RANK_ORDER[r]
136 if ranks[rank]:
137 rank_index = r
138 #rank_description = rank
139 break
140
141 rank_value += rank_index * RANK_BASE_VALUE - \
142 ((rank_value == STRAIGHT_LOW_ACE_INDICATOR and ACE_VALUE - 1) or 0)
143
144 return rank_value
145
146
147 def evaluate_7_card_ints(hand: list) -> int:
148 best_rank = None
149 assert len(hand) == 7, 'Invalid number of cards.'
150 # 7 choose 5
151 for i in range(7):
152 for j in range(i+1, 7):
153 new_hand = hand[0:i] + hand[i+1:j] + hand[j+1:]
154 rank = evaluate_5_card_ints(new_hand)
155 if best_rank is None or best_rank < rank:
156 best_rank = rank
157 return best_rank
158
159
160 def evaluate_omaha(hole_cards: list, board: list) -> int:
161 best_rank = None
162 assert len(hole_cards) == 4, 'Invalid number of hole cards'
163 assert len(board) == 5, 'Invalid number of board cards'
164 n = 0
165 for b in range(0, 4):
166 for r in range(b+1, 5):
167 for x in range(0, 3):
168 for y in range(x+1, 4):
169 new_hand = list(board)
170 new_hand[b] = hole_cards[x]
171 new_hand[r] = hole_cards[y]
172 rank = evaluate_5_card_ints(new_hand)
173 if best_rank is None or best_rank < rank:
174 best_rank = rank
175 n += 1
176 return best_rank
177
178
179 @export
180 def evaluate(hand: list) -> int:
181 if len(hand) == 1:
182 # Simple lookup
183 return 14 - RANKS[hand[0]]
184 else:
185 hand = [DECK.index(card) for card in hand]
186 if len(hand) == 5:
187 return evaluate_5_card_ints(hand)
188 elif len(hand) == 7:
189 return evaluate_7_card_ints(hand)
190 elif len(hand) == 9:
191 # Assume board is the last 5 cards
192 return evaluate_omaha(hand[:4], hand[4:])
193 else:
194 assert False, 'Invalid number of cards specified: {}'.format(len(hand))
195
196

Byte Code

e30000000000000000000000003500000040000000737801000064005a0064015a0164025a0264035a03645e5a0465056405640483025a0664065a07645f5a086409640a640b640c640d640e640f641064116412670a5a096413641464156416641764186419641a641b641c641d641e641f6420642164226423642464256426642764286429642a642b642c642d642e642f6430643164326433643464356436643764386439643a643b643c643d643e643f644064416442644364446445644667345a0a6401640164016401644764476447644764486448644864486407640764076407640864086408640864066406640664066449644964496449644a644a644a644a64036403640364036402640264026402644b644b644b644b6404640464046404644c644c644c644c644d9c345a0b6460644f645084015a0c6451645284005a0d650e650564539c026454645584045a0f650e650564539c026456645784045a10650e650e650564589c036459645a84045a116512645b8301650e650564539c02645c645d840483015a13644e53002961e934000000e90d000000e904000000e905000000e9020000005a0e3130303030303030303131313130e908000000e90a000000e909000000da09686967685f63617264da0470616972da0974776f5f7061697273da057472697073da087374726169676874da05666c757368da0a66756c6c5f686f757365da057175616473da0e73747261696768745f666c757368da0b726f79616c5f666c757368da023263da023363da023463da023563da023663da023763da023863da023963da025463da024a63da025163da024b63da024163da023264da023364da023464da023564da023664da023764da023864da023964da025464da024a64da025164da024b64da024164da023268da023368da023468da023568da023668da023768da023868da023968da025468da024a68da025168da024b68da024168da023273da023373da023473da023573da023673da023773da023873da023973da025473da024a73da025173da024b73da024173e90c000000e90b000000e907000000e906000000e903000000e901000000293472130000007220000000722d000000723a00000072140000007221000000722e000000723b00000072150000007222000000722f000000723c000000721600000072230000007230000000723d000000721700000072240000007231000000723e000000721800000072250000007232000000723f0000007219000000722600000072330000007240000000721a000000722700000072340000007241000000721b000000722800000072350000007242000000721c000000722900000072360000007243000000721d000000722a00000072370000007244000000721e000000722b00000072380000007245000000721f000000722c000000723900000072460000004e630300000000000000060000000500000043000000732e0000007c027d0364017d0478207c0144005d187d057c007c037c057c0483037d037c04640237007d04710e57007c03530029034ee900000000724c000000a9002906da0866756e6374696f6eda086974657261626c65da0b696e697469616c697a6572da0576616c7565da0169da07656c656d656e74724e000000724e000000da00da085f5f72656475636519000000730c0000000001040104010a010c010c017256000000630300000000000000030000000400000043000000733c0000007c007c0164016b02721664027c026401170013007018640317007c0164016b04723664027c02640117001300740014007c011400703864031700530029044e724c0000007205000000724d0000002901da094143455f56414c55452903da05746f74616cda0376616cda05696e646578724e000000724e0000007255000000da0f5f5f72616e6b5f76616c75655f666e22000000730400000000012201725b0000002902da0468616e64da0672657475726e6301000000000000000e0000000b00000043000000739e01000074007c00830164016b027314740164028301820164036701740214007d0164036701740314007d0278347c0044005d2c7d037c017c0374031a00050019006404370003003c007c027c0374031600050019006404370003003c00712e5700740474057c02640364058d037d0464047c026b0672807c026a06640483017d056e0464127d0564067d067c0564036b0572ca7c027c057c0564011700850219007d077c0474076b0273c674007c07830164016b0272ca74086407640884007c0744008301830172ca64097d067c026a09640a83017d08640b7c026b067d0964066406640c7c026b067c096ff07c0864046b02740a7c016b067c067c097c08640a6b027c0864046b026409640d9c0a7d0a7c0a640e190090016f1e7c0a640f19007c0a64103c007c0a6410190090016f347c05740b6b027c0a64113c0064037d0b7836740c7400740d83016404180064136414830344005d1e7d0c740d7c0c19007d0d7c0a7c0d1900900172547c0c7d0b50009001715457007c047c0b740e14007c0474076b0290017292740f64041800900170946403180037007d047c0453002915616c0100000a20202020413a20383139320a202020204b3a20343039360a20202020513a20323034380a202020204a3a20313032340a20202020543a20203531320a20202020393a20203235360a20202020383a20203132380a20202020373a20202036340a20202020363a20202033320a20202020353a20202031360a20202020343a20202020380a20202020333a20202020340a20202020323a20202020320a20202020413a20202020310a0a2020202031303a20526f79616c20466c7573680a20202020393a20537472616967687420466c7573680a20202020383a205175616473202834206f662061206b696e64290a20202020373a2046756c6c20486f7573650a20202020363a20466c7573680a20202020353a2053747261696768740a20202020343a205472697073202833206f662061206b696e64290a20202020333a2054776f2050616972730a20202020323a20506169720a20202020313a204869676820436172640a0a2020202072040000007a18496e76616c6964206e756d626572206f662063617264732e724d000000724c0000002901725100000046630100000000000000020000000400000053000000731400000067007c005d0c7d017c0164006b029102710453002901724c000000724e0000002902da022e30da0164724e000000724e0000007255000000fa0a3c6c697374636f6d703e53000000730200000006007a2a5f5f6576616c756174655f355f636172645f696e74732e3c6c6f63616c733e2e3c6c697374636f6d703e547205000000724b0000007203000000290a721200000072110000007210000000720f000000720e000000720d000000720c000000720b000000720a0000007209000000720e000000720d00000072110000007212000000e9ffffffff726100000072610000002910da036c656eda0e417373657274696f6e4572726f72da114e554d5f53554954535f494e5f4445434bda124e554d5f56414c5545535f494e5f4445434b7256000000725b000000725a000000da1a53545241494748545f4c4f575f4143455f494e44494341544f52da03616c6cda05636f756e74da114e554d5f43415244535f494e5f48414e44da1154454e5f434152445f504f534954494f4eda0572616e6765da0a52414e4b5f4f52444552da0f52414e4b5f424153455f56414c55457257000000290e725c000000da057375697473da0676616c756573da0463617264da0a72616e6b5f76616c7565da1066697273745f636172645f696e646578da0b69735f7374726169676874da0163da076e5f7061697273da0869735f7472697073da0572616e6b73da0a72616e6b5f696e646578da0172da0472616e6b724e000000724e0000007255000000da165f5f6576616c756174655f355f636172645f696e7473270000007346000000001d14010a010a010a01140118010e0108010c0204010401080110011601100104010a01080106010e0108010e01080116010a010c0104011a0108010a01040108010a011a01727b000000630100000000000000060000000600000043000000738e00000064007d0174007c00830164016b0273187401640283018201787074026401830144005d647d02785e74027c02640317006401830244005d4c7d037c0064047c02850219007c007c02640317007c038502190017007c007c036403170064008502190017007d0474037c0483017d057c0164006b08737e7c017c056b0072367c057d0171365700712257007c01530029054e72490000007a18496e76616c6964206e756d626572206f662063617264732e724c000000724d000000290472620000007263000000726b000000727b0000002906725c000000da09626573745f72616e6b7253000000da016ada086e65775f68616e64727a000000724e000000724e0000007255000000da165f5f6576616c756174655f375f636172645f696e74736a00000073120000000001040114010e0114012c01080110010c01727f0000002903da0a686f6c655f6361726473da05626f617264725d0000006302000000000000000a000000070000004300000073d000000064007d0274007c00830164016b027318740164028301820174007c01830164036b02732c740164048301820164057d03789a740264056401830244005d8c7d04788674027c04640617006403830244005d747d05786e740264056407830244005d607d06785a74027c06640617006401830244005d487d0774037c0183017d087c007c0619007c087c043c007c007c0719007c087c053c0074047c0883017d097c0264006b0873b07c027c096b0072b47c097d027c03640637007d03717457007160570071505700713c57007c02530029084e72030000007a1c496e76616c6964206e756d626572206f6620686f6c6520636172647372040000007a1d496e76616c6964206e756d626572206f6620626f617264206361726473724d000000724c000000724b000000290572620000007263000000726b000000da046c697374727b000000290a72800000007281000000727c000000da016eda01627279000000da0178da0179727e000000727a000000724e000000724e0000007255000000da105f5f6576616c756174655f6f6d61686176000000732000000000010401140114010401100114011001140108010c010c0108011001040118017287000000da1b636f6e5f706f6b65725f68616e645f6576616c7561746f725f7631630100000000000000010000000500000043000000739200000074007c00830164016b02721c640274017c00640319001900180053006404640584007c00440083017d0074007c00830164066b02723e74027c008301530074007c00830164076b02725274037c008301530074007c00830164086b02727874047c0064006409850219007c00640964008502190083025300640a738e7405640b6a0674007c00830183018301820164005300290c4e724c000000e90e000000724d000000630100000000000000020000000400000053000000731600000067007c005d0e7d0174006a017c018301910271045300724e0000002902da044445434b725a0000002902725e0000007270000000724e000000724e000000725500000072600000008e000000730200000006007a1c6576616c756174652e3c6c6f63616c733e2e3c6c697374636f6d703e7204000000724900000072080000007203000000467a25496e76616c6964206e756d626572206f66206361726473207370656369666965643a207b7d29077262000000da0552414e4b53727b000000727f00000072870000007263000000da06666f726d61742901725c000000724e000000724e0000007255000000da086576616c7561746589000000731600000000020c0110020e010c0108010c0108010c011a020c01728d00000069002000006900ca9a3b29014e2914da114e554d5f43415244535f494e5f4445434b7265000000726400000072690000007257000000da03696e747266000000726a000000726d000000726c000000728a000000728b0000007256000000725b0000007282000000727b000000727f0000007287000000da085f5f6578706f7274728d000000724e000000724e000000724e0000007255000000da083c6d6f64756c653e010000007338000000040104010401040104010a01040104010a010e0116011801180118010e010c010e01100110011001100114030a0908051043100c12130601