| """Balance floor regression: the greedy bot must keep the difficulty |
| gradient alive. Small seed counts — these guard against catastrophic |
| balance breaks, not 1% drift.""" |
|
|
| from balance.sim import simulate, standard_decks, winrate |
| from scrypt.data import load_content |
| from scrypt.engine.combat import Result |
|
|
|
|
| def test_simulator_is_deterministic(): |
| content = load_content() |
| deck = standard_decks(content)["vanilla"] |
| side = [content.card("bit")] * 10 |
| script = content.encounters["first_blood"]["script"] |
| a = simulate(deck, side, script, seed=11) |
| b = simulate(deck, side, script, seed=11) |
| assert a.result is b.result and a.turn == b.turn |
|
|
|
|
| def test_first_encounter_is_winnable_floor(): |
| content = load_content() |
| deck = standard_decks(content)["vanilla"] |
| r = winrate(content, deck, "first_blood", seeds=30) |
| assert r["winrate"] >= 0.7, f"first encounter too hard for the floor bot: {r}" |
| assert r["stall"] == 0, "fights must end" |
|
|
|
|
| def test_final_encounter_is_a_wall_for_the_floor_bot(): |
| content = load_content() |
| deck = standard_decks(content)["vanilla"] |
| r = winrate(content, deck, "scheduled_doom", seeds=30) |
| assert r["winrate"] <= 0.6, f"finale too easy: {r}" |
|
|
|
|
| def test_every_fight_terminates(): |
| content = load_content() |
| side = [content.card("bit")] * 10 |
| for deck in standard_decks(content).values(): |
| for enc in content.encounters.values(): |
| state = simulate(deck, side, enc["script"], seed=3) |
| assert state.result is not Result.UNDECIDED |
|
|