117 lines
4.0 KiB
Go
117 lines
4.0 KiB
Go
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)
|
||
}
|
||
}
|