package main import "testing" func TestEvaluate5Categories(t *testing.T) { tests := []struct { name string cards []Card want PokerHandCategory }{ {"роял-флеш", []Card{c(Ten, Spades), c(Jack, Spades), c(Queen, Spades), c(King, Spades), c(Ace, Spades)}, PokerStraightFlush}, {"стрит-флеш", []Card{c(Five, Hearts), c(Six, Hearts), c(Seven, Hearts), c(Eight, Hearts), c(Nine, Hearts)}, PokerStraightFlush}, {"каре", []Card{c(Nine, Clubs), c(Nine, Diamonds), c(Nine, Hearts), c(Nine, Spades), c(Two, Clubs)}, PokerFourOfAKind}, {"фулл-хаус", []Card{c(King, Clubs), c(King, Diamonds), c(King, Hearts), c(Two, Spades), c(Two, Clubs)}, PokerFullHouse}, {"флеш", []Card{c(Two, Hearts), c(Five, Hearts), c(Seven, Hearts), c(Nine, Hearts), c(King, Hearts)}, PokerFlush}, {"стрит", []Card{c(Four, Clubs), c(Five, Diamonds), c(Six, Hearts), c(Seven, Spades), c(Eight, Clubs)}, PokerStraight}, {"колесо (A-5 стрит)", []Card{c(Ace, Clubs), c(Two, Diamonds), c(Three, Hearts), c(Four, Spades), c(Five, Clubs)}, PokerStraight}, {"тройка", []Card{c(Jack, Clubs), c(Jack, Diamonds), c(Jack, Hearts), c(Two, Spades), c(Nine, Clubs)}, PokerThreeOfAKind}, {"две пары", []Card{c(Ten, Clubs), c(Ten, Diamonds), c(Four, Hearts), c(Four, Spades), c(Nine, Clubs)}, PokerTwoPair}, {"пара", []Card{c(Eight, Clubs), c(Eight, Diamonds), c(Two, Hearts), c(Five, Spades), c(Nine, Clubs)}, PokerPair}, {"старшая карта", []Card{c(Two, Clubs), c(Five, Diamonds), c(Seven, Hearts), c(Nine, Spades), c(King, Clubs)}, PokerHighCard}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := evaluate5(tt.cards) if got.Category != tt.want { t.Errorf("ожидалась категория %v, получено %v (карты: %v)", tt.want, got.Category, tt.cards) } }) } } func TestWheelStraightRanksAsFive(t *testing.T) { wheel := evaluate5([]Card{c(Ace, Clubs), c(Two, Diamonds), c(Three, Hearts), c(Four, Spades), c(Five, Clubs)}) if wheel.Category != PokerStraight || wheel.Tiebreak[0] != 5 { t.Fatalf("колесо A-2-3-4-5 должно оцениваться как стрит со старшей картой 5, получено %+v", wheel) } sixHighStraight := evaluate5([]Card{c(Two, Clubs), c(Three, Diamonds), c(Four, Hearts), c(Five, Spades), c(Six, Clubs)}) if ComparePokerHands(sixHighStraight, wheel) <= 0 { t.Errorf("стрит 2-6 должен быть старше колеса A-5") } } func TestNotAStraightWhenWheelBrokenByAceHigh(t *testing.T) { notStraight := evaluate5([]Card{c(Ace, Clubs), c(Two, Diamonds), c(Three, Hearts), c(Four, Spades), c(King, Clubs)}) if notStraight.Category == PokerStraight || notStraight.Category == PokerStraightFlush { t.Errorf("A,2,3,4,K не должно засчитываться как стрит, получено %v", notStraight.Category) } } func TestRoyalFlushBeatsStraightFlush(t *testing.T) { royal := evaluate5([]Card{c(Ten, Spades), c(Jack, Spades), c(Queen, Spades), c(King, Spades), c(Ace, Spades)}) lower := evaluate5([]Card{c(Five, Hearts), c(Six, Hearts), c(Seven, Hearts), c(Eight, Hearts), c(Nine, Hearts)}) if ComparePokerHands(royal, lower) <= 0 { t.Errorf("роял-флеш должен быть строго сильнее стрит-флеша 5-9") } } func TestFourOfAKindKickerBreaksTie(t *testing.T) { a := evaluate5([]Card{c(Nine, Clubs), c(Nine, Diamonds), c(Nine, Hearts), c(Nine, Spades), c(King, Clubs)}) b := evaluate5([]Card{c(Nine, Clubs), c(Nine, Diamonds), c(Nine, Hearts), c(Nine, Spades), c(Two, Clubs)}) if ComparePokerHands(a, b) <= 0 { t.Errorf("одинаковое каре девяток с кикером королём должно побеждать кикер двойку") } } func TestFullHouseTripsMatterMoreThanPair(t *testing.T) { a := evaluate5([]Card{c(Two, Clubs), c(Two, Diamonds), c(Two, Hearts), c(King, Spades), c(King, Clubs)}) b := evaluate5([]Card{c(Queen, Clubs), c(Queen, Diamonds), c(Queen, Hearts), c(Ace, Spades), c(Ace, Clubs)}) if ComparePokerHands(b, a) <= 0 { t.Errorf("фулл-хаус на тройке дам должен побеждать фулл-хаус на тройке двоек, несмотря на более слабую пару") } } func TestTwoPairComparesHigherPairFirst(t *testing.T) { a := evaluate5([]Card{c(King, Clubs), c(King, Diamonds), c(Two, Hearts), c(Two, Spades), c(Nine, Clubs)}) b := evaluate5([]Card{c(Queen, Clubs), c(Queen, Diamonds), c(Jack, Hearts), c(Jack, Spades), c(Ace, Clubs)}) if ComparePokerHands(a, b) <= 0 { t.Errorf("две пары королей и двоек должны побеждать пары дам и валетов, несмотря на более слабый кикер") } } func TestTwoPairKickerBreaksExactTie(t *testing.T) { a := evaluate5([]Card{c(King, Clubs), c(King, Diamonds), c(Two, Hearts), c(Two, Spades), c(Ace, Clubs)}) b := evaluate5([]Card{c(King, Hearts), c(King, Spades), c(Two, Clubs), c(Two, Diamonds), c(Nine, Hearts)}) if ComparePokerHands(a, b) <= 0 { t.Errorf("при равных парах решает кикер — туз должен побеждать девятку") } } func TestPairComparesKickersInOrder(t *testing.T) { a := evaluate5([]Card{c(Eight, Clubs), c(Eight, Diamonds), c(Ace, Hearts), c(Two, Spades), c(Three, Clubs)}) b := evaluate5([]Card{c(Eight, Hearts), c(Eight, Spades), c(King, Clubs), c(Queen, Diamonds), c(Jack, Hearts)}) if ComparePokerHands(a, b) <= 0 { t.Errorf("при равных парах восьмёрок кикер-туз должен побеждать набор король-дама-валет") } } func TestFlushComparesAllFiveCardsInOrder(t *testing.T) { a := evaluate5([]Card{c(Two, Hearts), c(Five, Hearts), c(Seven, Hearts), c(Nine, Hearts), c(Ace, Hearts)}) b := evaluate5([]Card{c(Two, Spades), c(Five, Spades), c(Seven, Spades), c(Nine, Spades), c(King, Spades)}) if ComparePokerHands(a, b) <= 0 { t.Errorf("флеш с тузом должен побеждать флеш с королём при прочих равных") } } func TestIdenticalHandsSplitPot(t *testing.T) { a := evaluate5([]Card{c(Two, Hearts), c(Five, Hearts), c(Seven, Hearts), c(Nine, Hearts), c(King, Hearts)}) b := evaluate5([]Card{c(Two, Spades), c(Five, Spades), c(Seven, Spades), c(Nine, Spades), c(King, Spades)}) if ComparePokerHands(a, b) != 0 { t.Errorf("одинаковые по значению флеши разных мастей должны оцениваться как полностью равные (сплит банка), получено a=%+v b=%+v", a, b) } } func TestEvaluateBest5ChoosesBestOfSeven(t *testing.T) { hole := []Card{c(Ace, Spades), c(Ace, Hearts)} board := []Card{c(Ace, Clubs), c(Ace, Diamonds), c(King, Spades), c(Two, Hearts), c(Three, Clubs)} all := append(append([]Card{}, hole...), board...) best := EvaluateBest5(all) if best.Category != PokerFourOfAKind { t.Fatalf("ожидалось каре тузов из семи карт, получено %v", best.Category) } if best.Tiebreak[0] != 14 || best.Tiebreak[1] != 13 { t.Errorf("кикером каре тузов должен был стать король (13), получено %+v", best.Tiebreak) } } func TestEvaluateBest5IgnoresWorseFiveCardSubset(t *testing.T) { hole := []Card{c(Two, Hearts), c(Nine, Hearts)} board := []Card{c(Five, Hearts), c(Six, Hearts), c(Seven, Clubs), c(Eight, Diamonds), c(King, Hearts)} all := append(append([]Card{}, hole...), board...) best := EvaluateBest5(all) if best.Category != PokerFlush { t.Fatalf("ожидался флеш как лучшая комбинация из семи карт, получено %v", best.Category) } } func TestCombinations5Count(t *testing.T) { cards := make([]Card, 7) for i := range cards { cards[i] = c(Rank(2+i), Clubs) } count := 0 combinations5(cards, func(combo []Card) { count++ }) if count != 21 { t.Errorf("ожидалось ровно 21 сочетание из 7 по 5, получено %d", count) } }