MCPcopy Create free account
hub / github.com/CodeClash-ai/CodeClash / discover_games

Function discover_games

codeclash/replay/base.py:114–169  ·  view source on GitHub ↗

Find every playable game under a tournament folder. Handles three layouts: ``rounds/round_ .tar.gz`` archives (the common case), uncompressed ``rounds/ /sim_*`` directories, and a flat folder of sim files (e.g. an ad-hoc sample with a single ``sim.json``).

(folder: Path, sim_glob: str)

Source from the content-addressed store, hash-verified

112 ``round_1`` -> 1), else 0. ``discover_games`` de-duplicates any collisions within a round."""
113 nums = re.findall(r"\d+", name.rsplit(".", 1)[0])
114 return int(nums[-1]) if nums else 0
115
116
117def _round_num(name: str) -> int:
118 m = re.search(r"(\d+)", name)
119 return int(m.group(1)) if m else 0
120
121
122def discover_games(folder: Path, sim_glob: str) -> list[GameRef]:
123 """Find every playable game under a tournament folder.
124
125 Handles three layouts: ``rounds/round_<R>.tar.gz`` archives (the common case),
126 uncompressed ``rounds/<R>/sim_*`` directories, and a flat folder of sim files
127 (e.g. an ad-hoc sample with a single ``sim.json``).
128 """
129 games: list[GameRef] = []
130 rounds_dir = folder / "rounds"
131 if rounds_dir.is_dir():
132 entries = sorted(rounds_dir.iterdir())
133 # Archives first, recording which rounds they cover.
134 archived: set[int] = set()
135 for entry in entries:
136 if entry.is_file() and entry.name.startswith("round") and entry.suffixes[-1:] == [".gz"]:
137 rnum = _round_num(entry.name)
138 archived.add(rnum)
139 with tarfile.open(entry) as tf:
140 for m in tf.getmembers():
141 base = Path(m.name).name
142 if m.isfile() and m.size > 0 and not base.startswith("._") and fnmatch.fnmatch(base, sim_glob):
143 games.append(
144 GameRef(round=rnum, sim=_sim_index(Path(m.name).name), archive=entry, member=m.name)
145 )
146 # Then round dirs — but skip any round already sourced from an archive. A round can
147 # exist both extracted and tarred; counting both would double up the same games.
148 for entry in entries:
149 if entry.is_dir() and _round_num(entry.name) not in archived:
150 rnum = _round_num(entry.name)
151 for f in sorted(entry.iterdir()):
152 if (
153 f.is_file()
154 and f.stat().st_size > 0
155 and not f.name.startswith("._")
156 and fnmatch.fnmatch(f.name, sim_glob)
157 ):
158 games.append(GameRef(round=rnum, sim=_sim_index(f.name), path=f))
159 else:
160 for f in sorted(folder.iterdir()):
161 if f.is_file() and f.stat().st_size > 0 and fnmatch.fnmatch(f.name, sim_glob):
162 games.append(GameRef(round=0, sim=_sim_index(f.name), path=f))
163 # Ensure sim indices are unique within each round; if a filename scheme collides
164 # (or lacks numbers), fall back to enumeration order.
165 per_round: dict[int, list[GameRef]] = {}
166 for g in games:
167 per_round.setdefault(g.round, []).append(g)
168 for gs in per_round.values():
169 sims = [g.sim for g in gs]
170 # Enumerate on collisions, or when the parsed numbers are clearly seeds/timestamps
171 # (e.g. Halite's .hlt names) rather than small sim indices.

Callers 1

load_tournamentFunction · 0.90

Calls 3

_round_numFunction · 0.85
GameRefClass · 0.85
_sim_indexFunction · 0.85

Tested by

no test coverage detected