简体   繁体   中英

Finding limited number sequence in list

This is a slight rework of a previous question that wasn't quite solved. I am working on a python challenge to create a game of Texas Holdem.

As one of my functions, I am creating a function to check for a "straight" hand.

The simple explanation is that the function will take in a list of 7 cards, sort their [integer] values, and check to see if there is a sequence of 5 or longer.

My function DOES work, but it seems a tad more complicated than is necessary:

def is_straight(hand): #Hand is a list of 7 card objects with integer value attributes

    #sorts the list of cards in the hand based on their [integer] values
    hand.sort(key = attrgetter("value"))

    #While loop to check for sequences in list of cards
    counter = 0
    sequence = 1
    sequences_list = []

    while counter < len(hand)-1:

        #Iterate through the list of int values and, if the value of 1 index == value + 1 of next index, increment sequence number for every sequence
        if hand[counter+1].value == hand[counter].value + 1:
            sequence += 1

        else:
            #When sequence breaks, append the number of the sequence to list and reset sequence counter
            sequences_list.append(sequence)
            sequence = 1
        counter += 1
    
    #after while loop, append the last sequence
    sequences_list.append(sequence)
        
    #Check that sequence has reached 5 or higher
    return max(sequences_list) >= 5

My question is: How could I achieve the same result with a much more condensed code? is there a module (or some other function/trick) that can shortcut this process a bit for more efficient/readable code?

For example, could I import a sequence counter module, break down my "hand" list into a list of values, and return a check that there is a sequence of numbers counting up that has a length of 5 or greater?

EG:

import "imaginary_sequence_counter"

def is_straight(hand):
     
     values = [x.value for x in hand]
     values.sort()

     seq_list = lst(imaginary_sequence_counter(values)

     return max(seq_list) >= 5

That's a bit of a silly example, but I hope it clarifies what I'm looking for. Many thanks for any advice!

As the values are in a small range (1 to 13 I suppose), you can use some binary bit magic.

Let every bit in a single number represent a distinct card value, then "turn on" the bits that correspond to each card in the given hand. Finally check whether there are 5 consecutive 1-bits:

def is_straight(hand):
    bitmask = 0
    for card in hand:
        bitmask |= 1 << card.value
    return "11111" in bin(bitmask)

You could use itertools.groupby to count consecutive increasing sequences from the sorted set of card values in the hand:

from itertools import groupby

hand = [1,2,2,3,5,6,7,8,9]

straights = [len(list(g)) for _,g in
             groupby(enumerate(sorted(set(hand))),key=lambda h:h[1]-h[0]) ]

print(straights) # [3, 5]

This works by grouping card values based on the difference with their index in the sorted set. Consecutive cards will have the same difference with their index and will end up in the same group. So the length of each group is the length of the sequence.

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