factory-sim
A fast, tick-exact simulator of Factorio's early game: train agents at simulator speed, then check them against the real game.
pip install factory-sim
It simulates a small slice of the game exactly: a character walking, reaching and hand-mining; burner mining drills; stone furnaces; fuel; items on the ground; walls and water. Every rule and number comes from measurements of Factorio 2.0.60, and the simulator is checked decision by decision, and tick by tick, against traces recorded from the running game by FactorioGym. A mechanic is added here only after it has been measured there.
The point is speed. The real game runs about 260 decisions a second across eight workers. This runs 950,000 on 16 threads, and 530,000 through the full RL path (observation tensors, masks, rewards) on eight. The 40 million decisions a PPO run below uses would be about two days of nonstop play on the game.
Two ways to solve a task
Reinforcement learning. train.py is masked PPO in one file: CleanRL's
layout at PufferLib's scale, with the choices and their sources in its
docstring. Policies trained here are evaluated on the real game with
FactorioGym's tools/sim_transfer.py. On held-out layouts they score:
| Task | Simulator | Factorio |
|---|---|---|
construct_smelting_line |
92.0% | 90.6% |
build_line |
99.2% | 90.6% |
This is one checkpoint per task, evaluated over 512 simulator episodes and 32 engine episodes. FactorioGym's README has the per-split numbers and the evidence files.
Program search. evolve/ has a language model write short Python
def build(world): programs, scores them in the simulator, and breeds the
better ones: islands, tournament selection, a genealogy of every attempt. A
program sees exactly what a trained policy sees, and every call it makes is one
decision of the same action space. It runs in a static sandbox with no imports
and no reflection. Selection uses a validation set, and the frozen held-out
scenes are touched only for reporting.
On construct_smelting_line, 1,000 held-out scenes that no run or analysis
had seen:
| Held-out success | Simulated decisions | |
|---|---|---|
| Evolved programs, 4 runs from a program that does nothing | 0.994, 1.000, 0.990, 0.999 | 0.46–0.69M to pass 0.9 |
| PPO, 4 runs, sampled actions | 0.928, 0.858, 0.837, 0.804 | 40M each |
Sampling is PPO's best mode: played greedily, the same checkpoints score 0.01–0.19. The model knows things PPO has to learn, pathfinding for a start, so fewer simulated decisions is not less compute. Seeding the search with a hand-written builder made it generalise worse: it kept the builder's wall-blind walker and patched individual validation scenes. The default seed is now a program that does nothing.
Use it
As a Gymnasium environment (pip install factory-sim[gym]):
import gymnasium as gym
import fsim.gym_env # registers the ids
env = gym.make("fsim/BuildLine-v0", split="test") # the held-out family
obs, info = env.reset(seed=0)
obs, reward, terminated, truncated, info = env.step(env.action_space.sample())
The ids are fsim/ConstructSmeltingLine-v0, fsim/BuildLine-v0 and
fsim/PlateLine-v0. The same environment is also available through
PufferLib, OpenEnv and the verifiers / Prime Environments Hub
format; docs/interfaces.md covers each.
Train PPO (uv sync --group train for PyTorch):
python train.py --run sparse-s1 --seed 1 --steps 20000000
Run program search. It needs an OpenAI-compatible endpoint, set in a JSON
file with base_url, api_key and model, plus optional price and
max_usd for a hard spending cap:
FSIM_LLM_CONFIG=provider.json python -m evolve.run --name demo --budget-candidates 150 --max-usd 1
Tasks
| Task | The agent has to |
|---|---|
construct_smelting_line |
find an ore patch it can only partly see, place a drill on ore and a furnace under the drill's drop point, fuel both, and get 10 machine-made plates in a verification minute |
build_line |
build a drill-and-furnace line and keep it running: success reads the output of a window after construction has settled, so a line that ran once and died fails |
plate_line |
commission a line that is already built by fuelling the right machines; one family adds decoy machines and items |
Each task has training families and a held-out family (a patch behind a wall, a narrow strip), drawn exactly as FactorioGym draws them, so a seed names the same scene in both projects.
What "tick-exact" means
- All 12 golden scenarios match the game at every decision, and all 8 tick-level traces match on every tick.
- Doubles match to within 1e-12, because the game prints some with an imprecise last digit.
- Ore under a drill is compared as a total over its four tiles: the order a drill visits its tiles follows the engine's internal entity order, which could not be reduced to a rule.
- The RL layer matches FactorioGym bit for bit: every encoded observation hashes identically, and so do the mask, reward, termination and success.
Build from source
uv sync # installs the checkout editable, compiling csrc/
uv run python build_fsim.py # rebuilds fsim/_fsim in place after a C change
uv run pytest # includes parity against tests/golden
uv run python bench/bench.py # throughput; results in bench/RESULTS.md
tools/sync_golden.py --from ../FactorioGym refreshes the golden traces from
a FactorioGym checkout, checking every trace's hash.
Citing
If you use factory-sim in academic work, please cite it. GitHub's "Cite this repository" button reads CITATION.cff; in BibTeX:
@software{agrawal2026factorysim,
author = {Agrawal, Divyansh},
title = {{factory-sim}: a fast, tick-exact simulator of an early-game factory},
year = {2026},
version = {0.1.2},
url = {https://github.com/divagr18/factory-sim},
license = {Apache-2.0}
}
License
Apache-2.0; see LICENSE. Factorio is a game and trademark of Wube Software Ltd. This project is independent, and is not affiliated with or endorsed by Wube. It contains no game code or assets; see NOTICE.
Release files for factory-sim 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| factory_sim-0.1.2.tar.gz | 237.2 kB | Details |
Built distributions (wheels)
Total release size: 2.1 MB
Release files / factory_sim-0.1.2.tar.gz
| Download URL | factory_sim-0.1.2.tar.gz |
|---|---|
| Size | 237.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
61ae34bad5e17cb53c423856cc84918a59f2e2220a6a963455ba1171823325a5
|
|
BLAKE2b-256 checksum How to use checksums |
9126b46c34daaeae56dfbbd7993946d0419777a8c2cbe6957eeb9116a96211e0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / factory_sim-0.1.2-cp313-cp313-win_amd64.whl
| Download URL | factory_sim-0.1.2-cp313-cp313-win_amd64.whl |
|---|---|
| Size | 178.0 kB |
| Tags | CPython 3.13 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
070dea00361a32214af9785e3a26c9f24e6f8c54770f260750a9be4d7c36f5b6
|
|
BLAKE2b-256 checksum How to use checksums |
347be1e38c6f9d01a25404792080821f86625fdb1bbe9674b99f77c2ec1620d2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / factory_sim-0.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
| Download URL | factory_sim-0.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 267.5 kB |
| Tags | CPython 3.13 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
8367e463cd02d7cef298b32635c2c82a54f7e3f96483ce58315f942e6612f0ff
|
|
BLAKE2b-256 checksum How to use checksums |
b22cfb46cf45da95b76253330ba711287af796b91009e95c1997251959bce0ee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / factory_sim-0.1.2-cp313-cp313-macosx_11_0_arm64.whl
| Download URL | factory_sim-0.1.2-cp313-cp313-macosx_11_0_arm64.whl |
|---|---|
| Size | 180.8 kB |
| Tags | CPython 3.13 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
0fdcf36c32820d75a27a8fe1d2054798de842ea5f41130300973aa607b9a7792
|
|
BLAKE2b-256 checksum How to use checksums |
311f9ce460373beb3a4ecd17293d62d97c63834ee8c386aaf999ac450750fbb6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / factory_sim-0.1.2-cp312-cp312-win_amd64.whl
| Download URL | factory_sim-0.1.2-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 178.0 kB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
88cb870aa2b99954192a5818c849ac428349008ef5ed101502a3ebdb79567a51
|
|
BLAKE2b-256 checksum How to use checksums |
376a8c86d1933a357b5b5f8eb2cb1e6705d0480c9e52a12fc0d932b2677b3e25
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / factory_sim-0.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
| Download URL | factory_sim-0.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 267.5 kB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
8df91cbbb1fabbdcfa6b05ba33e82e60980b7805b3f654307adacdf3bc38e5a3
|
|
BLAKE2b-256 checksum How to use checksums |
05d8ca0855ea3815ab74c29b3610a14387a56bbbf472e774286c6d6e97460b8d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / factory_sim-0.1.2-cp312-cp312-macosx_11_0_arm64.whl
| Download URL | factory_sim-0.1.2-cp312-cp312-macosx_11_0_arm64.whl |
|---|---|
| Size | 180.8 kB |
| Tags | CPython 3.12 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
061ab1b4b1272d13e8fbcf7efac142441f40be3a6d9c7500d458d1b711cc162b
|
|
BLAKE2b-256 checksum How to use checksums |
6e61e5df6778e64ec40fc165deb9d3bb3239b81a620bcb0188fb10aa7f64ddc3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / factory_sim-0.1.2-cp311-cp311-win_amd64.whl
| Download URL | factory_sim-0.1.2-cp311-cp311-win_amd64.whl |
|---|---|
| Size | 178.0 kB |
| Tags | CPython 3.11 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
b836152e50df2ab34e5f3757c0d311e0713cbdb9232fed94a2cde0441ceb1232
|
|
BLAKE2b-256 checksum How to use checksums |
b141d537832208f0fde3b8df1347175d205134a23b18fdd0e2a50ff4cb61c254
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / factory_sim-0.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
| Download URL | factory_sim-0.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 266.8 kB |
| Tags | CPython 3.11 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
16f4470bc7df4dcacf8f7aa1d157848b47e295ec8b83437bf04bc80a56d85107
|
|
BLAKE2b-256 checksum How to use checksums |
04e4627af6b22944e6a87ce10cbfe30bdd1dd2b82d36684d794661863228b4cc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / factory_sim-0.1.2-cp311-cp311-macosx_11_0_arm64.whl
| Download URL | factory_sim-0.1.2-cp311-cp311-macosx_11_0_arm64.whl |
|---|---|
| Size | 180.7 kB |
| Tags | CPython 3.11 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
7a38121697bc8fc00f17e98e9e398f0cc974097f04ed46ee14ba66a457918a8d
|
|
BLAKE2b-256 checksum How to use checksums |
ab7565a1d7289e0a9203fe0ef3f37ddb71fa798304d86eb4116793bf04cef7a3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency log