package game import ( "strings" "testing" ) // --- Tier 4 --- func countApplesIn(deck []Card) int { n := 0 for _, c := range deck { if c.Food == FoodApple { n++ } } return n } func TestSquirrelBuyAndSell(t *testing.T) { g, _, _ := testGame(t) p := current(g) g.ShopRow[0] = g.realPet(t, "Squirrel") if err := g.Buy(p.ID, 0); err != nil { t.Fatal(err) } if countApplesIn(p.Deck) != 2 { t.Fatalf("buying a Squirrel should add 2 apples, got %d", countApplesIn(p.Deck)) } // Sell it back on the next turn: 1 base + 2 extra = 3 more apples. if err := g.Buy(current(g).ID, 0); err != nil { // opponent spends a coin t.Fatal(err) } var squirrelID string for _, c := range p.Deck { if c.Name == "Squirrel" { squirrelID = c.ID } } if err := g.Sell(p.ID, []string{squirrelID}); err != nil { t.Fatal(err) } if countApplesIn(p.Deck) != 5 { t.Fatalf("selling a Squirrel should add 3 apples (1 base + 2 extra), got %d total", countApplesIn(p.Deck)) } } // Turtle's faint shields the next friendly hit completely. func TestTurtleShieldsNextFriendlyHit(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.realPet(t, "Turtle"), g.pet("Ally", 3)}, // turtle: 2 []Card{g.pet("Big", 5)}, ) // Turtle dies to the 5 (Big takes 2). Ally's first hit is fully // blocked; Ally hits back for 3: Big at 5 damage = dead. Ally wins // unscathed. shields := eventsOfType(res, "shield") if len(shields) != 1 || shields[0].Seat != 0 { t.Fatalf("expected one shield block for seat 0: %+v", shields) } clashes := eventsOfType(res, "clash") final := clashes[len(clashes)-1] if final.Damage[0] != 0 || !final.Died[1] { t.Fatalf("ally should take 0 damage while Big dies: %+v", final) } if res.WinnerSeat != 0 { t.Fatalf("seat 0 should win, got %d", res.WinnerSeat) } } // Pineapple is a perk that gives its pet "Play: throw 3 Rocks". func TestPineapplePerkThrowsRocks(t *testing.T) { g, _, _ := testGame(t) g.RollDie = func() int { return 1 } res := forceBattle(t, g, []Card{g.realFood(t, "Pineapple"), g.pet("Holder", 2)}, []Card{g.pet("Tank", 3)}, ) rocks := eventsOfType(res, "rock") if len(rocks) != 1 || rocks[0].Roll != 3 || !rocks[0].TargetDied { t.Fatalf("pineapple should throw 3 rocks and kill the 3-power tank: %+v", rocks) } if res.WinnerSeat != 0 { t.Fatalf("seat 0 should win, got %d", res.WinnerSeat) } } // Rooster summons a bee per apple it ate, capped at 3. func TestRoosterBeesPerEatenAppleCapped(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.newApple(), g.newApple(), g.newApple(), g.newApple(), g.realPet(t, "Rooster")}, // 4+4=8 []Card{g.pet("Colossus", 9)}, ) summons := eventsOfType(res, "summon") if len(summons) != 3 { t.Fatalf("rooster ate 4 apples but summons cap at 3 bees: %+v", summons) } for _, s := range summons { if s.Card.Name != "Bee" { t.Fatalf("rooster summons bees: %+v", s) } } // Colossus (9) takes 8 from rooster, dies to the first bee; seat 0 // still has bees to field and wins. if res.WinnerSeat != 0 { t.Fatalf("seat 0 should win, got %d", res.WinnerSeat) } } // Bison's Battle Prep needs a Triple this round. func TestBisonBattlePrepRequiresTriple(t *testing.T) { for _, tripled := range []bool{false, true} { g, p1, _ := testGame(t) p1.Deck = append(p1.Deck, g.realPet(t, "Bison")) if tripled { var ids []string for range 3 { c := g.pet("Fodder", 1) c.Suit = SuitBlue p1.Deck = append(p1.Deck, c) ids = append(ids, c.ID) } g.Turn = p1.Seat if err := g.TradeStart(p1.ID, ids); err != nil { t.Fatal(err) } if err := g.TradeChoose(p1.ID, 0); err != nil { t.Fatal(err) } } passShop(t, g) want := 0 if tripled { want = 3 } // Count only apples (the trade-chosen card may have added some via // its own Buy effect — exclude by counting before/after? Instead, // require at least; strict equality only in the no-trade case). got := countApplesIn(p1.Deck) if !tripled && got != want { t.Fatalf("no triple: bison should add no apples, got %d", got) } if tripled && got < want { t.Fatalf("tripled: bison should add 3 apples, got %d", got) } } } // Blowfish volleys 3 rocks at the enemy only when the next pet plays. func TestBlowfishDelayedRocksEnemyOnly(t *testing.T) { g, _, _ := testGame(t) g.RollDie = func() int { return 1 } res := forceBattle(t, g, []Card{g.realPet(t, "Blowfish"), g.pet("Next", 2)}, // blowfish: 3 []Card{g.pet("Tank", 6)}, ) // Blowfish dies (takes 6), Tank keeps 3 damage. Next plays → 3 rocks // at the enemy only: Tank at 6 damage = dead. Seat 0 wins; Next is // untouched. rocks := eventsOfType(res, "rock") if len(rocks) != 1 || rocks[0].Target != 1 || rocks[0].Roll != 3 { t.Fatalf("blowfish should volley the enemy only: %+v", rocks) } if res.WinnerSeat != 0 { t.Fatalf("seat 0 should win, got %d", res.WinnerSeat) } } // A fainting Blowfish is set aside as a card (with its own ID), then released // once the next pet plays and its volley resolves. func TestBlowfishSetAsideThenRelease(t *testing.T) { g, _, _ := testGame(t) g.RollDie = func() int { return 1 } blowfish := g.realPet(t, "Blowfish") res := forceBattle(t, g, []Card{blowfish, g.pet("Next", 2)}, []Card{g.pet("Tank", 6)}, ) setasides := eventsOfType(res, "setaside") if len(setasides) != 1 || setasides[0].Seat != 0 || setasides[0].Card == nil || setasides[0].Card.ID != blowfish.ID { t.Fatalf("blowfish should be set aside once for seat 0: %+v", setasides) } releases := eventsOfType(res, "release") if len(releases) != 1 || releases[0].Seat != 0 || releases[0].Card == nil || releases[0].Card.ID != blowfish.ID { t.Fatalf("blowfish should be released once for seat 0: %+v", releases) } // setaside on faint, then release after the volley: setaside precedes the // rock, which precedes the release. idx := func(typ string) int { for i, ev := range res.Events { if ev.Type == typ { return i } } return -1 } if !(idx("setaside") < idx("rock") && idx("rock") < idx("release")) { t.Fatalf("expected setaside < rock < release, got %d < %d < %d", idx("setaside"), idx("rock"), idx("release")) } } // Skunk strips the enemy pet's foods; a wounded veteran can faint from the // power loss. func TestSkunkStripCanKill(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.pet("Chip", 3), g.realPet(t, "Skunk")}, []Card{g.newApple(), g.newApple(), g.pet("Wall", 2)}, // 2+2 = 4 power ) // Chip (3) dies to Wall (4); Wall carries 3 damage (1 health). Skunk // plays and strips both apples: Wall drops to 2 power with 3 damage — // it faints on the spot, no clash needed. strips := eventsOfType(res, "strip") if len(strips) != 1 || strips[0].Target != 1 || !strips[0].TargetDied { t.Fatalf("strip should kill the buffed veteran: %+v", strips) } if len(eventsOfType(res, "clash")) != 1 { t.Fatal("only the first clash should happen") } if res.WinnerSeat != 0 { t.Fatalf("seat 0 should win, got %d", res.WinnerSeat) } } // Hippo heals 1 damage whenever an enemy pet faints. func TestHippoHealsOnEnemyFaint(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.realPet(t, "Hippo")}, // 4 power []Card{g.pet("Chip", 2), g.pet("Chip2", 2)}, ) heals := eventsOfType(res, "heal") if len(heals) != 2 { t.Fatalf("hippo should heal on each enemy faint: %+v", heals) } if heals[0].DamageAfter != 1 || heals[1].DamageAfter != 2 { t.Fatalf("hippo damage should go 2→1 then 3→2: %+v", heals) } if res.WinnerSeat != 0 { t.Fatalf("hippo should win, got %d", res.WinnerSeat) } } // --- Tier 5 --- // Monkey starts the battle with 3 apples attached to the first pet. func TestMonkeyApplesInPlay(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.pet("First", 2), g.realPet(t, "Monkey")}, // monkey: 3 []Card{g.pet("Enemy", 5)}, ) preps := eventsOfType(res, "prep") if len(preps) != 3 || preps[0].Seat != 0 { t.Fatalf("monkey should start 3 apples in play for seat 0: %+v", preps) } // First fights at 2+3=5 vs 5: both die. Monkey (3) then beats nothing — // enemy is out. Seat 0 wins. if res.WinnerSeat != 0 { t.Fatalf("seat 0 should win, got %d", res.WinnerSeat) } } // Rhino rocks every enemy pet as it's played. func TestRhinoRocksEnemyPlays(t *testing.T) { g, _, _ := testGame(t) g.RollDie = func() int { return 1 } res := forceBattle(t, g, []Card{g.realPet(t, "Rhino")}, // 5 power []Card{g.pet("A", 1), g.pet("B", 6)}, ) // A is played → rhino rocks it dead (1 damage ≥ 1 power) before any // clash. B is played → rocked for 1, then clashes: B (6, dmg 1) takes // 5 → dead at 6; rhino takes 6 → dead at 5. Both out: draw. rocks := eventsOfType(res, "rock") if len(rocks) != 2 || rocks[0].Seat != 0 || !rocks[0].TargetDied { t.Fatalf("rhino should rock each played enemy pet: %+v", rocks) } if res.WinnerSeat != -1 { t.Fatalf("expected draw, got %d", res.WinnerSeat) } } // Crocodile's set-aside fires when the enemy plays their last pet. func TestCrocodileLastPetRocks(t *testing.T) { g, _, _ := testGame(t) g.RollDie = func() int { return 1 } res := forceBattle(t, g, []Card{g.realPet(t, "Crocodile"), g.pet("Anchor", 9)}, // croc: 4 []Card{g.pet("Tank", 4), g.pet("Last", 4)}, ) // Croc and Tank (4v4) kill each other; croc sets aside. Anchor and // Last are played — Last is the enemy's last pet, so croc volleys 3 // rocks (3 damage): Last at 3 damage. Clash: Last dies (3+9), Anchor // takes 4. Seat 0 wins. rocks := eventsOfType(res, "rock") if len(rocks) != 1 || rocks[0].Target != 1 || rocks[0].Roll != 3 { t.Fatalf("crocodile should volley the enemy's last pet: %+v", rocks) } if res.WinnerSeat != 0 { t.Fatalf("seat 0 should win, got %d", res.WinnerSeat) } } // Scorpion KOs whatever its clash attack hurts — but a fully prevented // attack (Garlic on a 1-power hit) KOs nothing, and its rocks never KO. func TestScorpionKnockout(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.realPet(t, "Scorpion")}, // 1 power []Card{g.pet("Giant", 9)}, ) clash := eventsOfType(res, "clash")[0] if !clash.Died[1] { t.Fatalf("scorpion's hit should KO the giant: %+v", clash) } if !clash.Died[0] { t.Fatal("the giant's 9 attack still kills the scorpion") } if res.WinnerSeat != -1 { t.Fatalf("expected mutual destruction draw, got %d", res.WinnerSeat) } } func TestGarlicBlocksScorpionKO(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.realPet(t, "Scorpion")}, []Card{g.realFood(t, "Garlic"), g.pet("Guard", 9)}, ) // Scorpion's 1 attack is fully prevented by garlic: no hurt, no KO. clash := eventsOfType(res, "clash")[0] if clash.Died[1] { t.Fatalf("garlic should negate the scorpion's KO: %+v", clash) } if res.WinnerSeat != 1 { t.Fatalf("guard should win, got %d", res.WinnerSeat) } } // Seal only pays out if it carries a perk. func TestSealNeedsPerk(t *testing.T) { g, _, _ := testGame(t) // Without a perk: nothing. res := forceBattle(t, g, []Card{g.realPet(t, "Seal")}, []Card{g.pet("Enemy", 9)}, ) if len(eventsOfType(res, "summon")) != 0 { t.Fatal("seal without a perk should summon nothing") } // With honey attached: 3 apples onto the deck. g2, _, _ := testGame(t) res2 := forceBattle(t, g2, []Card{g2.newHoney(t), g2.realPet(t, "Seal"), g2.pet("Heir", 3)}, []Card{g2.pet("Enemy", 9)}, ) apples := 0 for _, s := range eventsOfType(res2, "summon") { if s.Card.Food == FoodApple && s.Seat == 0 { apples++ } } if apples != 3 { t.Fatalf("perked seal should push 3 apples onto its deck, got %d", apples) } } // Shark eats an apple per fainted friendly pet. func TestSharkEatsPerFaintedPet(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.pet("A", 1), g.pet("B", 1), g.realPet(t, "Shark")}, // shark: 1 []Card{g.pet("Wall", 3)}, ) // A and B faint chipping Wall to 2 damage (1 health). Shark plays with // 2 fainted friends → eats 2 → 3 power. Clash: Wall dies (3 more // damage), shark survives 3 damage? 3 damage vs 3 power = fainted too. eats := eventsOfType(res, "eat") if len(eats) != 1 || eats[0].Bonus != 2 { t.Fatalf("shark should eat 2 apples: %+v", eats) } if res.WinnerSeat != -1 { t.Fatalf("expected draw (both die in final clash), got %d", res.WinnerSeat) } } // Turkey's aura buffs later friendly bees. func TestTurkeyBuffsBees(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.realPet(t, "Turkey"), g.tier1(t, "Cricket")}, // turkey 4, cricket 1 []Card{g.pet("Wall", 6)}, ) // Turkey dies (Wall at 4 damage, 2 health), aura set. Cricket dies // (Wall at 5 damage, 1 health), summons its bee. The bee plays at // 1+1=2 power: kills Wall and survives with 6 damage? No — bee takes // 6, dies; Wall takes 2, dies at 7 ≥ 6. Draw... but the bee had 2 // power so Wall dies; bee dies too. Draw. if res.WinnerSeat != -1 { t.Fatalf("expected draw, got %d", res.WinnerSeat) } // Verify the aura actually applied: final clash damage on Wall is // 5+2=7 (a 1-power bee would leave it at 6 exactly = still dead...); // check damage total instead. clashes := eventsOfType(res, "clash") final := clashes[len(clashes)-1] if final.Damage[1] != 7 { t.Fatalf("buffed bee should hit for 2 (wall at 7 damage), got %d", final.Damage[1]) } } // Chili mills the enemy deck down to the next non-Bee pet. func TestChiliMillsEnemyDeck(t *testing.T) { g, _, _ := testGame(t) bee := g.newBee() res := forceBattle(t, g, []Card{g.realFood(t, "Chili"), g.pet("Holder", 3)}, []Card{g.pet("Front", 3), g.newApple(), bee, g.pet("Real", 3)}, ) // Holder (with chili) and Front play. Chili mills: apple, bee are // discarded; Real stays on top. Clash: Holder and Front trade (3v3, // both die). Real vs nothing — seat 1 wins. mills := eventsOfType(res, "mill") if len(mills) != 2 || mills[0].Seat != 1 { t.Fatalf("chili should mill exactly the apple and bee: %+v", mills) } if mills[0].Card.Food != FoodApple || !isBee(*mills[1].Card) { t.Fatalf("milled cards should be the apple then the bee: %+v", mills) } if res.WinnerSeat != 1 { t.Fatalf("seat 1's Real pet should carry the day, got %d", res.WinnerSeat) } } // --- Tier 6 --- // Gorilla is hurt only every other hit. func TestGorillaAlternatingShield(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.realPet(t, "Gorilla")}, // 6 power []Card{g.pet("A", 2), g.pet("B", 2), g.pet("C", 2)}, ) // Hit 1: takes 2 (damage 2), gains shield. Hit 2: blocked. Hit 3: // takes 2 (damage 4), gains shield. Gorilla kills all three. shields := eventsOfType(res, "shield") if len(shields) != 1 || shields[0].Seat != 0 { t.Fatalf("gorilla should block exactly the second hit: %+v", shields) } clashes := eventsOfType(res, "clash") if len(clashes) != 3 || clashes[2].Damage[0] != 4 { t.Fatalf("gorilla should end at 4 damage after 3 clashes: %+v", clashes) } if res.WinnerSeat != 0 { t.Fatalf("gorilla should win, got %d", res.WinnerSeat) } } // Melon blocks the first hit against its pet. func TestMelonBlocksFirstHit(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.realFood(t, "Melon"), g.pet("Holder", 3)}, []Card{g.pet("Big", 5)}, ) // Hit 1 blocked; holder hits Big for 3. Hit 2: holder takes 5, dies; // Big takes 3 more → 6 ≥ 5, dies. Draw. shields := eventsOfType(res, "shield") if len(shields) != 1 || shields[0].Seat != 0 { t.Fatalf("melon should block the first hit: %+v", shields) } if res.WinnerSeat != -1 { t.Fatalf("expected draw, got %d", res.WinnerSeat) } } // A used Melon names itself in the log and is released from the play area so // the fan clears. func TestMelonBlockNamesSourceAndClears(t *testing.T) { g, _, _ := testGame(t) melon := g.realFood(t, "Melon") res := forceBattle(t, g, []Card{melon, g.pet("Holder", 3)}, []Card{g.pet("Big", 5)}, ) shields := eventsOfType(res, "shield") if len(shields) != 1 || !strings.Contains(shields[0].Text, "Melon") || strings.Contains(shields[0].Text, "shield") { t.Fatalf("shield line should name the Melon, not say 'shield': %q", shields[0].Text) } releases := eventsOfType(res, "release") if len(releases) != 1 || releases[0].Card == nil || releases[0].Card.ID != melon.ID { t.Fatalf("the spent Melon should be released from the play area: %+v", releases) } } // With both a set-aside Turtle and a Melon protecting the same pet, the // borrowed Turtle shield is spent first so its card clears the board. func TestTurtleShieldSpentBeforeMelon(t *testing.T) { g, _, _ := testGame(t) turtle := g.realPet(t, "Turtle") // power 2 res := forceBattle(t, g, []Card{turtle, g.realFood(t, "Melon"), g.pet("Holder", 3)}, []Card{g.pet("Big", 5)}, ) // Turtle (2) dies to Big (5), setting aside a shield; Big keeps 2 damage. // Holder plays with Melon (own shield). The next hit is absorbed by the // Turtle set-aside first, releasing the Turtle; Holder then downs Big and // its Melon shield is never spent. releases := eventsOfType(res, "release") if len(releases) != 1 || releases[0].Card == nil || releases[0].Card.ID != turtle.ID { t.Fatalf("the Turtle shield should be spent (and released) before the Melon: %+v", releases) } shields := eventsOfType(res, "shield") if len(shields) != 1 || !strings.Contains(shields[0].Text, "Turtle") { t.Fatalf("the block should be credited to the Turtle: %+v", shields) } if res.WinnerSeat != 0 { t.Fatalf("seat 0 should win with the Melon still in reserve, got %d", res.WinnerSeat) } } // Leopard throws rocks equal to its power, apples included. func TestLeopardRocksEqualPower(t *testing.T) { g, _, _ := testGame(t) g.RollDie = func() int { return 1 } res := forceBattle(t, g, []Card{g.newApple(), g.newApple(), g.newApple(), g.realPet(t, "Leopard")}, // 4+3=7 []Card{g.pet("Fortress", 7)}, ) rocks := eventsOfType(res, "rock") if len(rocks) != 1 || rocks[0].Roll != 7 || !rocks[0].TargetDied { t.Fatalf("leopard should throw 7 rocks (7 damage) and level the fortress: %+v", rocks) } if res.WinnerSeat != 0 { t.Fatalf("seat 0 should win, got %d", res.WinnerSeat) } } // Mammoth's aura buffs all later friendly pets. func TestMammothBuffsPets(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.realPet(t, "Mammoth"), g.pet("Heir", 3)}, // mammoth: 4 []Card{g.pet("Wall", 8)}, ) // Mammoth dies (Wall at 4 damage). Heir plays at 3+1=4: dies to the 8, // but Wall ends at 8 damage ≥ 8 → dead too. Draw proves the +1. if res.WinnerSeat != -1 { t.Fatalf("expected draw (aura makes exactly lethal), got %d", res.WinnerSeat) } } // Cat doubles the apples in hand after adding two. func TestCatDoublesApples(t *testing.T) { g, _, _ := testGame(t) p := current(g) p.Deck = append(p.Deck, g.newApple()) // 1 apple already in hand g.ShopRow[0] = g.realPet(t, "Cat") if err := g.Buy(p.ID, 0); err != nil { t.Fatal(err) } // 1 existing + 2 added = 3, doubled = 6. if countApplesIn(p.Deck) != 6 { t.Fatalf("cat should leave 6 apples ((1+2)×2), got %d", countApplesIn(p.Deck)) } } // Snake volleys on EVERY friendly pet play. func TestSnakeRecurringRocks(t *testing.T) { g, _, _ := testGame(t) g.RollDie = func() int { return 1 } res := forceBattle(t, g, []Card{g.realPet(t, "Snake"), g.pet("A", 2), g.pet("B", 2)}, // snake: 2 []Card{g.pet("Wall", 9)}, ) // Snake dies. A plays → 2 rocks (2 damage) → Wall 2+2... sequence: // snake clash: wall 2 damage. A plays → rocks 2 → wall 4. Clash: A // dies, wall 6. B plays → rocks 2 → wall 8. Clash: B dies, wall 10 ≥ 9 // → dead. Both out → draw, with TWO rock volleys proving recurrence. rocks := eventsOfType(res, "rock") if len(rocks) != 2 { t.Fatalf("snake should volley on each friendly play: %+v", rocks) } // The set-aside Snake threw the rocks, not the pet (A/B) in play. for _, r := range rocks { if !strings.Contains(r.Text, "Snake") { t.Fatalf("rock event should credit Snake as the source, got %q", r.Text) } } if res.WinnerSeat != -1 { t.Fatalf("expected draw, got %d", res.WinnerSeat) } } // Wolverine steals up to 3 apples, which can faint a wounded victim. func TestWolverineStealsApples(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.pet("Chip", 4), g.realPet(t, "Wolverine")}, // wolverine: 5 []Card{g.newApple(), g.newApple(), g.newApple(), g.newApple(), g.pet("Hoard", 2)}, // 2+4=6 ) // Chip (4) dies to Hoard (6); Hoard carries 4 damage (2 health). // Wolverine plays, steals 3 apples: Hoard drops to 3 power with 4 // damage → faints. Wolverine ends at 5+3=8 power. steals := eventsOfType(res, "steal") if len(steals) != 1 || steals[0].Count != 3 || !steals[0].TargetDied { t.Fatalf("wolverine should steal 3 apples and kill the hoard: %+v", steals) } if res.WinnerSeat != 0 { t.Fatalf("seat 0 should win, got %d", res.WinnerSeat) } } // Fly summons three bees on faint. func TestFlySummonsThreeBees(t *testing.T) { g, _, _ := testGame(t) res := forceBattle(t, g, []Card{g.realPet(t, "Fly")}, // 4 power []Card{g.pet("Wall", 7)}, ) summons := eventsOfType(res, "summon") if len(summons) != 3 { t.Fatalf("fly should summon 3 bees: %+v", summons) } // Wall takes 4+1+1+1 = 7 → dies with the last bee. Draw. if res.WinnerSeat != -1 { t.Fatalf("expected draw, got %d", res.WinnerSeat) } }