hand.py 3.55 KB
Newer Older
1 2 3
from collections import Counter
from typing import List

4 5
from pydantic.main import BaseModel

6 7 8 9
from server.encoding import encode_color, encode_value
from server.model.card import Card
from server.model.color import Color
from server.model.value import Value
10 11


12 13
class Hand(BaseModel):
    cards: List[Card] = []
14

15 16 17 18 19 20
    class Config:
        json_encoders = {
            Value: encode_value,
            Color: encode_color,
        }

21 22 23 24 25 26 27 28 29 30 31 32 33
    def __contains__(self, item: Card):
        return item in self.cards

    def __len__(self) -> int:
        return len(self.cards)

    def __getitem__(self, item):
        return self.cards[item]

    def __repr__(self):
        return "|".join([str(c) for c in self.cards])

    def give(self, other: Card):
34 35 36 37 38 39 40
        """
        Adds another card to this hand.

        :raises ValueError if the card is already in this hand.
        """
        if (other.value, other.color) in [(c.value, c.color) for c in self.cards]:
            raise ValueError(f"TRICHEUR! {other} already in this hand: {self.cards}!")
41 42 43
        self.cards.append(other)

    def value(self):
44
        """ Scores this hand according to the Poker Menteur rules."""
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
        counter = Counter([c.value for c in self.cards])

        has_pair = False
        has_double_pair = False
        has_brelan = False
        has_full = False
        has_carre = False

        highest_card = None
        pair = None
        double_pair = None
        brelan = None
        carre = None

        for element, count in counter.items():
            element_cards = [c for c in self.cards if c.value == element]
            card = element_cards[0]  # Note we take a random color
            highest_card = max(highest_card, card) if highest_card else card

            if count == 2:
                if has_pair:
                    has_double_pair = True
                    double_pair = max(pair, card)
                    pair = min(pair, card)
                else:
                    has_pair = True
                    pair = max(pair, card) if pair else card
            if count == 3:
                has_brelan = True
                brelan = max(brelan, card) if brelan else card
            if has_brelan and has_pair:
                has_full = True
            if count == 4:
                has_carre = True
                carre = max(carre, card) if carre else card

        analysis_log = " | ".join([
            f"ANALYSIS",
            f"Carre[{carre}]" if has_carre else "no carre",
            f"Full[{brelan}|{pair}]" if has_full else "no full",
            f"Brelan[{brelan}]" if has_brelan else "no carre",
            f"Double paire[{double_pair}|{pair}]" if has_double_pair else "no Dpaire",
            f"Paire[{pair}]" if has_pair else "no paire",
            f"Card[{highest_card}]"
        ])
        # Finished counting, let's return scores
        if has_carre:
            score = (20 ** 5) * carre.score()
        elif has_full:
            score = (20 ** 4) * brelan.score() + 20 * pair.score()
        elif has_brelan:
            score = (20 ** 3) * brelan.score()
        elif has_double_pair:
            score = (20 ** 2) * double_pair.score() + pair.score()
        elif has_pair:
            score = 20 * pair.score()
        else:
            score = highest_card.score()

        analysis_log += f"\t-> score=\t{score}"
        # print(analysis_log)
106 107 108 109 110 111 112 113 114
        return score

    @property
    def is_menteur(self) -> bool:
        return len(self.cards) == 0

    @property
    def is_carre_as(self) -> bool:
        return len(self.cards) == 4 and all([c.value == Value.Ace for c in self.cards])