简体   繁体   中英

check if all tuples contain a specific value

I have a list of tuples representing playing cards: hand = [('A', '♣'), ('A', '♠'), ('A', '♦'), ('A', '♥'), ('K', '♠')] and I want to check if I have a flush.

I thought of using all(h[1] == '♠' for h in hand) and it seems to work well ( False in this case, but True in others, where it should. Of course I'll need to check this for all 4 suits... ), but I wanted to know if this is the right/best way to do so

You could:

any(all(h[1] == suit for h in hand) for suit in ('♣','♠','♦','♥'))

Which isn't very efficient but very readable in my opinion or you could do as suggested by @ Ev. Kounis in the comments, which is much more efficient solution but not very readable. Since this game only has 52 cards per deck, 4 suits, 13 sets, and 5 cards per hand, the numbers aren't so large that they require any special treatment for efficiency, so I would go with this solution.

To add onto Ofer Sadans answer, i would suggest using flags to represent cards, since computers are easier for integer to calculate value via bitwise operators than unicode string manipulation .

This solution would need some sort of conversion from tuple type to integer representation but it is possible with simple lambda function.

card = ('K','\u2660') # for example. K ♠
card_pack = lambda c: (ord(c[0])<<16)+ord(c[1])  #c for card 
# where you have now 32 bit integer that contains all your values  
# 00000000-01001011|00100110-01100000 == 4 925 024 
#        KING      |      SPADE 

With this version you can ( as long you have finite number of cards in a hand ) make a hand long integer and check a hand as a whole. With premade masks you can easily check for all decks and values with single == logical operator.

hand = [('A', u'\u2663'), ('A', u'\u2660'), ('A', u'\u2666'), ('A', u'\u2665'), ('K', u'\u2660')]
hand_i = map( card_pack, hand ) 
hand_i = sum( [ val<<( shift*32 ) shift,val in enumerate(hand_i) ] )  

Then if you need you can unpack each card with unpacking function:

card_unpack = lambda ci: ( (ci>>16)&0xffff, ci&0xffff) #ci for card integer 
unpack_2_individual_cards = lambda hand_i,_i: (hand_i>>(32*_i))&0xffffffff

# then you just need to do similar function as summing for hand_i but inverse to get each card individual and use unichr/chr to represent values after that.   
hand = [ unpack_2_individual_cards(hand_i, i ) for i in range(5) ]   

And then the test for strength of hand or what type of hand it is would be easy as :

STRAIGHT = 1675898824200706064573121072408259537242498659 
if hand_i&STRAIGHT==STRAIGHT: print('you have straight') 
if hand_i < STRAIGHT: print('straight wins!!')

Have in mind that any logical operation ( with all and any ) use this same approach on finding logical relationships between elements. It is just that this type of approach is so low level that it is under the surface. The type of data that we compare is to us as programmers , but to computer it is all the same as long as we tell it where to find it.

You can use struct module for packing and unpacking the data instead of those lambdas and you can check the specific type of deck in hand with simple mask of 0x00ff00ff00ff00ff00ff and values in hand with 0xff00ff00ff00ff00ff00 since all cards are packed by value|deck .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM