Python Forum
why don't i get the answer i want
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
why don't i get the answer i want
#1
Hello, i have this small program:

hand = [['7','h'],['5','h']]
flop = []
turn = []
river = []
table = [['13','H'],['10', 'h'],['12','h'],['11','h'],['9','h']]
playershand = hand + table
pairinhand = False
a = 0
b = 0
c = 0
d = 0
e = 0
f = 0
g = 0
possiblesuite=False
suite = False
playersgrade = []

def checksuiteinplayershand(playershand, possiblesuite):
    suite = playershand
    suite.sort()
    a=int(suite[0][0])
    b=int(suite[1][0])
    c=int(suite[2][0])
    d=int(suite[3][0])
    e=int(suite[4][0])
    f=int(suite[5][0])
    g=int(suite[6][0])
    if a!=b and a!=c and a!=d and a!=g:
        if a+5>b>a and a+5>c>a and a+5>d>a and a+5>e>a:
            possiblesuite=True
            return possiblesuite, g
    if b!=c and b!=d and b!=e and b!=f:
        if b+5>c>b and b+5>d>b and b+5>e>b and b+5>f>b:
            possiblesuite=True
            return possiblesuite, f
    if c!=d and c!=e and c!=f and c!=g:
        if c+5>d>c and c+5>e>c and c+5>f>c and c+5>g>c:
            possiblesuite=True
            return possiblesuite, g
    if a==1:
        a=14
        if g!=f and f!=e and e!=d:
            if g>a-5 and f>a-5 and e>a-5 and d>a-5:
                possiblesuite=True
                return possiblesuite, a
        if g==f and f!=e and e!=d and d!=c:
            if f>a-5 and e>a-5 and d>a-5 and c>a-5:
                possiblesuite=True
                return possiblesuite, a
        if g==f and f==e and e!=d and d!=c and c!=b:
            if d>e-5 and c>e-5 and b>e-5:
                possiblesuite=True
                return possiblesuite, a

print(hand)
print(table)
print(playershand)
print('checksuiteinplayershand:     ', end=' ')
print(checksuiteinplayershand(playershand, possiblesuite))
Output:
[['7', 'h'], ['5', 'h']] [['13', 'H'], ['10', 'h'], ['12', 'h'], ['11', 'h'], ['9', 'h']] [['7', 'h'], ['5', 'h'], ['13', 'H'], ['10', 'h'], ['12', 'h'], ['11', 'h'], ['9', 'h']] checksuiteinplayershand: None
I was expecting

Output:
checksuiteinplayershand: (True, 13)
I've been trying to figure it out for hours now, but to no avail. I mean if it returns 'None' it means the list is empty, but it's not because when i do print(playershand) i get [['7', 'h'], ['5', 'h'], ['13', 'H'], ['10', 'h'], ['12', 'h'], ['11', 'h'], ['9', 'h']] so how can i get 'None' for answer???
Can someone help?
Reply
#2
Can you describe what "checksuiteinplayershand" should do? What is the purpose? "suite" looks a bit like "suit" to my eye, but it doesn't seem to be looking at suits.

One thing that is probably incorrect is that your hand values start as str, they are sorted, and then later converted to int.

So your hand will sort in a text order, not numeric order. [10, 11, 12, 13, 5, 7, 9]

If you're looking for a straight to be in order, it won't necessarily be.
Reply
#3
(Sep-02-2021, 11:17 PM)bowlofred Wrote: Can you describe what "checksuiteinplayershand" should do? What is the purpose? "suite" looks a bit like "suit" to my eye, but it doesn't seem to be looking at suits.

One thing that is probably incorrect is that your hand values start as str, they are sorted, and then later converted to int.

So your hand will sort in a text order, not numeric order. [10, 11, 12, 13, 5, 7, 9]

If you're looking for a straight to be in order, it won't necessarily be.

Yeah, i'm sorry "suite" is french for "straight". the function is supposed to identifie a straight in the players hand, which is two in his hand and five on the table. So it should identifie that there's a straight :[9, 10, 11, 12, 13] return True for the variable 'possiblestraight' and then give back the highest number of the straight which is '13'. Here's a function i have written only for the card present on the table:

def check5outof5suiteinriver(table, possiblesuite):
    suite = table
    a=int(suite[0][0])
    b=int(suite[1][0])
    c=int(suite[2][0])
    d=int(suite[3][0])
    suite = [a,b,c,d]
    suite.sort()
    
    if a!=b and b!=c and c!=d:
        if a+5>b>a and a+5>c>a and a+5>d>a:
            possiblesuite=True
            return possiblesuite, d
        elif a==1:
            a=14
            if b>a-5 and c>a-5 and d>a-5:
                possiblesuite=True
                return possiblesuite, a
and in a print statement, it returns

Output:
(True, 13)
ps: for the string problem should i just write my card as [9, 'h'], [10, 'h'], [11, 'h'], [12,'h'], [13, 'h']? This is the very first program i write by myself so i'm not use to that
Reply
#4
The problem in your first program is that your card values are strings and they don't sort the way you expect.

>>> playerhand = [['7', 'h'], ['5', 'h'], ['13', 'H'], ['10', 'h'], ['12', 'h'], ['11', 'h'], ['9', 'h']]
>>> sorted(playerhand)
[['10', 'h'], ['11', 'h'], ['12', 'h'], ['13', 'H'], ['5', 'h'], ['7', 'h'], ['9', 'h']]
If the card values were ints, then the sort would be as expected.
>>> playerhand = [[int(r), s] for r,s in playerhand]
>>> sorted(playerhand)
[[5, 'h'], [7, 'h'], [9, 'h'], [10, 'h'], [11, 'h'], [12, 'h'], [13, 'H']]
That's better.

One other thing to think about. Do your straights/suites allow the ace to play both high and low? Is [1, 10, 11, 12, 13] a valid straight?
Reply
#5
(Sep-03-2021, 12:38 AM)bowlofred Wrote: The problem in your first program is that your card values are strings and they don't sort the way you expect.

>>> playerhand = [['7', 'h'], ['5', 'h'], ['13', 'H'], ['10', 'h'], ['12', 'h'], ['11', 'h'], ['9', 'h']]
>>> sorted(playerhand)
[['10', 'h'], ['11', 'h'], ['12', 'h'], ['13', 'H'], ['5', 'h'], ['7', 'h'], ['9', 'h']]
If the card values were ints, then the sort would be as expected.
>>> playerhand = [[int(r), s] for r,s in playerhand]
>>> sorted(playerhand)
[[5, 'h'], [7, 'h'], [9, 'h'], [10, 'h'], [11, 'h'], [12, 'h'], [13, 'H']]
That's better.

One other thing to think about. Do your straights/suites allow the ace to play both high and low? Is [1, 10, 11, 12, 13] a valid straight?

Well i completely agree with you that my numbers must be integers and I'll change that right now, but the second function does the exact same thing gives me the right answer and they both have the same list to work from, so why does one return '(True, 13)' and the other returns 'None'?

P.S. Yeah, there's an 'elif' statement that takes care of the 'ace' problem. It's written in the function.
Reply
#6
Your first function logic assumes that all straights are either a,b,c,d,e; b,c,d,e,f; or c,d,e,f,g. So those are the only possibilities you try. And if the list were sorted, that would be correct.

But because this list is not sorted, your straight is actually made of the cards: a,b,c,d,g. Because g is smaller than the others, it isn't detected.

If you convert to int before you sort, it works for some cases, but you have other problems.

def checksuiteinplayershand(playershand, possiblesuite):
    suite = [[int(r), s] for r,s in playershand]
    suite.sort()
    a=int(suite[0][0])
    b=int(suite[1][0])
    ...
Output:
$ python3 pokerhand.py [['7', 'h'], ['5', 'h']] [['13', 'h'], ['10', 'h'], ['12', 'h'], ['11', 'h'], ['9', 'h']] [['7', 'h'], ['5', 'h'], ['13', 'h'], ['10', 'h'], ['12', 'h'], ['11', 'h'], ['9', 'h']] checksuiteinplayershand: (True, 13)
But what would happen if the hand were 5, 10, 11, 12, 12, 12, 13? You wouldn't have a straight, but your function would say you did. You need to not only sort them, you need to remove duplicates. A set is a good way to do that. (you're sort of checking for duplicates, but incompletely)


What I might do to detect a straight would be:
* sort all the unique ranks
* see if the card 4 slots away has a rank 4 less than the current card

hands = [
    [[1, "s"], [2, "s"], [3, "s"], [4, "s"], [7, "s"], [8, "s"], [9, "s"]],  # not a straight
    [[2, "s"], [8, "s"], [5, "s"], [7, "s"], [6, "s"], [10, "s"], [4, "s"]],  # straight
    [[1, "s"], [10, "s"], [11, "s"], [3, "s"], [12, "s"], [3, "h"], [13, "s"]],  # straight (ace high)
    [[2, "s"], [2, "h"], [5, "s"], [5, "h"], [4, "s"], [6, "s"], [3, "s"]],  # straight (duplicate cards)
]


def is_a_straight(hand):
    """Looks for straight in set of hands.  Returns top card of highest straight"""
    size_straight = 5  # must have this many in a row

    # if we reverse sort, we'll find the highest straight when going front to back.
    sorted_ranks = sorted({x[0] for x in hand}, reverse=True)

    if len(sorted_ranks) < size_straight:
        # can't be a straight
        return None

    for start in range(len(sorted_ranks) - size_straight + 1):
        if sorted_ranks[start] - sorted_ranks[start + size_straight - 1] == size_straight - 1:
            return sorted_ranks[start]

    # Check for ace_high
    if 1 in sorted_ranks:
        new_hand = [h for h in hand if h[0] != 1]
        new_hand.append([14, "x"])
        return is_a_straight(new_hand)


for hand in hands:
    print(is_a_straight(hand))
Output:
None 8 14 6
Reply
#7
You need better abstraction. A list is a poor representative of a Card and it isn't much better at representing a hand. A card should be able to compare itself to another card and tell you if it is of equal or lesser value. This makes it easier to compare cards for equality or sorting. With the right abstraction doing things like identifying straights, flushes, full houses and the like can be done with a few lines of code.
import random
import collections

card_suits = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
card_ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']

class Grouper(dict):
    '''Similar to a Counter, but instead of increasing a counter I append to a value list'''
    def __setitem__(self, key, value):
        group = self.get(key, [])
        group.append(value)
        super().__setitem__(key, group)

    def most_common(self):
        '''Return items sorted in decreasing order by count'''
        items = list(super().items())
        items.sort(key=lambda item: len(item[1]), reverse=True)
        return items

class Card():
    '''A playing card.  Has a suite and a rank'''
    def __init__(self, suit, rank):
        self.suit = suit
        self.rank = rank
        self.value = card_ranks.index(rank) + 2
        self.name = f'{rank} {suit}'
        self.abbr = f'{rank}{suit[0]}'

    def __eq__(self, other):
        '''Return True if self has same value as other'''
        return self.value == other.value

    def __lt__(self, other):
        '''Return True if self has lower value than other.  Used for sorting'''
        return self.value < other.value

    def __hash__(self):
        '''Use value as the hash value.  Allows using sets to remove duplicate
        ranks.  Not sure if this is a good idea as it means Cards cannot be used
        as keys in dictionaries.
        '''
        return self.value

    def __repr__(self):
        '''Return nice string representation for card'''
        return self.name

class Hand(list):
    '''A list of cards that knows a little bit about poker'''
    def __init__(self, cards=None):
        self.cards = [] if cards is None else cards.copy()

    def deal(self, deck, count):
        '''Deal count cards from deck into hand'''
        for _ in range(count):
            self.cards.append(deck.pop())
        return self

    def __getitem__(self, index):
        '''Return card[index]'''
        return self.cards[index]

    def append(self, card):
        '''Append card to self.cards'''
        self.cards.append(card)

    def __len__(self):
        '''Return number of cards in hand'''
        return len(self.cards)

    def __add__(self, other):
        '''Make a new hand containing all cards from self and other'''
        return Hand(self.cards + other.cards)

    def __repr__(self):
        '''Make a pretty string rep of a hand'''
        return f"{{{', '.join([card.abbr for card in self.cards])}}}"

    def group_by_rank(self):
        """Return list of cards grouped by rank.  Groups are sorted by count in decreasing order"""
        ranks = Grouper()
        for card in self.cards:
            ranks[card.rank] = card
        return ranks.most_common()

    def group_by_suit(self):
        """Return list of cards grouped by suit.  Groups are sorted by count in decreasing order"""
        suits = Grouper()
        for card in self.cards:
            suits[card.suit] = card
        return suits.most_common()

    def full_house(self):
        '''Return full-house if hand contains 3 of one rank and 2 of another'''
        ranks = self.group_by_rank()
        if len(ranks[0][1]) >= 3 and len(ranks[1][1]) >= 2:
            return ranks[0][1] + ranks[1][1]
        return None

    def two_pair(self):
        '''Return pairs if there are two pairs of matching ranks'''
        ranks = self.group_by_rank()
        if len(ranks[0][1]) >= 2 and len(ranks[1][1]) >= 2:
            return ranks[0][1] + ranks[1][1]
        return None

    def royal_flush(self):
        "Return cards if 10 through Ace if all in same suit"
        flush = self.straight_flush()
        if flush and flush[-1].rank == 'A':
            return flush
        return None

    def straight_flush(self):
        '''Return matching cards if straight is also a flush'''
        flush = self.flush()
        if flush:
            return Hand(flush).straight()
        return None

    def flush(self):
        '''Return matching cards if 5 or more cards have same suit'''
        suits = self.group_by_suit()
        if len(suits[0][1]) >= 5:
            return suits[0][1]
        return False

    def straight(self):
        '''Return cards if 5 cards sequenial by rank'''
        # remove duplicates and sort cards by value
        cards = list(set(self.cards))
        cards.sort()
        # Search for 5 consecutive ranks.  rank[i] + 4 == rank[i+4]
        for i in range(0, len(cards)-4):
            if cards[i].value + 4 == cards[i+4].value:
                return cards[i:i+5]
        return False

