from jutge import read, read_many

class Card:
    """Represents a standard playing card.
    
    Attributes:
      suit: integer 0-3
      rank: integer 1-13
    """

    suit_names = ['Clubs', 'Diamonds', 'Hearts', 'Spades']
    rank_names = [None, 'Ace', '2', '3', '4', '5', '6', '7', '8', '9', '10',
        'Jack', 'Queen', 'King']

    def __init__(self, suit=0, rank=2):
        self.suit = suit
        self.rank = rank

    def __str__(self):
        """Returns a human-readable string representation."""
        return '%s of %s' % (Card.rank_names[self.rank],
                             Card.suit_names[self.suit])

    def __lt__(self, other):
        """Compares this card to other, first by suit, then rank.

        returns: bool
        """
        t1 = self.suit, self.rank
        t2 = other.suit, other.rank
        return t1 < t2

class Deck:
    """Represents a deck of cards.

    Attributes:
      cards: list of Card objects.
    """
    
    def __init__(self):
        """Initializes the Deck with 52 cards."""
        self.cards = list()
        for suit in range(4):
            for rank in range(1, 14):
                card = Card(suit, rank)
                self.cards.append(card)

    def __str__(self):
        """Returns a string representation of the deck."""
        res = list()
        for card in self.cards:
            res.append(str(card))
        return '\n'.join(res)

    def add_card(self, card):
        """Adds a card to the deck.

        card: Card
        """
        self.cards.append(card)

    def pop_card(self, i=-1):
        """Removes and returns a card from the deck.

        i: index of the card to pop; by default, pops the last card.
        """
        return self.cards.pop(i)

    def move_cards(self, hand, num):
        """Moves the given number of cards from the deck into the Hand.

        hand: destination Hand object
        num: integer number of cards to move
        """
        for i in range(num):
            hand.add_card(self.pop_card())

    def read_cards(self):
        """Reads a deck of cards."""
        for _ in range(len(self.cards)):
            self.pop_card()
        for rank, _, suit in read_many(str, str, str):
            suit = Card.suit_names.index(suit)
            rank = Card.rank_names.index(rank)
            card = Card(suit, rank)
            self.add_card(card)

    def deal_hands(self, num_hands=2, num_cards=5):
        """Deals hands from the deck and returns Hand objects.

        num_hands: number of hands
        num_cards: number of cards per hand

        returns: list of Hand objects
        """
        hands = list()
        for i in range(num_hands):
            hand = Hand()
            self.move_cards(hand, num_cards)
            hands.append(hand)
        return hands

class Hand(Deck):
    """Represents a hand of playing cards."""

    def __init__(self, label=''):
        self.cards = list()
        self.label = label

class PokerDeck(Deck):
    """Represents a deck of cards that can deal Poker hands."""

    def deal_hands(self, num_hands=2, num_cards=5):
        """Deals hands from the deck and returns PokerHand objects.

        num_hands: number of hands
        num_cards: number of cards per hand

        returns: list of PokerHand objects
        """
        hands = list()
        for i in range(num_hands):
            hand = PokerHand()
            self.move_cards(hand, num_cards)
            hands.append(hand)
        return hands

class PokerHand(Hand):
    """Represents a Poker hand."""

    def make_dictionaries(self):
        self.rank_suits = dict()
        self.suit_ranks = dict()
        for card in self.cards:
            r = card.rank_names[card.rank]
            s = card.suit_names[card.suit]
            self.rank_suits[r] = self.rank_suits.get(r, []) + [s]
            self.suit_ranks[s] = self.suit_ranks.get(s, []) + [r]
        self.rank_lengths = sorted([len(self.rank_suits[r]) for r in self.rank_suits])
        self.suit_lengths = sorted([len(self.suit_ranks[s]) for s in self.suit_ranks])

    def has_one_pair(self):
        """Checks whether this hand has one pair."""
        return self.rank_lengths == [1, 1, 1, 2]

    def has_two_pair(self):
        """Checks whether this hand has two pair."""
        return self.rank_lengths == [1, 2, 2]

    def has_three_of_a_kind(self):
        """Checks whether this hand has three of a kind."""
        return self.rank_lengths == [1, 1, 3]

    def has_straight(self):
        """Checks whether this hand has a straight."""
        if self.rank_lengths != [1, 1, 1, 1, 1]:
            return False
        elif self.suit_lengths == [5]:
            return False
        else:
            ranks = sorted([card.rank for card in self.cards])
            return ranks == list(range(ranks[0], ranks[4] + 1)) or ranks == [1, 10, 11, 12, 13]

    def has_flush(self):
        """Checks whether this hand has a flush."""
        if self.suit_lengths != [5]:
            return False
        else:
            ranks = sorted([card.rank for card in self.cards])
            return ranks != list(range(ranks[0], ranks[4] + 1)) and ranks != [1, 10, 11, 12, 13]

    def has_full_house(self):
        """Checks whether this hand has a full house."""
        return self.rank_lengths == [2, 3]

    def has_four_of_a_kind(self):
        """Checks whether this hand has four of a kind."""
        return self.rank_lengths == [1, 4]

    def has_straightflush(self):
        """Checks whether this hand has a straight flush."""
        if self.suit_lengths != [5]:
            return False
        else:
            ranks = sorted([card.rank for card in self.cards])
            return ranks == list(range(ranks[0], ranks[4] + 1)) or ranks == [1, 10, 11, 12, 13]

    def classify(self):
        """Classifies this hand."""
        self.make_dictionaries()
        if self.has_straightflush():
            self.label = 'Straight flush'
        elif self.has_four_of_a_kind():
            self.label = 'Four of a kind'
        elif self.has_full_house():
            self.label = 'Full house'
        elif self.has_flush():
            self.label = 'Flush'
        elif self.has_straight():
            self.label = 'Straight'
        elif self.has_three_of_a_kind():
            self.label = 'Three of a kind'
        elif self.has_two_pair():
            self.label = 'Two pair'
        elif self.has_one_pair():
            self.label = 'One pair'
        else:
            self.label = 'None'

class Player:
  # ...

class Game:
  # ...

num_hands = read(int)
num_cards = read(int)
deck = PokerDeck()
deck.read_cards()
players = [ Player('Player ' + str(i)) for i in range(1, num_hands + 1) ]
game = Game('Simple Poker Game', deck, players, num_cards)
player, hand = game.decide_winner()
print('Winner:', player)

