game/server/game_test_runner.go
2026-04-20 16:07:22 +08:00

461 lines
11 KiB
Go
Executable File

package main
import (
"fmt"
"math/rand"
"time"
)
// ========================
// 测试辅助结构
// ========================
type TestPlayer struct {
UserID string
Username string
Character string
HP, MaxHP int
Shield bool
Poisoned bool
PoisonSteps int
Curse bool
Revive bool
TimeBombTurns int
SkipTurn bool
RevealedCells map[int]string
MonkeyBananaCount int
ChickenItemCount int
HippoDeathImmune bool
}
type TestGrid struct {
Type string
ItemID string
Revealed bool
}
func NewTestPlayer(id, character string) *TestPlayer {
maxHP := 4
if character == "elephant" {
maxHP = 5
} else if character == "cat" {
maxHP = 3
}
return &TestPlayer{
UserID: id,
Username: "Player_" + id,
Character: character,
HP: maxHP,
MaxHP: maxHP,
RevealedCells: make(map[int]string),
}
}
// ========================
// 核心逻辑函数
// ========================
func testApplyDamage(target *TestPlayer, amount int) int {
if target.HP <= 0 {
return 0
}
if target.Shield {
target.Shield = false
return 0
}
if target.Character == "cat" {
amount = 1
target.Curse = false
} else if target.Curse {
amount *= 2
target.Curse = false
}
target.HP -= amount
if target.HP <= 0 {
if target.Revive {
target.Revive = false
target.HP = 1
} else if target.Character == "hippo" && !target.HippoDeathImmune {
if rand.Float32() < 0.55 {
target.HP = 1
target.HippoDeathImmune = true
}
}
}
if target.HP < 0 {
target.HP = 0
}
return amount
}
func testHealPlayer(p *TestPlayer, amount int) {
if p.HP < p.MaxHP {
p.HP += amount
if p.HP > p.MaxHP {
p.HP = p.MaxHP
}
}
}
// ========================
// 测试结果
// ========================
var passed, failed int
func assert(name string, condition bool, msg string) {
if !condition {
fmt.Printf(" ❌ %s: %s\n", name, msg)
failed++
} else {
passed++
}
}
// ========================
// 道具测试
// ========================
func TestMedkit() {
fmt.Println("\n📦 测试: 医疗包")
p := NewTestPlayer("1", "default")
p.HP = 2
p.Poisoned = true
p.PoisonSteps = 3
p.Poisoned = false
p.PoisonSteps = 0
testHealPlayer(p, 1)
assert("回复1血", p.HP == 3, fmt.Sprintf("期望HP=3, 实际HP=%d", p.HP))
assert("解除中毒", !p.Poisoned, "中毒状态未解除")
}
func TestBombTimer() {
fmt.Println("\n📦 测试: 定时炸弹")
// 普通玩家
p := NewTestPlayer("1", "default")
p.TimeBombTurns = 3
for i := 0; i < 3; i++ {
if p.TimeBombTurns > 0 {
p.TimeBombTurns--
if p.TimeBombTurns == 0 {
testApplyDamage(p, 2)
}
}
}
assert("3回合后扣2血", p.HP == 2, fmt.Sprintf("期望HP=2, 实际HP=%d", p.HP))
// 懒懒
p2 := NewTestPlayer("1", "sloth")
p2.TimeBombTurns = 3
for i := 0; i < 3; i++ {
if p2.TimeBombTurns > 0 {
p2.TimeBombTurns--
if p2.TimeBombTurns == 0 {
testApplyDamage(p2, 1) // 懒懒减伤
}
}
}
assert("懒懒伤害降为1", p2.HP == 3, fmt.Sprintf("期望HP=3, 实际HP=%d", p2.HP))
}
func TestPoison() {
fmt.Println("\n📦 测试: 毒药瓶")
p := NewTestPlayer("1", "default")
p.Poisoned = true
p.PoisonSteps = 0
for i := 0; i < 4; i++ {
if p.Poisoned {
p.PoisonSteps++
if p.PoisonSteps%2 == 0 {
testApplyDamage(p, 1)
}
}
}
assert("每2回合扣1血(4回合扣2)", p.HP == 2, fmt.Sprintf("期望HP=2, 实际HP=%d", p.HP))
}
func TestShield() {
fmt.Println("\n📦 测试: 护盾")
p := NewTestPlayer("1", "default")
p.Shield = true
testApplyDamage(p, 2)
assert("免疫1次伤害", p.HP == 4, fmt.Sprintf("期望HP=4, 实际HP=%d", p.HP))
assert("使用后消失", !p.Shield, "护盾应消失")
}
func TestSkip() {
fmt.Println("\n📦 测试: 好人卡")
p := NewTestPlayer("1", "default")
p.SkipTurn = true
p.Shield = true
assert("跳过回合", p.SkipTurn, "SkipTurn应为true")
assert("附带护盾", p.Shield, "应带护盾效果")
}
func TestKnife() {
fmt.Println("\n📦 测试: 飞刀")
target := NewTestPlayer("2", "default")
testApplyDamage(target, 1)
assert("随机敌人1伤害", target.HP == 3, fmt.Sprintf("期望HP=3, 实际HP=%d", target.HP))
// 老虎飞刀
t1 := NewTestPlayer("2", "default")
t2 := NewTestPlayer("3", "default")
testApplyDamage(t1, 2)
testApplyDamage(t2, 2)
assert("老虎全体2伤害", t1.HP == 2 && t2.HP == 2, fmt.Sprintf("期望2,2 实际%d,%d", t1.HP, t2.HP))
}
func TestRevive() {
fmt.Println("\n📦 测试: 复活甲")
p := NewTestPlayer("1", "default")
p.Revive = true
p.HP = 1
testApplyDamage(p, 5)
assert("免疫一次死亡保留1血", p.HP == 1, fmt.Sprintf("期望HP=1, 实际HP=%d", p.HP))
assert("使用后消失", !p.Revive, "复活甲应消失")
}
func TestLightning() {
fmt.Println("\n📦 测试: 闪电")
players := []*TestPlayer{NewTestPlayer("1", "default"), NewTestPlayer("2", "default")}
for _, p := range players {
testApplyDamage(p, 1)
}
assert("全体扣1血", players[0].HP == 3 && players[1].HP == 3, "所有玩家应扣1血")
}
func TestCurse() {
fmt.Println("\n📦 测试: 诅咒")
p := NewTestPlayer("1", "default")
p.Curse = true
testApplyDamage(p, 1)
assert("伤害翻倍", p.HP == 2, fmt.Sprintf("期望HP=2(4-1*2), 实际HP=%d", p.HP))
assert("触发后消失", !p.Curse, "诅咒应消失")
}
// ========================
// 角色测试
// ========================
func TestElephant() {
fmt.Println("\n🐘 测试: 大象")
p := NewTestPlayer("1", "elephant")
assert("HP=5", p.MaxHP == 5, fmt.Sprintf("期望MaxHP=5, 实际=%d", p.MaxHP))
// 模拟禁用道具逻辑
bannedItems := map[string]bool{"medkit": true, "skip": true, "revive": true}
for item := range bannedItems {
canUse := !(p.Character == "elephant" && bannedItems[item])
assert(fmt.Sprintf("禁用%s", item), !canUse, "应禁用该道具")
}
}
func TestCat() {
fmt.Println("\n🐱 测试: 猫咪")
p := NewTestPlayer("1", "cat")
assert("HP=3", p.MaxHP == 3, fmt.Sprintf("期望MaxHP=3, 实际=%d", p.MaxHP))
testApplyDamage(p, 5)
assert("伤害强制为1", p.HP == 2, fmt.Sprintf("期望HP=2, 实际HP=%d", p.HP))
p2 := NewTestPlayer("1", "cat")
p2.Curse = true
testApplyDamage(p2, 1)
assert("诅咒无效", p2.HP == 2, fmt.Sprintf("期望HP=2, 实际HP=%d", p2.HP))
}
func TestDog() {
fmt.Println("\n🐶 测试: 狗狗")
p := NewTestPlayer("1", "dog")
grid := []TestGrid{{Type: "bomb"}, {Type: "item", ItemID: "medkit"}}
idx := 0
cellType := grid[idx].Type
p.RevealedCells[idx] = cellType
assert("透视存入RevealedCells", p.RevealedCells[idx] == "bomb", "应存入bomb")
}
func TestMonkey() {
fmt.Println("\n🐒 测试: 猴子(吉吉国王)")
p := NewTestPlayer("1", "monkey")
p.HP = 2
for i := 0; i < 3; i++ {
if p.MonkeyBananaCount < 2 {
testHealPlayer(p, 1)
p.MonkeyBananaCount++
}
}
assert("香蕉最多2次", p.MonkeyBananaCount == 2, fmt.Sprintf("触发%d次", p.MonkeyBananaCount))
assert("回复2血", p.HP == 4, fmt.Sprintf("期望HP=4, 实际HP=%d", p.HP))
}
func TestChicken() {
fmt.Println("\n🐔 测试: 坤坤")
p := NewTestPlayer("1", "chicken")
for i := 0; i < 3; i++ {
if p.ChickenItemCount < 2 {
p.ChickenItemCount++
}
}
assert("道具触发最多2次", p.ChickenItemCount == 2, fmt.Sprintf("触发%d次", p.ChickenItemCount))
}
func TestSloth() {
fmt.Println("\n🦥 测试: 懒懒")
p := NewTestPlayer("1", "sloth")
canPoison := p.Character != "sloth"
assert("免疫毒药", !canPoison, "应免疫毒药")
dmg := 2
if p.Character == "sloth" {
dmg = 1
}
assert("炸弹伤害降为1", dmg == 1, fmt.Sprintf("伤害=%d", dmg))
}
func TestHippo() {
fmt.Println("\n🦛 测试: 河马")
p := NewTestPlayer("1", "hippo")
canPickup := p.Character != "hippo"
assert("无法拾取道具", !canPickup, "应无法拾取")
// 统计性测试
survived := 0
trials := 10000
for i := 0; i < trials; i++ {
testP := NewTestPlayer("1", "hippo")
testP.HP = 1
testApplyDamage(testP, 2)
if testP.HP > 0 {
survived++
}
}
rate := float64(survived) / float64(trials)
assert("55%免死概率", rate > 0.50 && rate < 0.60, fmt.Sprintf("实际=%.1f%%", rate*100))
}
func TestTiger() {
fmt.Println("\n🐯 测试: 老虎")
attacker := NewTestPlayer("1", "tiger")
dmg := 1
isAOE := false
if attacker.Character == "tiger" {
dmg = 2
isAOE = true
}
assert("飞刀变2伤害", dmg == 2, fmt.Sprintf("伤害=%d", dmg))
assert("变为全体攻击", isAOE, "应为AOE")
}
func TestMagnifier() {
fmt.Println("\n🔍 测试: 放大镜")
p := NewTestPlayer("1", "default")
grid := []TestGrid{
{Type: "empty"}, {Type: "bomb"}, {Type: "item", ItemID: "shield"},
}
// 模拟放大镜逻辑
idx := 2
cellType := grid[idx].Type
if grid[idx].Type == "item" {
cellType = grid[idx].ItemID
}
p.RevealedCells[idx] = cellType
assert("存入道具ID", p.RevealedCells[idx] == "shield", fmt.Sprintf("应为shield,实际=%s", p.RevealedCells[idx]))
}
// ========================
// 综合场景测试
// ========================
func TestComplexScenarios() {
fmt.Println("\n🎮 测试: 综合场景")
// 护盾+诅咒
p1 := NewTestPlayer("1", "default")
p1.Shield = true
p1.Curse = true
testApplyDamage(p1, 2)
assert("护盾优先于诅咒", p1.HP == 4 && p1.Curse, "护盾应先生效,诅咒保留")
// 复活甲+毒死
p2 := NewTestPlayer("1", "default")
p2.Revive = true
p2.Poisoned = true
p2.PoisonSteps = 1
testApplyDamage(p2, 5)
p2.PoisonSteps++
if p2.PoisonSteps%2 == 0 {
testApplyDamage(p2, 1)
}
assert("复活后被毒死", p2.HP == 0, fmt.Sprintf("期望HP=0, 实际=%d", p2.HP))
}
// ========================
// 主函数
// ========================
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println("╔═══════════════════════════════════════════╗")
fmt.Println("║ 🎮 动物扫雷 - 道具&角色逻辑测试 ║")
fmt.Println("╚═══════════════════════════════════════════╝")
// 道具测试
fmt.Println("\n━━━ 道具测试 ━━━")
TestMedkit()
TestBombTimer()
TestPoison()
TestShield()
TestSkip()
TestMagnifier()
TestKnife()
TestRevive()
TestLightning()
TestCurse()
// 角色测试
fmt.Println("\n━━━ 角色测试 ━━━")
TestElephant()
TestCat()
TestDog()
TestMonkey()
TestChicken()
TestSloth()
TestHippo()
TestTiger()
// 综合测试
fmt.Println("\n━━━ 综合场景 ━━━")
TestComplexScenarios()
// 结果
fmt.Println("\n╔═══════════════════════════════════════════╗")
total := passed + failed
if failed == 0 {
fmt.Printf("║ ✅ 全部通过! %d/%d 测试用例 ║\n", passed, total)
} else {
fmt.Printf("║ ⚠️ %d 通过, %d 失败 (共%d) ║\n", passed, failed, total)
}
fmt.Println("╚═══════════════════════════════════════════╝")
}