Cody Flanagan
Software & Automation / Idle-RPG Combat Simulator

Python · Numba · Simulation · Systems design

Idle-RPG Combat Simulator

A Python tool for testing combat rules, comparing team compositions and making better balance decisions.

The goal
Understand how a combat system behaves across thousands of matchups, then investigate the interactions behind the results.
My role
I designed the combat framework and led the simulator’s development: requirements, implementation review, validation strategy and balance decisions.
What it delivers
Broad matchup screening, detailed battle diagnostics, streaming team summaries and repeatable comparisons across four simulation engines.

A tested foundation for design decisions

353,760

Battle results per engine

Four engines reproduced the same recorded baseline across 100 output fields, with zero differences.

513 / 513

Checks passed

Rule-derived tests and supporting validation checked mechanics, outputs and consistency.

154 / 154

Seeded defects detected

Deliberately broken rules were caught by the tests intended to protect them.

Recorded verification: September 8, 2026. Eleven generic test modules; deterministic combat. These results cover the implemented baseline.

The practical result is a tool I can use to compare a proposed change with a known starting point, follow an unexpected outcome down to the battle, and keep the design decision connected to evidence.

From a design question to an inspectable result

  1. Choose the comparisonFix the team pool and rules; identify the variable being changed.
  2. Run the matchupsUse the Python reference or optimized execution paths.
  3. Read the patternCompare outcomes, battle duration and team contributions.
  4. Investigate the causeUse individual battle records and diagnostics to explain the result.

Scale the calculation

The simulator includes reference Python, optimized Python, opcode and Numba engines. Keeping a readable reference alongside the faster paths makes changes easier to check.

Keep large runs manageable

For team summaries, each worker folds battle results into an aggregate as it runs. The parent combines those partial summaries, avoiding the need to retain or export every battle row.

I made output selection part of the requirements: broad screening for coverage, team aggregates for comparison, and detailed records when a specific interaction needs explanation.

ATK: improve the pace without flattening team roles

I wanted battles to resolve sooner while preserving the reasons to use tanks, damage dealers and supports. The stat budget provided a system-wide tuning point: lowering the cost of ATK gives a module more attack for the same allocation.

I requested the weight-18 comparison after the weight-20 test because the shorter mirror fight was closer to the pace I wanted. The controlled study compared the same nine-module pool before expanding the active roster.

Recorded August 4 experiment · nine-module pool
ATK weight5v5 battles reaching the capMedian ticks, uncapped 5v5 battles1v1 mirror turns per side
30 — starting point48.3%32410.1
20 — comparison14.3%2146.4
18 — selected9.2%1905.8

The selected weight moved the system toward the intended pace. I then evaluated the returning modules in that changed environment, including a focused adjustment to Fast Taunt’s damage.

See the Fast Taunt rework

The comparison above is the nine-module experiment. The current eleven-module baseline adopted weight 18 and was verified on September 8; its results are a separate population.

Check that the software follows the intended rules

Agreement between engines is useful, but the design needs an independent reference. I required expected results to come from the combat rules and worked through the decisions needed to make those rules testable.

Derive the expected behavior

Hand-derived scenarios check individual rules and interactions. The current baseline has 357 conformance tests, supported by 156 additional validation checks.

Try to break the protection

Mutation testing deliberately changes a rule to check whether a test detects it. The recorded run caught all 154 seeded defects.

Cross-engine comparisons then check that the faster implementations retain the reference behavior. The September verification compared 353,760 battle rows per engine, including 1v1–5v5 packets and control cases.

Verification scope

The four engines agreed across every one of the 100 recorded battle fields. Screening also matched diagnostics across 213,444 legal 5v5 battles and 1,000 seeded team selections. Combat itself remained deterministic.

Mutation coverage reached 345 of the 357 conformance tests. The other 12 check structural, document or boundary conditions outside the seeded combat mutations. The full baseline is an ongoing development stage; Crit and later combat layers remain future work.

Postmortem: keep the measurement tied to the decision

What worked

A shared comparison process made it possible to move between a system-wide pacing change and a specific module adjustment. I could keep the intended experience in view while checking the consequences at several team sizes.

The engineering challenge

Multiple optimized engines and parallel summaries needed to preserve behavior. A reference implementation, independently derived checks and repeatable comparisons gave that work a concrete acceptance standard.

The design lesson

A high win rate or a battle hitting its cap needs context. I judged those results against the roles and compositions involved, then chose targeted changes that preserved useful differences between teams.

The next step

The deterministic foundation is verified. The next balance stage must address 558 identified 4v4/5v5 stalled matchups and evaluate the proposed Crit layer against the same comparisons.

Inspect the implementation

The public repository contains the current Python package, setup instructions and regression fixtures. Its 161 included checks passed, with zero mismatches across 1,000 seeded engine comparisons.

Developed with AI coding assistance under my direction.

Project image