results = {}

def print_result(key, hand):
    print(key, hand)
    results[key] = results.get(key, 0) + 1

for _ in range(1000):
    deck = [Card(s, r) for s in card_suits for r in card_ranks]
    random.shuffle(deck)
    table = Hand().deal(deck, 5)
    hand = Hand().deal(deck, 2)
    both = table + hand

    of_a_kind = both.group_by_rank()

    if cards := both.royal_flush():
        print_result('Royal Flush', cards)
    elif cards := both.straight_flush():
        print_result('Straight Flush', cards)
    elif len(of_a_kind[0][1]) > 3:
        print_result('Four of a kind', of_a_kind[0][1])
    elif cards := both.full_house():
        print_result('Full House', cards)
    elif cards := both.flush():
        print_result('Flush', cards)
    elif cards := both.straight():
        print_result('Straight', cards)
    elif len(of_a_kind[0][1]) > 2:
        print_result('Three of a kind', of_a_kind[0][1])

print(results)
Reply
#8
Your deck doesn't seem to allow for aces to be low. A2345 is not detected as a straight.
Reply
#9
My ace is high. Is easy to make if low. Tougher to make it both.

But not a lot tougher.
import random
import collections
 
card_suits = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
card_ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
straights = [set(card_ranks[i:i+5]) for i in range(len(card_ranks)-4)] + [{'A', '2', '3', '4', '5'}]
 
class Grouper(dict):
    '''Similar to a Counter, but instead of increasing a counter I append to a value list'''
    def __init__(self, items=[]):
        super().__init__()
        for item in items:
            self[item[0]] = item[1]

    def __setitem__(self, key, value):
        group = self.get(key, [])
        group.append(value)
        super().__setitem__(key, group)
 
    def most_common(self):
        '''Return items sorted in decreasing order by count'''
        items = list(super().items())
        items.sort(key=lambda item: len(item[1]), reverse=True)
        return items
 
class Card():
    '''A playing card.  Has a suite and a rank'''
    def __init__(self, rank, suit):
        self.suit = suit
        self.rank = rank
        self.value = card_ranks.index(rank) + 2
        self.name = f'{rank} {suit}'
        self.abbr = f'{rank}{suit[0]}'
 
    def __eq__(self, other):
        '''Return True if self has same value as other'''
        return self.value == other.value
 
    def __lt__(self, other):
        '''Return True if self has lower value than other.  Used for sorting'''
        return self.value < other.value
 
    def __hash__(self):
        '''Use value as the hash value.  Allows using sets to remove duplicate
        ranks.  Not sure if this is a good idea as it means Cards cannot be used
        as keys in dictionaries.
        '''
        return self.value
 
    def __repr__(self):
        '''Return nice string representation for card'''
        return self.name
 
