Files
nl-game-api/internal/gamecore/ddz/game_test.go
2026-08-14 13:17:03 +08:00

117 lines
4.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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=%vstart=%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次× 42个炸弹× 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)
}
}