Skip to main content

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; transport belts, burner inserters and wooden chests; 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. A belt-heavy scene, 338 belts with about 180 items moving, runs at about 200,000 ticks a second on one laptop core.

Three 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. Played on the real game, the four runs' programs succeed in 397 of 400 held-out episodes (99.3%), and the simulator agrees on every episode.

Training a language model. The same program task is an RL environment for language models: factorio-build on Prime Intellect's Environments Hub (prime env install divagr/factorio-build). The model writes one program per row, and the reward is the fraction of the row's unseen scenes it solves. recipes/grpo-factorio-build trains Qwen3.5-9B on it with prime-rl. Scored in the simulator on construct_smelting_line, with PlanBench Blocksworld to measure what the training costs the model's general planning:

Qwen3.5-9B val (sim) holdout (sim) PlanBench generation PlanBench execution
base 2.1% 1.6% 53.2 39.8
SFT on 800 evolved programs + GRPO 85.9% 84.0% 2.8 3.0
Evolve & Reinforce, round 1 85.6% 71.9% 46.4 27.8

Evolve & Reinforce builds the warm start from the model's own explanations of the evolved programs, with replay of its answers to general prompts, then runs GRPO. It keeps most of the planning ability that SFT on bare programs destroyed, and gives up 12 points of holdout. A sample of the SFT + GRPO model's holdout programs succeeds in 136 of 160 episodes on the real game, again in agreement with the simulator on every episode. Models: qwen3.5-9b-factorio-build-er-r1 and -er-r1-sft; all of them in the models collection.

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
python train.py --run belt-s1 --task belt_smelting    # the v3 profile, its own budget

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

--task belt_smelting searches for belt-line programs instead.

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
belt_smelting walk between an iron patch, a coal patch and an output chest that no standing spot reaches two of, and build drills, furnaces, belts and burner inserters that deliver 150 iron plates into the chest in a ten-minute window. The 20 starting coal runs a line for about 79 plates, so the line also needs coal from the coal patch

Each task has training families and held-out families (a patch behind a wall, a narrow strip, a chest at the far end of the belt budget), drawn exactly as FactorioGym draws them, so a seed names the same scene in both projects. belt_smelting's scripted reference (fsim/belt_expert.py, a port of FactorioGym's reference solver) solves 599 of its first 600 scenes; the one failure has its whole coal patch on water.

Action and observation profiles

The first three tasks use MultiDiscrete([22, 33, 122, 5, 15, 4]): operation, target, placement tile, direction, item and amount, in two variants (v1, and v2, where the target is a table row and the placement a fixed tile). belt_smelting uses v3, MultiDiscrete([25, 97, 226, 5, 19, 4]):

  • 25 operations: v2's 22 plus hand-mining a resource tile (mine_tile), take_fuel and finish, which ends the build phase and runs the verification window at once;
  • a mask per operation, legal where the game accepts: entities within the engine's reach (10 tiles from the character to the entity's box), resource tiles within 2.7 tiles, and placements within build distance;
  • the observation adds each belt's lane counts and turn, each inserter's hand and its pickup and drop points, a drill's drop point, the task's public markers, and the free inventory slots.

Programs on belt_smelting hold WorldV3, which speaks the same profile.

What "tick-exact" means

  • All 24 golden scenarios match the game at every decision, and all 19 tick-level traces match on every tick. Twelve of the scenarios exercise what belt_smelting needs: belts, inserters, chests, hand-mining, take_fuel and finish.
  • The belt and inserter rules come from five logistics probes and two hand-mining probes on the engine: belt-line segments and their merge delays, turns, sideloads, loops, and inserters picking from moving belts. FactorioGym's docs/sim-logistics.md records every measurement.
  • 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. Under v2 every encoded observation hashes identically, and so do the mask, reward, termination and success. Under v3 the observation tensors and masks do, at every decision of every golden scenario.

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.2.0},
  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.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for factory-sim 0.2.0
File Size Uploaded
factory_sim-0.2.0.tar.gz 711.6 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for factory-sim 0.2.0
File
factory_sim-0.2.0-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details
factory_sim-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.17+ x86-64, Linux glibc 2.28+ x86-64 Details
factory_sim-0.2.0-cp313-cp313-macosx_11_0_arm64.whl CPython 3.13 CPython 3.13 macOS 11.0+ ARM64 Details
factory_sim-0.2.0-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details
factory_sim-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.17+ x86-64, Linux glibc 2.28+ x86-64 Details
factory_sim-0.2.0-cp312-cp312-macosx_11_0_arm64.whl CPython 3.12 CPython 3.12 macOS 11.0+ ARM64 Details
factory_sim-0.2.0-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details
factory_sim-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.17+ x86-64, Linux glibc 2.28+ x86-64 Details
factory_sim-0.2.0-cp311-cp311-macosx_11_0_arm64.whl CPython 3.11 CPython 3.11 macOS 11.0+ ARM64 Details

Total release size: 6.7 MB

