133 lines
4.6 KiB
Go
133 lines
4.6 KiB
Go
package ai
|
||
|
||
import (
|
||
"testing"
|
||
|
||
"nl-game-api-gin/internal/gamecore/ddz"
|
||
)
|
||
|
||
// card 按点数造一张牌(花色取 0-3 循环,保证同点数多张时编码不同)
|
||
// 点数 r:3-15(15=2),16=小王,17=大王
|
||
func card(r, i int) int {
|
||
if r == 16 {
|
||
return 52
|
||
}
|
||
if r == 17 {
|
||
return 53
|
||
}
|
||
return (r-3)*4 + i
|
||
}
|
||
|
||
// TestFarmerNotBeatPartner 平民不压队友:队友出的中等牌(J 以上)应选择过牌
|
||
func TestFarmerNotBeatPartner(t *testing.T) {
|
||
a := &ruleDdzAI{difficulty: DiffMedium, name: "测试"}
|
||
// 手牌里有 2(能压 J)但队友出的 J 不该压
|
||
hand := []int{card(15, 0), card(10, 0), card(5, 0), card(5, 1)}
|
||
last := ddz.Parse([]int{card(11, 0)}) // 队友出单张 J
|
||
pick, _ := a.DecidePlay(hand, last, PlayContext{
|
||
IsLandlord: false, LastIsPartner: true,
|
||
PartnerCards: 8, LandlordCards: 10, OppMin: 10,
|
||
})
|
||
if pick != nil {
|
||
t.Fatalf("平民不应压队友的大牌,却出了 %v", pick)
|
||
}
|
||
}
|
||
|
||
// TestFarmerBeatPartnerSmall 队友前期小牌可以用小牌接管,但不能动 2/王/炸弹
|
||
func TestFarmerBeatPartnerSmall(t *testing.T) {
|
||
a := &ruleDdzAI{difficulty: DiffMedium, name: "测试"}
|
||
hand := []int{card(15, 0), card(8, 0), card(6, 0), card(6, 1)}
|
||
last := ddz.Parse([]int{card(4, 0)}) // 队友出单张 4(早期小牌)
|
||
pick, _ := a.DecidePlay(hand, last, PlayContext{
|
||
IsLandlord: false, LastIsPartner: true,
|
||
PartnerCards: 10, LandlordCards: 12, OppMin: 12,
|
||
})
|
||
if pick == nil {
|
||
t.Fatal("队友的小牌应该用小牌接管节奏")
|
||
}
|
||
if c := ddz.Parse(pick); c.MainRank > 12 {
|
||
t.Fatalf("接队友的牌不应动大牌,却出了主点数 %d", c.MainRank)
|
||
}
|
||
}
|
||
|
||
// TestFarmerFinishOverridesCoop 能一手出完时即使是队友的牌也直接出完取胜
|
||
func TestFarmerFinishOverridesCoop(t *testing.T) {
|
||
a := &ruleDdzAI{difficulty: DiffMedium, name: "测试"}
|
||
hand := []int{card(14, 0)} // 只剩一张 A
|
||
last := ddz.Parse([]int{card(11, 0)}) // 队友出单张 J
|
||
pick, _ := a.DecidePlay(hand, last, PlayContext{
|
||
IsLandlord: false, LastIsPartner: true,
|
||
PartnerCards: 3, LandlordCards: 9, OppMin: 9,
|
||
})
|
||
if len(pick) != 1 {
|
||
t.Fatalf("能直接出完应立即取胜,实际出牌 %v", pick)
|
||
}
|
||
}
|
||
|
||
// TestFarmerFeedsPartnerSingle 队友只剩 1 张时,平民自由出牌应喂最小单张
|
||
func TestFarmerFeedsPartnerSingle(t *testing.T) {
|
||
a := &ruleDdzAI{difficulty: DiffMedium, name: "测试"}
|
||
hand := []int{card(15, 0), card(12, 0), card(12, 1), card(3, 0)}
|
||
pick, _ := a.DecidePlay(hand, nil, PlayContext{
|
||
IsLandlord: false, LastIsPartner: false,
|
||
PartnerCards: 1, LandlordCards: 8, OppMin: 8,
|
||
})
|
||
c := ddz.Parse(pick)
|
||
if c == nil || c.Type != ddz.ComboSingle {
|
||
t.Fatalf("队友剩 1 张应喂单张,实际 %v", pick)
|
||
}
|
||
if c.MainRank != 3 {
|
||
t.Fatalf("应喂最小单张 3,实际主点数 %d", c.MainRank)
|
||
}
|
||
}
|
||
|
||
// TestFarmerFeedsPartnerPair 队友只剩 2 张时优先喂最小对子
|
||
func TestFarmerFeedsPartnerPair(t *testing.T) {
|
||
a := &ruleDdzAI{difficulty: DiffMedium, name: "测试"}
|
||
hand := []int{card(15, 0), card(9, 0), card(9, 1), card(4, 0), card(4, 1)}
|
||
pick, _ := a.DecidePlay(hand, nil, PlayContext{
|
||
IsLandlord: false, LastIsPartner: false,
|
||
PartnerCards: 2, LandlordCards: 8, OppMin: 8,
|
||
})
|
||
c := ddz.Parse(pick)
|
||
if c == nil || c.Type != ddz.ComboPair {
|
||
t.Fatalf("队友剩 2 张应喂对子,实际 %v", pick)
|
||
}
|
||
if c.MainRank != 4 {
|
||
t.Fatalf("应喂最小对子 4,实际主点数 %d", c.MainRank)
|
||
}
|
||
}
|
||
|
||
// TestFarmerBlocksLandlordEndgame 地主只剩 1 张时,平民领出应避免送小单牌
|
||
func TestFarmerBlocksLandlordEndgame(t *testing.T) {
|
||
a := &ruleDdzAI{difficulty: DiffMedium, name: "测试"}
|
||
// 手牌:小单 3、对 7、大单 A
|
||
hand := []int{card(14, 0), card(7, 0), card(7, 1), card(3, 0)}
|
||
pick, _ := a.DecidePlay(hand, nil, PlayContext{
|
||
IsLandlord: false, LastIsPartner: false,
|
||
PartnerCards: 10, LandlordCards: 1, OppMin: 1,
|
||
})
|
||
c := ddz.Parse(pick)
|
||
if c == nil {
|
||
t.Fatal("应有出牌")
|
||
}
|
||
// 不应送出最小单张 3(地主最后一张很可能压过)
|
||
if c.Type == ddz.ComboSingle && c.MainRank == 3 {
|
||
t.Fatal("地主只剩 1 张时不应送最小单牌")
|
||
}
|
||
}
|
||
|
||
// TestLandlordUnchanged 地主视角:正常出能压住的最小牌,不受配合逻辑影响
|
||
func TestLandlordUnchanged(t *testing.T) {
|
||
a := &ruleDdzAI{difficulty: DiffMedium, name: "测试"}
|
||
hand := []int{card(15, 0), card(10, 0), card(6, 0)}
|
||
last := ddz.Parse([]int{card(5, 0)})
|
||
pick, _ := a.DecidePlay(hand, last, PlayContext{
|
||
IsLandlord: true, LandlordCards: 3, OppMin: 10,
|
||
})
|
||
c := ddz.Parse(pick)
|
||
if c == nil || c.MainRank != 6 {
|
||
t.Fatalf("地主应出能压住的最小牌 6,实际 %v", pick)
|
||
}
|
||
}
|