package ddz import "testing" // TestBidRobFlow 叫地主 → 抢地主 → 确定地主的完整流程与倍数计算 func TestBidRobFlow(t *testing.T) { g := NewGame() g.Turn = 0 g.BidStart = 0 // 座位 0 叫地主 → 进入抢地主,轮到座位 1 if _, err := g.Bid(0, true); err != nil { t.Fatal(err) } if g.Phase != PhaseRobbing || g.Turn != 1 || g.Landlord != 0 || g.Multiplier != 1 { t.Fatalf("叫地主后状态异常:phase=%s turn=%d landlord=%d mult=%d", g.Phase, g.Turn, g.Landlord, g.Multiplier) } // 座位 1 抢地主 → 地主候选换成 1,倍数×2,轮到座位 2 if err := g.Rob(1, true); err != nil { t.Fatal(err) } if g.Landlord != 1 || g.Multiplier != 2 || g.Turn != 2 { t.Fatalf("抢地主后状态异常:landlord=%d mult=%d turn=%d", g.Landlord, g.Multiplier, g.Turn) } // 座位 2 不抢 → 地主确定为 1,底牌并入(20张),进入出牌阶段 if err := g.Rob(2, false); err != nil { t.Fatal(err) } if g.Phase != PhasePlaying || g.Landlord != 1 || g.Turn != 1 { t.Fatalf("抢地主结束后状态异常:phase=%s landlord=%d turn=%d", g.Phase, g.Landlord, g.Turn) } if len(g.Hands[1]) != 20 { t.Fatalf("地主应有 20 张手牌,实际 %d", len(g.Hands[1])) } } // TestRobNonePass 两家都不抢:首叫者当地主,倍数不变 func TestRobNonePass(t *testing.T) { g := NewGame() g.Turn = 2 g.BidStart = 2 g.Bid(2, true) if g.Turn != 0 { t.Fatalf("抢地主应从下家开始,实际 turn=%d", g.Turn) } g.Rob(0, false) if g.Turn != 1 { t.Fatalf("第二位抢地主表态者应为座位 1,实际 %d", g.Turn) } g.Rob(1, false) if g.Phase != PhasePlaying || g.Landlord != 2 || g.Multiplier != 1 { t.Fatalf("两家不抢后状态异常:phase=%s landlord=%d mult=%d", g.Phase, g.Landlord, g.Multiplier) } } // TestRedealWhenAllPass 三家都不叫应重新发牌 func TestRedealWhenAllPass(t *testing.T) { g := NewGame() start := g.Turn for i := 0; i < 2; i++ { redeal, err := g.Bid(g.Turn, false) if err != nil || redeal { t.Fatalf("前两家不叫不应触发重发:redeal=%v err=%v", redeal, err) } } redeal, err := g.Bid(g.Turn, false) if err != nil || !redeal { t.Fatalf("三家都不叫应返回重发:redeal=%v err=%v(start=%d)", redeal, err, start) } } // TestSpringMultiplier 春天与反春的判定 func TestSpringMultiplier(t *testing.T) { // 春天:地主赢且农民从未出过牌 g := &Game{Landlord: 0, Winner: 0, Phase: PhaseOver, Multiplier: 1} g.History = []PlayEvent{ {Seat: 0, Cards: []int{1}}, {Seat: 1}, {Seat: 2}, {Seat: 0, Cards: []int{2}}, {Seat: 1}, {Seat: 2}, } if g.SpringMultiplier() != 2 { t.Fatalf("地主全程压制应判春天 ×2,实际 %d", g.SpringMultiplier()) } // 反春:农民赢且地主只出过第一手 g2 := &Game{Landlord: 0, Winner: 1, Phase: PhaseOver, Multiplier: 1} g2.History = []PlayEvent{ {Seat: 0, Cards: []int{1}}, {Seat: 1, Cards: []int{2}}, {Seat: 2}, {Seat: 1, Cards: []int{3}}, } if g2.SpringMultiplier() != 2 { t.Fatalf("地主只出一手被打完应判反春 ×2,实际 %d", g2.SpringMultiplier()) } // 普通局:双方都出过多手 g3 := &Game{Landlord: 0, Winner: 1, Phase: PhaseOver, Multiplier: 1} g3.History = []PlayEvent{ {Seat: 0, Cards: []int{1}}, {Seat: 1, Cards: []int{2}}, {Seat: 0, Cards: []int{3}}, {Seat: 1, Cards: []int{4}}, } if g3.SpringMultiplier() != 1 { t.Fatalf("普通局春天倍数应为 1,实际 %d", g3.SpringMultiplier()) } } // TestTotalMultiplier 结算总倍数 = 叫抢 × 炸弹 × 春天(含上限) func TestTotalMultiplier(t *testing.T) { g := &Game{Landlord: 0, Winner: 0, Phase: PhaseOver, Multiplier: 2, Bombs: 2} g.History = []PlayEvent{{Seat: 0, Cards: []int{1}}, {Seat: 1, Cards: []int{2}}} // 2(抢1次)× 4(2个炸弹)× 1(无春天)= 8 if got := g.TotalMultiplier(); got != 8 { t.Fatalf("总倍数应为 8,实际 %d", got) } // 上限保护:巨量炸弹也不超过 64 g.Bombs = 10 if got := g.TotalMultiplier(); got != 64 { t.Fatalf("总倍数应封顶 64,实际 %d", got) } }