Release files / factory_sim-0.2.0.tar.gz

Download URL factory_sim-0.2.0.tar.gz
Size 711.6 kB
Tags Source
SHA-256 checksum
How to use checksums
722b6f602a4ee0f57ee57016f7d18cd6be6bf37af1b555c29b83637fcdb06dde
BLAKE2b-256 checksum
How to use checksums
bde369efac446c18b25d3fc3932f78c531d414b3e4c02652746d604b6bfeb79a
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 26, 2026.

Transparency log

Release files / factory_sim-0.2.0-cp313-cp313-win_amd64.whl

Download URL factory_sim-0.2.0-cp313-cp313-win_amd64.whl
Size 587.5 kB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
33082b3dadfdf98d351cdc37433044d2feb060a5830e30f40142435101c94dd8
BLAKE2b-256 checksum
How to use checksums
9ee05d5063dd7f722a1688d98a62ef565a2e4312e5740f9c80783ce00018da0d
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 26, 2026.

Transparency log

Release files / factory_sim-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl

Download URL factory_sim-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Size 809.1 kB
Tags CPython 3.13 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
9464d7578979a6f00bce6d43d54b8d1a9773696d9cb339ca184ac9b0ab822c35
BLAKE2b-256 checksum
How to use checksums
165f2addf4f9a4942ae90be3c81089faaf27cec213eb71e6caf416ecf7ae9869
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 26, 2026.

Transparency log

Release files / factory_sim-0.2.0-cp313-cp313-macosx_11_0_arm64.whl

Download URL factory_sim-0.2.0-cp313-cp313-macosx_11_0_arm64.whl
Size 604.5 kB
Tags CPython 3.13 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
eed1ca7a2b58e3c55e6287279677c434aa3d4db36b266fe2bf47d4fde1d23bd0
BLAKE2b-256 checksum
How to use checksums
a8ad2747ca6156151b6da1bbbba192649ea4cb11343d699f200222d9cebd4c0c
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 26, 2026.

Transparency log

Release files / factory_sim-0.2.0-cp312-cp312-win_amd64.whl

Download URL factory_sim-0.2.0-cp312-cp312-win_amd64.whl
Size 587.5 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
c28ff04a5e19a67cb8c01b49fd54eeb21955c7283b7def7214c76c6c8377e002
BLAKE2b-256 checksum
How to use checksums
e6d2151ad7a2f08384a0d8598eb2ab0f19562039b1105b8524ca97d4a919875a
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 26, 2026.

Transparency log

Release files / factory_sim-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl

Download URL factory_sim-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Size 809.1 kB
Tags CPython 3.12 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
3ec00b8fda2d2c0bf84bac52e1badaeb372128ab004f7ab60d0f3517fdd6fe7a
BLAKE2b-256 checksum
How to use checksums
9859b5ae742bd4b4c43aa91d27b284c2b2d7d0dcabb1225e6b7760aa412fc75c
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 26, 2026.

Transparency log

Release files / factory_sim-0.2.0-cp312-cp312-macosx_11_0_arm64.whl

Download URL factory_sim-0.2.0-cp312-cp312-macosx_11_0_arm64.whl
Size 604.5 kB
Tags CPython 3.12 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
af92f3b2aaaa0ba516b944119ff5e893917b7ec769d836e8f46340623837aa71
BLAKE2b-256 checksum
How to use checksums
e915ceb119c1075bb44a9c8e7714d8ab4eb699aa5f1c8109b767f00ee33507a3
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 26, 2026.

Transparency log

Release files / factory_sim-0.2.0-cp311-cp311-win_amd64.whl

Download URL factory_sim-0.2.0-cp311-cp311-win_amd64.whl
Size 587.4 kB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
7dae6eb0d73a73a4ec76632fc0f73395e291b2eb6f0ebcf19a26288e7b135f82
BLAKE2b-256 checksum
How to use checksums
197e1e560458a9a4c16c22d6aa588a42349a884584855b47c4ef369a814a1701
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 26, 2026.

Transparency log

Release files / factory_sim-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl

Download URL factory_sim-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl
Size 808.2 kB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
9d11f50a99b9c59b001f9022627fe304f592e684832177d4794658037b7ae3c2
BLAKE2b-256 checksum
How to use checksums
1aa4833386863fbf853bd0d5aecfe23da0ad31815e26b4288756e8dbec23ccf4
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 26, 2026.

Transparency log

Release files / factory_sim-0.2.0-cp311-cp311-macosx_11_0_arm64.whl

Download URL factory_sim-0.2.0-cp311-cp311-macosx_11_0_arm64.whl
Size 604.3 kB
Tags CPython 3.11 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
54a1d6d5af66f9f56207033cd8e77d678f706c2fb30638a3ed98ebee26dabd94
BLAKE2b-256 checksum
How to use checksums
2f47057b27417ee4dd67fa0b87b43aaea5e5c9919293ab7f7ac42ba5be45f254
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 26, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

10 release files

0.1.2

10 release files

0.1.1

10 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page