Files
back-hokm/internal/game/hokm_test.go
T
2026-06-15 16:53:25 +03:30

129 lines
3.7 KiB
Go

package game
import "testing"
func TestParseCardRoundTrip(t *testing.T) {
cases := []string{"AS", "10H", "2C", "KD", "JS", "QH"}
for _, code := range cases {
c, err := ParseCard(code)
if err != nil {
t.Fatalf("parse %q: %v", code, err)
}
if c.String() != code {
t.Errorf("roundtrip %q -> %q", code, c.String())
}
}
}
func TestBeats(t *testing.T) {
trump := Hearts
lead := Spades
// آتو بر غیرآتو می‌برد
if !beats(Card{Hearts, 2}, Card{Spades, Ace}, trump, lead) {
t.Error("trump 2 should beat non-trump Ace")
}
// بالاترین خال زمینه بر کارت خال دیگر (غیرآتو) می‌برد
if !beats(Card{Spades, 5}, Card{Diamonds, Ace}, trump, lead) {
t.Error("lead-suit card should beat off-suit card")
}
// کارت خارج از خال زمینه و غیرآتو نمی‌برد
if beats(Card{Diamonds, Ace}, Card{Spades, 2}, trump, lead) {
t.Error("off-suit non-trump should not beat lead suit")
}
}
func TestMustFollowSuit(t *testing.T) {
g := NewGame(7, 0)
if err := g.ChooseTrump(0, Hearts); err != nil {
t.Fatal(err)
}
// حاکم (seat 0) شروع می‌کند. یک کارت از دستش بازی می‌کنیم.
lead := g.hands[0][0]
if err := g.PlayCard(0, lead); err != nil {
t.Fatal(err)
}
// بازیکن بعدی اگر کارت هم‌خال دارد باید همان را بزند.
next := g.Turn
if hasSuit(g.hands[next], lead.Suit) {
// یک کارت با خال متفاوت پیدا کن
for _, c := range g.hands[next] {
if c.Suit != lead.Suit {
if err := g.PlayCard(next, c); err != ErrMustFollow {
t.Fatalf("expected ErrMustFollow, got %v", err)
}
return
}
}
}
}
// playFullGame یک بازی کامل را با یک ربات ساده تا پایان پیش می‌برد و
// تمام نامتغیرها (invariants) را بررسی می‌کند.
func TestFullGamePlaysOut(t *testing.T) {
g := NewGame(7, FirstHakem())
for hand := 0; g.Phase != PhaseGameOver; hand++ {
if hand > 100 {
t.Fatal("too many hands; engine likely stuck")
}
// انتخاب حکم توسط حاکم
if g.Phase != PhaseChooseTrump {
t.Fatalf("expected choose_trump, got %s", g.Phase)
}
if err := g.ChooseTrump(g.Hakem, g.hands[g.Hakem][0].Suit); err != nil {
t.Fatal(err)
}
// بررسی: هر بازیکن دقیقاً ۱۳ کارت دارد
for s := 0; s < 4; s++ {
if g.HandCount(s) != 13 {
t.Fatalf("seat %d has %d cards after deal", s, g.HandCount(s))
}
}
// بازی دست‌ها تا پایان هَند
for g.Phase == PhasePlaying {
if g.TrickDone {
if err := g.CollectTrick(); err != nil {
t.Fatalf("collect trick: %v", err)
}
continue
}
seat := g.Turn
card := legalMove(g, seat)
if err := g.PlayCard(seat, card); err != nil {
t.Fatalf("play %s by seat %d: %v", card, seat, err)
}
}
// بعد از هَند: یا تمام شده یا hand_over
if g.Phase == PhaseHandOver {
r := g.LastResult
if r.Points < 1 || r.Points > 2 {
t.Fatalf("unexpected points %d", r.Points)
}
if err := g.NextHand(); err != nil {
t.Fatal(err)
}
}
}
// در پایان یک تیم باید به امتیاز هدف رسیده باشد
if g.Scores[0] < g.TargetScore && g.Scores[1] < g.TargetScore {
t.Fatalf("game over but no team reached target: %v", g.Scores)
}
t.Logf("final scores: %v", g.Scores)
}
// legalMove یک حرکت مجاز برای ربات انتخاب می‌کند (follow suit در صورت امکان).
func legalMove(g *Game, seat int) Card {
hand := g.hands[seat]
if g.leadSet {
for _, c := range hand {
if c.Suit == g.LeadSuit {
return c
}
}
}
return hand[0]
}