I'm trying to write a Poker hand evaluator using NumPy, because I find pure Python is pretty slow.
def eval_(*args):
if len(args) == 5:
hand = np.asarray([*args], dtype=np.int8)
else:
hand = np.asarray(args[0], dtype=np.int8)
ranks = np.bincount(hand // 4, minlength = 13)
count = np.array([np.where(ranks == count)[0] for count in range(5)])
if len(count[4]):
return 8, count[4][0], count[1][0]
if len(count[3]) and len(count[2]):
return 7, count[3][0], count[2][0]
if len(count[3]):
return 4, count[3][0], count[1][1], count[1][0]
if len(count[2]) == 2:
return 3, count[2][1], count[2][0], count[1][0]
if len(count[2]):
return 2, count[2][0], count[1][2], count[1][1], count[1][0]
is_straight = count[1][0] + 4 == count[1][4]
is_acestraight = count[1][4] - 9 == count[1][3]
is_flush = 5 in np.bincount(hand % 4)
if is_straight: return 5 + 4 * is_flush, count[1][4]
if is_acestraight: return 5 + 4 * is_flush, 3
return 1 + 5 * is_flush, count[1][4], count[1][3], count[1][2], count[1][1], count[1][0]
I'm not satisfied with my code. I don't like all kinds of count[1][2]
calls, I should be able to just attach the whole count[1]
array to my return value but I don't know how to do it. And I have trouble with np.where()
. I don't think I should use list comprehension for different count values on this:
count = np.array([np.where(ranks == count)[0] for count in range(5)])
but I have no idea.
count
is a 2d array, it is better form to index it ascount[3,0]
orcount[1,:]
. But maybe it would better to leave it as a nested list. Except for the use ofbincount
I doubt if the use of arrays will give any speed improvement. \$\endgroup\$ – hpaulj Aug 10 '17 at 4:19