init
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
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]
|
||||
}
|
||||
Reference in New Issue
Block a user