461 lines
11 KiB
Go
Executable File
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("╚═══════════════════════════════════════════╝")
|
|
}
|