Here's the picture:
Analysis
game.rs is the clear candidate — 13,870 lines, and it's the only file that's unwieldy. Everything else is reasonably sized (the set files are large but inherently repetitive card listings).
Breaking game.rs down:
| Section | Lines | Notes |
|---|
| Core game logic | ~4,857 | impl Game with all methods |
| Test modules | ~9,013 | 38 separate mod *_tests blocks |
The biggest functions in the core logic:
| Function | ~Lines | Does what |
|---|
execute_effects() | 1,636 | Giant match on ~30+ Effect variants |
pay_costs() | 326 | Match on Cost variants |
apply_continuous_effects() | 273 | Applies StaticEffect variants |
check_triggered_abilities() | 242 | Checks all trigger conditions |
compute_legal_actions() | 173 | Enumerates legal plays |
There are also 3 duplicate AlwaysPassPlayer impls in different test modules.
Recommendations
Splits that would help:
-
Move tests out of game.rs (~9K lines) — The 38 test modules could live in mtg-engine/tests/ as integration tests, or in a game/ module directory with a separate tests.rs. This alone would cut the file from 14K to ~5K lines.
-
Extract execute_effects() into game/effect_resolution.rs (~1,600 lines) — This is a massive match statement. It's a natural unit: "given an Effect enum variant, modify game state." Could be impl Game in a separate file via the mod pattern.
-
Extract combat into game/combat_resolution.rs (~350 lines) — declare_attackers_step, declare_blockers_step, combat_damage_step, resolve_fight_pair form a cohesive group.
-
Extract apply_continuous_effects + filter/matching helpers (~400 lines) — apply_continuous_effects, matches_filter, card_matches_filter, find_matching_permanents are a natural cluster.
Splits that are probably NOT worth it:
- The set card files (
fdn.rs etc.) — they're big but dead-simple repetitive factories; splitting by letter or rarity would add complexity without improving readability.
abilities.rs (2,113 lines) — it's mostly enum definitions and builder methods, reads fine as-is.
- Any of the other engine files — all under 1K lines.
Bottom line: game.rs is doing the work of 3-4 files. The highest-impact move is extracting tests, then execute_effects. Want me to plan and do one of these splits?