Skip to content

Instantly share code, notes, and snippets.

@morganrivers
Created July 10, 2025 17:01
Show Gist options
  • Select an option

  • Save morganrivers/4e7a780108fb52cea2e17ae269f60761 to your computer and use it in GitHub Desktop.

Select an option

Save morganrivers/4e7a780108fb52cea2e17ae269f60761 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
"""Wildfire Evacuation Game (CLI)
Two-phase family game for 2-5 players:
• Preparation phase – visit locations for resource cards (or speed through forNeighborly Token).
• Disaster phase – race along a 25-space path to the Safe Zone while avoiding Action card hazards.
Characters are secret and award end-game bonuses (+1 pt per specific resource and ×2 for another).
The first player to arrive receives +5 pts. Highest score wins.
Run directly: python wildfire_game.py
"""
from __future__ import annotations
import os
import random
from dataclasses import dataclass, field
from typing import Dict, List, Optional
# ────────────────────────────── CARD DATA ──────────────────────────────
LOCATIONS: Dict[str, List[tuple[str, int]]] = {
"Home": \
[("Emergency Blanket", 1)] * 3\
+ [("Important Documents", 2)] * 3\
+ [("Extra Clothes", 1)] * 3,\
"Grocery Store":\
[("Water Bottle", 1)] * 3 \
+ [("Extra Cash", 2)] * 2 \
+ [("Canned Food", 3)] * 3,\
"Pharmacy":\
[("N95 Respirator", 2)] * 2 \
+ [("First Aid Kit", 1)] * 3 \
+ [("1 Month of Medication", 3)] * 3,\
"Gas Station": \
[("Gas Canister", 1)] * 3 \
+ [("Flashlight", 2)] * 2 \
+ [("Spare Tire", 3)] * 1,\
"Electronics Store":\
[("Batteries", 2)] * 3 \
+ [("Hand Crank Radio", 3)] * 1 \
+ [("Power Bank", 1)] * 2
}
def print_prep_map(
p1, p2, p3, p4, p5,
g1, g2, g3, g4, g5,
a1, a2, a3, a4, a5,
h1, h2, h3, h4, h5,
e1, e2, e3, e4, e5,
y1, y2, y3, y4, y5
):
print(f"""
_______________
/{g4} {g2} {g1} {g3} {g5} \\
+-------------| Grocery Store |-------------+
| *---------------* |
| | |
___ ___|______ ______|______ ______|______
/{p4} {p2} {p1} {p3} {p5}\\ {y3} /{h4} {h2} {h1} {h3} {h5}\\ {y1} /{a4} {a2} {a1} {a3} {a5}\\
| Pharmacy |------| HOME |------| Gas Station |
*--------------* {y4} *--------------* {y2} *--------------*
| {y5} | |
| _________|__________ |
| / {e4} {e2} {e1} {e3} {e5} \\ |
+-----------| Electronics Store | ---------+
*--------------------*
""")
CHARACTER_CARDS = {
"Elderly": (\
"N95 Respirator",\
"First Aid Kit"), # x2 points for each of these
"Student": ("Water Bottle",\
"Batteries"), # x2 points for each of these
"Parent": ("Extra Clothes",\
"Extra Cash"), # x2 points for these
"Pet Owner": ("Emergency Blanket",\
"Canned Food"), # x2 points for these
"Community Leader": ("Hand Crank Radio",\
"Neighborly Token"), # x2 points for these
}
ACTION_CARDS = [
(1, "Flat Tire", "Skip next turn", "Spare Tire"),
(2, "Road Block", "Move only 1 space next turn", "Important Documents"),
(3, "Heavy Smoke", "Skip next turn", "N95 Respirator"),
(4, "Blackout", "Lose next turn’s die roll", "Flashlight"),
# (5, "Car Trouble", "Discard 1 resource card", "Power Bank"),
# (6, "Panic", "Trade 1 card if possible", "Blanket"),
(5, "Bad Directions", "Backtrack 4 spaces", "Hand Crank Radio"),
(6, "Dehydration", "Lose 5 points", "Water Bottle"),
(7, "Medical Emergency", "Skip 2 turns", "First Aid Kit"),
(8, "Food Spoilage", "Lose 5 points", "Canned Food"),
]
# ────────────── COMBO BONUSES ──────────────
COMBO_BONUSES = [
{
"name": "Portable Go-Kit Bonus",
"required": [
"Water Bottle",
"First Aid Kit",
"Canned Food",
],
"points": 3,
"description": (
" [A portable Go-Kit]\n"
" You should have this portable kit prepared plus a few more items to carry you through 3 days away from home.\n"
" Source: Red Cross"
),
},
{
"name": "Prepper Kit Bonus",
"required": [
"Water Bottle",
"First Aid Kit",
"Canned Food",
"Important Documents",
"1 Month of Medication",
],
"points": 6,
"description": (
" [A portable Go-Kit + More!]\n"
" Preparing a portable 3-day Go-Kit, plus 1 month of medication in a child-proof container and have important documents ready to go in an emergency.\n"
" Source: Red Cross "
),
},
# Add more combos here later!
]
# --- new board size ---
PATH_LENGTH = 15 # squares 0-14; Safe Zone is index 15
SAFE_ZONE_INDEX = PATH_LENGTH # unchanged code that uses this still works
# Action (“red”) squares – cluster near the end
RED_SPACES = {4, 8, 10, 12, 13}
# Shortcuts (optional) – adjust to fit the shorter path
SHORTCUT_SPACES = {5, 9}
NT_BONUS = 3
COMMUNITY_LEADER_NT_BONUS = 4
RESOURCE_POINTS = 2
SAFE_ZONE_POINTS = 5
# ─────────────────────────────── DATA CLASSES ───────────────────────────────
@dataclass
class ResourceCard:
name: str
points: int
origin: str
@dataclass
class CharacterCard:
name: str
plus_resource: str
multiplier_resource: str # or "Neighborly Token" for Community Leader
@dataclass
class Player:
name: str
character: CharacterCard
inventory: List[ResourceCard] = field(default_factory=list)
tokens: int = 0
position: int = 0 # path index during disaster phase
skipped_turns: int = 0
one_space_only: bool = False
reached_safe_zone: bool = False
bonus_points: int = 0
last_location: str = "(none)" # add this field
# ── inventory helpers ──
def add_card(self, card: ResourceCard):
self.inventory.append(card)
def has_card(self, name: str) -> bool:
return any(c.name == name for c in self.inventory)
def remove_any(self, name: Optional[str] = None, value: Optional[int] = None) -> bool:
"""Try to pop a card matching criteria; return True if removed."""
for idx, c in enumerate(self.inventory):
if (name is None or c.name == name) and (value is None or c.points == value):
self.inventory.pop(idx)
return True
return False
# ── scoring ──
def total_points(self) -> int:
pts = sum(c.points for c in self.inventory)
# +1 per matching resource
pts += sum(RESOURCE_POINTS for c in self.inventory if c.name == self.character.plus_resource)
# ×2 multiplier for matching resource (add its points again)
if self.character.multiplier_resource != "Neighborly Token":
pts += sum(c.points for c in self.inventory if c.name == self.character.multiplier_resource)
# Neighborly Tokens
token_value = COMMUNITY_LEADER_NT_BONUS if self.character.name == "Community Leader" else NT_BONUS
pts += self.tokens * token_value
# arrival bonus
pts += self.bonus_points
# combo bonuses!
pts += self.combo_bonus_points()
return pts
def get_combo_bonuses(self) -> List[str]:
"""Returns the single highest-value combo bonus achieved by this player."""
inventory_names = [card.name for card in self.inventory]
# Sort combos by points descending
for combo in sorted(COMBO_BONUSES, key=lambda c: c["points"], reverse=True):
if all(req in inventory_names for req in combo["required"]):
return [combo["name"]]
return []
def combo_bonus_points(self) -> int:
inventory_names = [card.name for card in self.inventory]
for combo in sorted(COMBO_BONUSES, key=lambda c: c["points"], reverse=True):
if all(req in inventory_names for req in combo["required"]):
return combo["points"]
return 0
# ── display helpers ──
def secret_label(self) -> str:
return f"{self.name} (Character card is secret)"
def reveal(self) -> str:
return (
f"{self.name} – {self.character.name} | Tokens:{self.tokens} | Score: {self.total_points()}"
)
# ──────────────────────────────── GAME CLASS ────────────────────────────────
class WildfireGame:
"""Top-level game controller."""
def __init__(self, players: List[Player]):
self.players = players
self.phase = "prep"
self.prep_round = 1
self.rng = random.Random()
# build location decks
self.location_decks: Dict[str, List[ResourceCard]] = {
loc: [ResourceCard(n, pts, loc) for n, pts in cards] for loc, cards in LOCATIONS.items()
}
for deck in self.location_decks.values():
self.rng.shuffle(deck)
# --- Give everyone 2 random starting resources ---
for pl in self.players:
for _ in range(2):
loc = self.rng.choice(list(self.location_decks))
if self.location_decks[loc]:
pl.add_card(self.location_decks[loc].pop())
# action card deck
self.action_deck = ACTION_CARDS.copy()
self.rng.shuffle(self.action_deck)
self.first_to_safe_zone: Optional[Player] = None
# ───────────────────── TRADING PHASE ─────────────────────
def trading_phase(self) -> None:
print("\n=== Optional Trading Phase ===")
active = [p for p in self.players if not p.reached_safe_zone and p.inventory]
for p in active:
if input(f"{p.name}, start a trade? (y/N): ").strip().lower() != "y":
continue
partners = [pl for pl in active if pl is not p]
if not partners:
print("No partners available.")
continue
partner_name = input(f"Pick partner {', '.join(pl.name for pl in partners)}: ").strip()
partner = next((pl for pl in partners if pl.name == partner_name), None)
if not partner:
print("Bad choice – aborted.")
continue
print(f"{p.name}'s cards: {[c.name for c in p.inventory]}")
give = input("Card to give: ").strip()
print(f"{partner.name}'s cards: {[c.name for c in partner.inventory]}")
take = input("Card to receive: ").strip()
if not p.has_card(give) or not partner.has_card(take):
print("Trade failed – card not owned.")
continue
# execute swap
card_give = next(c for c in p.inventory if c.name == give)
card_take = next(c for c in partner.inventory if c.name == take)
p.inventory.remove(card_give)
partner.inventory.remove(card_take)
p.inventory.append(card_take)
partner.inventory.append(card_give)
# # reward tokens
# p.tokens += 1
# partner.tokens += 1
print("Trade successful – Always check with neighbors to ensure they’re also prepared! [Source: CAL FIRE]")
# # ── simple ASCII map of a 15-square serpentine path ──
# def draw_path(self) -> None:
# cells = [f"{i:02}" for i in range(PATH_LENGTH)] # 00–14
# for p in self.players:
# if p.reached_safe_zone:
# continue
# mark = p.name[0].upper()
# cells[p.position] = mark * 2 # overwrite number
# # 3 rows × 5 columns, serpentine
# rows = []
# for r in range(2, -1, -1): # bottom row is index 0
# row = cells[r * 5:(r + 1) * 5]
# if (2 - r) % 2: # reverse every other row
# row.reverse()
# rows.append(" ".join(row))
# print("\nBelow: letter pairs are players first initials repeated twice, to show their position.")
# print("\nSZ == Safe Zone.")
# print("\nEvacuation Route (0-14 → SZ):")
# for line in rows:
# print(line)
# print("SZ = Safe Zone (index 15)\n")
def draw_path(self) -> None:
# Board positions
board = [f"{i:02}" for i in range(PATH_LENGTH)] + ["SZ"]
# Shortcut markers (above)
shortcut_row = []
for i in range(PATH_LENGTH):
if i in SHORTCUT_SPACES:
shortcut_row.append("SC")
else:
shortcut_row.append(" ")
shortcut_row.append(" ") # No shortcut in SZ
print("\nShortcuts: SC means you can gamble for a jump ahead.\n" +
" ".join(shortcut_row))
# Number row
print("Spaces: " + " ".join(board))
# Action squares row
action_row = ["XX" if i in RED_SPACES else " " for i in range(PATH_LENGTH)] + [" "]
print("Action Squares:" + " ".join(action_row))
# Player rows
for p in self.players:
if p.reached_safe_zone:
pos = PATH_LENGTH # SZ
else:
pos = p.position
row = [" " for _ in board]
initials = (p.name[0] * 2).upper()
row[pos] = initials
print(f"{p.name[:10]:10} :" + " ".join(row))
print(f"\nSZ = Safe Zone (index 15). +{SAFE_ZONE_POINTS} to reach the safe zone first!")
# ────────────────────────── TERMINAL HELPERS ──────────────────────────
@staticmethod
def clear():
os.system("cls" if os.name == "nt" else "clear")
# ────────────────────────────── PHASES ──────────────────────────────
def run(self):
self.clear()
print("=== Wildfire Ready-Set-Go ===\n")
print("BONUS COMBOS available this game:")
for combo in COMBO_BONUSES:
print(f" - {combo['name']} (+{combo['points']} pts):")
print(f" Needs: {', '.join(combo['required'])}")
print(f"{combo['description']}\n")
print()
self.preparation_phase()
self.disaster_phase()
self.final_scoring()
# ─────────────────── PREPARATION PHASE ───────────────────
def preparation_phase(self):
while self.phase == "prep":
for p in self.players:
self.take_prep_turn(p)
if self.prep_round > 3:
if self.roll_disaster_die():
print("The wildfire sparks early! Everyone evacuate!\n")
self.phase = "disaster"
break
if self.phase == "disaster":
break
if self.prep_round >= 7:
print("Seven rounds complete – the fire front arrives. Evacuate!\n")
self.phase = "disaster"
break
self.prep_round += 1
def take_prep_turn(self, player: Player):
# self.clear()
# print("Players' Inventories and Tokens:")
# for pl in self.players:
# cards = ", ".join(c.name for c in pl.inventory) or "(none)"
# print(f" {pl.name}: {cards} | Tokens: {pl.tokens}")
# print("-" * 40)
self.clear()
# ── compact prep-phase player map ──
initials = [(pl.name[0] * 2).upper() for pl in self.players]
initials += [" "] * (5 - len(initials)) # pad out to 5 slots
# --- Build minimap arguments by location for up to 5 players ---
def initials(player):
return (player.name[0]*2).upper()
def by_location(locname):
# Get up to 5 initials of players at this loc
lst = [initials(pl) if getattr(pl, "last_location", None) == locname else None for pl in self.players]
# filter to those at loc, keep order, pad with ' '
result = [i for i in lst if i]
result += [" "] * (5 - len(result))
return result[:5]
pharmacy = by_location("Pharmacy")
grocery = by_location("Grocery Store")
gas = by_location("Gas Station")
home = by_location("Home")
elec = by_location("Electronics Store")
yard = by_location("Yard")
# Unpack as 25 arguments (order: p1..p5,g1..g5,a1..a5,h1..h5,e1..e5)
print_prep_map(
*pharmacy,
*grocery,
*gas,
*home,
*elec,
*yard,
)
print(f"Preparation Round {self.prep_round}/7 – {player.secret_label()}")
print()
print("Players' Inventories, Tokens, Locations, and Profiles:")
for pl in self.players:
cards = ", ".join(c.name for c in pl.inventory) or "(none)"
location = getattr(pl, "last_location", "(none)")
char = pl.character
profile = (
f"{char.name}: +1/{char.plus_resource}, "
f"x2/{char.multiplier_resource}"
)
print(f" {pl.name}: {cards} | Tokens: {pl.tokens} | Location: {location} | Profile: {profile}")
print()
print("\n--- Combo Bonuses Available This Game ---")
for combo in COMBO_BONUSES:
print(f" - {combo['name']}: {combo['points']} pts")
print(f" Needs: {', '.join(combo['required'])}")
print(f"{combo['description']}\n")
print("--- Neighborly Token ---")
print(f" The Neighborly Token lets you leave sooner (+5 spaces ahead in disaster). It's also worth {NT_BONUS} points at the end of the game.")
print()
print("--- Items Typically Available at Each Location (if not sold out)---")
for loc, items in LOCATIONS.items():
items_list = [name for name, _ in items]
unique_items = sorted(set(items_list), key=items_list.index) # preserve order, unique
loc_pad = 25
print(f"{loc+':': <{loc_pad}} {', '.join(unique_items)}\n", end="")
# print(f"{loc})
# print("-" * 40)
print()
print("Tokens:", player.tokens)
print("Inventory:", ", ".join(c.name for c in player.inventory) or "(none)")
# choice: fast path (token) or visit location
print(f"\nChoose an action (each resource will be worth {RESOURCE_POINTS} points at end of game):")
print(" 0 – Create a defensible space by clearing flammable vegetation near your home (earn 1 Neighborly Token)")
for idx, loc in enumerate(LOCATIONS.keys(), 1):
print(f" {idx} – Go to {loc} ({len(self.location_decks[loc])} cards left)")
choice = input("Your selection: ").strip()
if choice == "0":
player.tokens += 1
print("You reduced your fire hazard, earn a Neighborly Token.")
player.last_location = "Yard"
elif choice.isdigit() and 1 <= int(choice) <= len(LOCATIONS):
loc = list(LOCATIONS.keys())[int(choice) - 1]
deck = self.location_decks[loc]
player.last_location = loc
if deck:
card = deck.pop()
player.add_card(card)
print(f"You drew: {card.name} (worth {card.points} pts)")
else:
print("No cards left at this location – you lose the turn.")
else:
print("Invalid choice – you lose the turn.")
input("Press Enter to end your turn…")
def roll_disaster_die(self) -> bool:
"""Return True if a 6 is rolled (disaster triggers)."""
result = self.rng.randint(1, 6)
print(f"Disaster die rolled a {result}.")
return result == 6
# ───────────────────── DISASTER PHASE ─────────────────────
def disaster_phase(self):
self.clear()
print("=== Disaster Phase – Evacuate! ===")
# everyone starts at path index 0
for p in self.players:
p.position = 0
turn_counter = 1
while not self.first_to_safe_zone:
for p in self.players:
self.take_disaster_turn(p, turn_counter)
if self.first_to_safe_zone:
break
# Only allow trading if game is still in progress
if not self.first_to_safe_zone:
self.trading_phase()
turn_counter += 1
while not self.first_to_safe_zone:
for p in self.players:
self.take_disaster_turn(p, turn_counter)
if self.first_to_safe_zone:
break
self.trading_phase() # ← add this line
turn_counter += 1
def take_disaster_turn(self, player: Player, turn_no: int):
self.clear()
self.draw_path() # ← add this line
print("Players' Inventories and Tokens:")
for pl in self.players:
cards = ", ".join(c.name for c in pl.inventory) or "(none)"
pos = f" | Pos: {pl.position}" if self.phase == "disaster" else ""
print(f" {pl.name}: {cards} | Tokens: {pl.tokens}{pos}")
print("-" * 40)
print()
print(f"Disaster Turn {turn_no} – {player.name}")
print(f"Position: {player.position}/24 | Tokens:{player.tokens} | Skips:{player.skipped_turns}")
print("\n--- Action Cards Reference ---")
for (num, title, effect, blocker) in ACTION_CARDS:
if blocker:
print(f"{title}: {effect} (Prevent with {blocker})")
else:
print(f"{title}: {effect}")
print("-" * 40)
if player.reached_safe_zone:
input("Already safe – press Enter…")
return
if player.skipped_turns > 0:
player.skipped_turns -= 1
print("You are delayed and lose this turn.")
input("Press Enter…")
return
# roll movement die
if player.one_space_only:
move = 1
player.one_space_only = False
print("Road Block – you may move only 1 space this turn.")
else:
move = 2*self.rng.randint(1, 3)
print(f"You rolled a {move}.")
# optional token spend
if player.tokens and not player.reached_safe_zone:
spend = input("Spend a token to move +5 spaces (y/N)? ").strip().lower()
if spend == "y":
player.tokens -= 1
move += 5
print("Token spent! +5 movement.")
# move along path
new_pos = min(player.position + move, SAFE_ZONE_INDEX)
print(f"You advance to space {new_pos}.")
player.position = new_pos
# check shortcut gamble
if player.position in SHORTCUT_SPACES and not player.reached_safe_zone:
gamble = input("You found a shortcut! Gamble? 1-4=fail(+skip), 5-6=skip ahead 3 (y/N): ").strip().lower()
if gamble == "y":
roll = self.rng.randint(1, 6)
print("Roll:", roll)
if roll >= 5:
player.position = min(player.position + 3, SAFE_ZONE_INDEX)
print("Success! You jump ahead.")
else:
player.skipped_turns = 1
print("Failed – you lose next turn.")
# check red space
if player.position in RED_SPACES and not player.reached_safe_zone:
self.resolve_action_card(player)
# check safe zone
if player.position >= SAFE_ZONE_INDEX:
player.reached_safe_zone = True
if not self.first_to_safe_zone:
self.first_to_safe_zone = player
player.bonus_points += 5
print(f"Congratulations – you reached the Safe Zone first (+{SAFE_ZONE_POINTS} pts)!")
else:
print("You made it to the Safe Zone – well done.")
# # --- show what each square represents ---
# print("\nBoard Squares Legend:")
# for idx in range(PATH_LENGTH):
# label = "ACTION" if idx in RED_SPACES else "empty"
# print(f"{idx:02}: {label}")
# print("-" * 40)
input("Press Enter to pass play…")
# ───────────────────── ACTION CARDS ─────────────────────
def draw_action_card(self):
if not self.action_deck:
self.action_deck.extend(ACTION_CARDS)
self.rng.shuffle(self.action_deck)
return self.action_deck.pop()
def resolve_action_card(self, player: Player):
card_id, title, penalty, blocker = self.draw_action_card()
print(f"‼️ ACTION CARD – {title}: {penalty}")
# prevention?
if blocker and player.has_card(blocker):
use = input(f"Use {blocker} to avoid the penalty (y/N)? ").strip().lower()
if use == "y":
print("Penalty avoided.")
return
# apply penalty
if title == "Flat Tire":
player.skipped_turns += 1
print("You will skip your next turn.")
elif title == "Road Block":
player.one_space_only = True
print("Next turn you may move only 1 space.")
elif title == "Heavy Smoke":
player.skipped_turns += 1
elif title == "Blackout":
player.skipped_turns += 1
elif title == "Car Trouble":
if player.inventory:
player.inventory.pop()
print("You discarded a random resource.")
else:
print("No resources to discard.")
# elif title == "Panic":
# others = [pl for pl in self.players if pl is not player and pl.inventory]
# if others and player.inventory:
# target = self.rng.choice(others)
# card_give = player.inventory.pop()
# card_take = target.inventory.pop()
# player.inventory.append(card_take)
# target.inventory.append(card_give)
# player.tokens += 1
# target.tokens += 1
# print(f"You traded with {target.name} and both earned a token.")
# else:
# print("Trade impossible – no effect.")
elif title == "Bad Directions":
player.position = max(0, player.position - 4)
print("You move back 4 spaces.")
elif title == "Dehydration":
player.bonus_points -= 5
print("You lose 5 points.")
elif title == "Medical Emergency":
player.skipped_turns += 2
elif title == "Food Spoilage":
# removed = player.remove_any(value=2)
# print("Food item discarded." if removed else "No 2-pt food to spoil.")
player.bonus_points -= 5
print("You lose 5 points.")
else:
print("Unknown penalty – none applied.")
# ───────────────────── FINAL SCORING ─────────────────────
def final_scoring(self):
self.clear()
print("=== Final Scores ===\n")
ranked = sorted(self.players, key=lambda p: p.total_points(), reverse=True)
for p in ranked:
print(p.reveal())
combos = p.get_combo_bonuses()
if combos:
print(f" Combo Bonuses: {', '.join(combos)} (+{p.combo_bonus_points()} pts)")
winner = ranked[0]
print(f"\nWinner: {winner.name} with {winner.total_points()} pts!")
# ────────────────────────────── UTILITIES ──────────────────────────────
def choose_players() -> List[Player]:
num = 0
while num not in range(2, 6):
try:
num = int(input("How many players (2-5)? "))
except ValueError:
pass
names = []
for i in range(1, num + 1):
name = input(f"Name for player {i}: ").strip() or f"Player{i}"
names.append(name)
rng = random.Random()
character_pool = list(CHARACTER_CARDS.items())
rng.shuffle(character_pool)
players: List[Player] = []
for name in names:
char_name, (plus, mult) = character_pool.pop()
character = CharacterCard(char_name, plus, mult)
players.append(Player(name=name, character=character))
# secretly tell the player their character card
os.system("cls" if os.name == "nt" else "clear")
print(f"{name}, your secret character is: {char_name}\n")
print(f" +1 pt for each {plus}")
if mult == "Neighborly Token":
print(f" Neighborly Tokens are worth {COMMUNITY_LEADER_NT_BONUS} pts each instead of {NT_BONUS}.")
else:
print(f" ×2 points for each {mult}")
input("Memorise this and press Enter (others look away)…")
os.system("cls" if os.name == "nt" else "clear")
return players
# ──────────────────────────────── MAIN ────────────────────────────────
if __name__ == "__main__":
players = choose_players()
game = WildfireGame(players)
game.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment