The below code is ordering poker hands. It works well in Python 2.7 but it does not work in Python 3. What are the changes that have been made causing it to give an TypeError: unorderable types: tuple() < int()?
def poker(hands):
scores = [(i, score(hand.split())) for i, hand in enumerate(hands)]
winner = sorted(scores , key=lambda x:x[1])[-1][0]
return hands[winner]
def score(hand):
ranks = '23456789TJQKA'
rcounts = {ranks.find(r): ''.join(hand).count(r) for r, _ in hand}.items()
score, ranks = zip(*sorted((cnt, rank) for rank, cnt in rcounts)[::-1])
if len(score) == 5:
if ranks[0:2] == (12, 3): #adjust if 5 high straight
ranks = (3, 2, 1, 0, -1)
straight = ranks[0] - ranks[4] == 4
flush = len({suit for _, suit in hand}) == 1
'''no pair, straight, flush, or straight flush'''
score = ([1, (3,1,1,1)], [(3,1,1,2), (5,)])[flush][straight]
return score, ranks
>>> poker(['8C TS KC 9H 4S', '7D 2S 5D 3S AC', '8C AD 8D AC 9C', '7C 5H 8D TD KS'])
'8C AD 8D AC 9C'
It is happening because you are comparing int
and a tuple
. In python2x, default cmp
operation was defined for different inbuilt objects, which has been removed in python3.
Python 3 ignores the cmp() method. In addition to this, the cmp() function is gone! This typically results in your converted code raising a TypeError: unorderable types error. So you need to replace the cmp() method with rich comparison methods instead. To support sorting you only need to implement lt(), the method used for the “less then” operator, <.
Official documentation
So, in python2, we can do something like this
(2, 3) > 2
but it raises TypeError
in python3. If this code was working in python2, then most probably it was bug that was implicitly being handled by default comparison behaviour.
Now in your example:-
#value of scores that are being compared for sorting
scores = [(0, (1, (11, 8, 7, 6, 2))), (1, (1, (12, 5, 3, 1, 0))), (2, ((2, 2, 1), (12, 6, 7))), (3, (1, (11, 8, 6, 5, 3)))]
print(type(scores[1][1][0])) # <class 'int'>
print(type(scores[2][1][0])) # <class 'tuple'>
which as I have explained does not work in python3. What is the criteria you are assuming for comparing a tuple
and an int
.
If you really want to compare different type of objects, then you need to roll out your own version of tuple
, and use that object in your scores
instead.
class MyTuple(tuple):
def __lt__(self, other):
pass
Default tuple comparison python 2
Note:- I don't recommend using this approach. It was just for instructional purposes.
The solution: Convert the integer into a tuple: score = ([(1, ), (3,1,1,1)], [(3,1,1,2), (5,)])[flush][straight]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With