class Hand(list):
    '''A list of cards that knows a little bit about poker'''
    def __init__(self, cards=None):
        self.cards = [] if cards is None else cards.copy()
 
    def deal(self, deck, count):
        '''Deal count cards from deck into hand'''
        for _ in range(count):
            self.cards.append(deck.pop())
        return self
 
    def __getitem__(self, index):
        '''Return card[index]'''
        return self.cards[index]
 
    def append(self, card):
        '''Append card to self.cards'''
        self.cards.append(card)
 
    def __len__(self):
        '''Return number of cards in hand'''
        return len(self.cards)
 
    def __add__(self, other):
        '''Make a new hand containing all cards from self and other'''
        return Hand(self.cards + other.cards)
 
    def __repr__(self):
        '''Make a pretty string rep of a hand'''
        return f"{{{', '.join([card.abbr for card in self.cards])}}}"
 
    def group_by_rank(self):
        """Return list of cards grouped by rank.  Groups are sorted by count in decreasing order"""
        return Grouper([(card.rank, card) for card in self.cards]).most_common()
 
    def group_by_suit(self):
        """Return list of cards grouped by suit.  Groups are sorted by count in decreasing order"""
        return Grouper([(card.suit, card) for card in self.cards]).most_common()
 
    def full_house(self):
        '''Return full-house if hand contains 3 of one rank and 2 of another'''
        ranks = self.group_by_rank()
        if len(ranks[0][1]) >= 3 and len(ranks[1][1]) >= 2:
            return ranks[0][1] + ranks[1][1]
        return None
 
    def two_pair(self):
        '''Return pairs if there are two pairs of matching ranks'''
        ranks = self.group_by_rank()
        if len(ranks[0][1]) >= 2 and len(ranks[1][1]) >= 2:
            return ranks[0][1] + ranks[1][1]
        return None
 
    def royal_flush(self):
        "Return cards if 10 through Ace if all in same suit"
        flush = self.straight_flush()
        if flush and flush[-1].rank == 'A':
            return flush
        return None
 
    def straight_flush(self):
        '''Return matching cards if straight is also a flush'''
        flush = self.flush()
        if flush:
            return Hand(flush).straight()
        return None
 
    def flush(self):
        '''Return matching cards if 5 or more cards have same suit'''
        suits = self.group_by_suit()
        if len(suits[0][1]) >= 5:
            return suits[0][1]
        return False
 
    def straight(self):
        '''Return matching cards if hand is superset of a straight set'''
        cards = set(self.cards)
        ranks = set([card.rank for card in cards])
        for straight in straights:
            if straight & ranks == straight:
                return [card for card in cards if card.rank in straight]
        return None

results = {}
 
def print_result(key, hand):
    print(key, hand)
    results[key] = results.get(key, 0) + 1
 
for _ in range(1000):
    deck = [Card(r, s) for s in card_suits for r in card_ranks]
    random.shuffle(deck)
    table = Hand().deal(deck, 5)
    hand = Hand().deal(deck, 2)
    both = table + hand
 
    of_a_kind = both.group_by_rank()
 
    if cards := both.royal_flush():
        print_result('Royal Flush', cards)
    elif cards := both.straight_flush():
        print_result('Straight Flush', cards)
    elif len(of_a_kind[0][1]) > 3:
        print_result('Four of a kind', of_a_kind[0][1])
    elif cards := both.full_house():
        print_result('Full House', cards)
    elif cards := both.flush():
        print_result('Flush', cards)
    elif cards := both.straight():
        print_result('Straight', cards)
    elif len(of_a_kind[0][1]) > 2:
        print_result('Three of a kind', of_a_kind[0][1])
 
print(results)
Reply
#10
def answer(cards: list) -> (bool, int):
    res = None
    def isStraight(cards: list) -> bool:
        nonlocal res
        res = [cards[0]]
        count = 1
        cards.sort()
        for n, card in enumerate(cards):
            if count == 5: return count == 5
            elif n:
                if card-cards[n-1] == 1:
                    count += 1
                    res.append(card)
                else:
                    count = 1
                    res = [card]
        return count == 5
    
    if isStraight(cards):
        return (isStraight(cards), max(res))
    else:
        return (isStraight(cards), None)

def main() -> print:
    player = {'h': [5, 7]}
    table = {'H': [13], 'h': [10, 12, 11, 9]}
    valid = player
    key = table.keys()
    for k in key:
        if k in valid:
            valid[k] = valid[k]+table[k]
        else:
            valid[k] = table[k]
    value = valid.values()
    res = []
    for v in value:
        res = res+v
    if answer(res)[0]:
        print(*answer(res))

if __name__ == "__main__":
    main()
    
Output:
True 13
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  I am getting the wrong answer, and not sure why riskeay 3 2,050 Nov-05-2020, 08:24 PM
Last Post: deanhystad
  Make the answer of input int and str enderfran2006 2 2,008 Oct-12-2020, 09:44 AM
Last Post: DeaD_EyE
  Keeps looping even after correct answer mcesmcsc 2 1,912 Dec-12-2019, 04:27 PM
Last Post: mcesmcsc
  I'm getting a wrong answer don't know where the bug is 357mag 4 2,810 Jul-07-2019, 11:21 PM
Last Post: DeaD_EyE
  How to answer subprocess prompt Monty 8 17,379 Feb-14-2018, 09:59 AM
Last Post: wavic

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020