Factorio Calculator

In this post I’ll be talking about one of my all-time favorite computer games, Factorio! Specifically: how well it lends itself to automation, and how a lot of benefits can come from using external tools to find the most efficient solutions to many of the challenges the game presents.

What is Factorio?

Factorio is a game all about automation. As a programmer who loves scripting and making things as efficient as possible, I love this aspect of it. Yet like any piece of software I might write, Factorio is complex enough that for most aspects of it, the “best” solution is not obvious, nor is it obvious that there even exists a “best” solution.

Like many other games, Factorio is built around progression. You start out with very little: simple hand tools, basic materials available to you in the environment, and only a few simple crafting recipes. Yet, even the smallest amount of manual labor unlocks the potential to automate an otherwise tedious task.

In other games, progression usually takes the form of increasing the power or capabilities of the player, but in Factorio, what the player unlocks is the ability to do more and more automation. The ultimate goal of Factorio is to build a factory that runs entirely on its own. (Technically, you “win” the game by building and launching a rocket ship, but more advanced players got bored with that 100 gameplay-hours ago.)

My Factorio play time on Steam. I regret nothing.

To be more specific, here are the basic steps of your first Factorio game:

  1. Realize your goal. For new players, the game tells you this: build and launch a rocket ship. Realize that in order to do this, you’re going to need to gather a lot of resources and research many different technologies. But, you’ve got to start somewhere. How about some iron plates?
  2. Find some iron ore on the ground and start mining it with your pickaxe. Realize it’s boring and think: I want to automate this!
  3. Build some automated mining tools, like a mining drill. Realize it requires coal to run, so now you have to mine some coal as well.
  4. Build some storage for all these raw materials you now have coming in from your mining drills. Realize you need some way of centralizing your storage since the ore patches are a bit of walk from each other.
  5. Build some transport belts to ferry items halfway across the map into your storage area. Now we’re talking!
  6. Your hands are tired from crafting all these belts. Make some assembling machines to do the crafting for you!
  7. Wait a second… these assembling machines require electricity! Time to build a water pump, boilers, steam engines, and power poles to make a power grid…
  8. Time to do some research! This requires many different materials with complicated crafting recipes that require different amounts of ingredients.
  9. Oh no! All these machines are producing pollution and attracting hostile aliens! Time to build some defenses.

And so on…

The point here is that on the way to your ultimate goal, Factorio presents you with various problems, and usually the solution to these problems introduces two more problems. The game is a wonderful balancing act of managing those problems as they arise, but still maintaining sight of your goal.

What Challenges Does Factorio Present to Players?

The main challenge that Factorio gives the player, and the one I really want to focus this post on, is similar to a concept in chemistry known as the limiting reagent. In a chemical reaction, reactants (reagents) are consumed to form products. But only exact amounts of each reactant can be consumed to cause each reaction. For example, take a look at this chemical reaction showing the combustion of benzene with oxygen to form carbon dioxide and water:

\[2\mathrm{C}_6\mathrm{H}_6 + 15\mathrm{O}_2 \rightarrow 12\mathrm{CO}_2 + 6\mathrm{H}_2\mathrm{O} \]

The reaction can only occur if exactly 2 moles of benzene are present and exactly 15 moles of oxygen are present. If you have 2 moles of benzene and 2 moles of oxygen, nothing will happen. If you have 15 moles of benzene and 15 moles of oxygen, the reaction will occur, but you’ll have 13 moles of benzene left over.

Recipes in Factorio are the same way. They require exact amounts of ingredients to make, and the key part of the problem is that the ratio of those ingredients is not always 1, meaning you can have differing amounts of required ingredients. Here’s what a recipe in Factorio might look like:

Factorio recipe for a basic assembling machine.

This recipe requires 3 electronic circuits, 5 iron gear wheels, and 9 iron plates. The implication of this is that if you have equal amounts of supply of each of those ingredients, you’re going to run out of iron plates very fast. And it gets even more complicated: each of the recipes for these ingredients also has requirements. In fact, the recipes for electronic circuits and iron gear wheels both require iron plates. So how many iron plates does it really take to make an assembling machine? Going further, how many of each basic material does it to take to make an assembling machine? And in what ratio do I need to have these materials in supply in order to not run out of any of them?

Before I go on, let me just say that Factorio presents many other kinds of interesting challenges besides these, like belt balancing, train scheduling/routeing and factory modularity. Maybe I’ll leave these topics for future posts.

How Can These Challenges be Solved More Efficiently with External Tools?

The in-game interface, as well as the official Factorio wiki have somewhat limited capability to answer these questions. They tell you the ingredients and ratio of those ingredients required for any recipe, but it’s hard for the player to determine anything further from that without doing a lot of multiplying. So I decided to save myself and other players the headache and write a tool that will do all this for me. As is the Factorio way, I automated the process.

Gathering Data

The first challenge was to make sure I had a complete description of all of the in-game recipes. I wasn’t about to enter them all by hand, so I decided to write a scraper that would parse use the game’s (relatively) opaque data files included in the installation. While the game engine itself is written in C++ and distributed in a binary, all of the game data is distributed as Lua scripts in order to allow easy modding access. I’m not too big on Lua, so I decided to use my language of choice, Python, and find a simple Lua interpreter that could parse the game data for me. Note: Lupa requires a bit more setup than simply installing the Python package. You’ll also need to install a Lua runtime. The docs have all the instructions neccessary.

It took a little snooping, but after perusing the data files in the game install folder, I found the Lua scripts simply extend a large table called data with all of the item “prototypes” and recipes. Getting the data out from there was simply a matter of executing those scripts, grabbing the data object, and looking through the (quite large) returned Python dictionary for the objects I needed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import os
import lupa
# start Lua runtime
lua = lupa.LuaRuntime(unpack_returned_tuples=True)
# add game libraries to Lua's import path
lib_dirs = [
('data', 'base'),
('data', 'core', 'lualib')
]
lua.execute("package.path = package.path .. '{}'".format(''.join(
";{}/?.lua".format(os.path.join(GAME_DIR, *path).replace(os.sep, "/")) for path in lib_dirs)))
# execute data files
with open(os.path.join(GAME_DIR, 'data', 'core', 'lualib', 'dataloader.lua'), 'r') as f:
lua.execute(f.read())
with open(os.path.join(GAME_DIR, 'data', 'base', 'data.lua'), 'r') as f:
lua.execute(f.read())
# get data object
data = lua.eval('data')['raw']
# parse data (a very large, nested Python dictionary) to find items and recipes
...

Parsing Data

Once I had the raw data, I built a tree of Recipe objects in Python representing each recipe. For this part I had to make the simplifying assumption that recipes produce only one item, and each item is produced by only one recipe, neither of which is always the case. A Recipe simply keeps track of what items it requires and in what quantities, how many of the product it produces, and how much energy the recipe requires. Energy in Factorio recipes is simply a measure of how long the recipe takes to complete (different methods of crafting can produce recipes at different energy rates).

Energy actually turns out to be another important factor in determining supply and demand. Let’s say my goal is to produce electronic circuits at one item per second. The recipe for electronic circuits takes one second and requires 3 copper cables. Copper cables take 0.5 seconds to make. So in order to make one electronic circuit per second, I need:

\[\frac{3~\mathrm{copper~cable}/\mathrm{electronic~circuit} \times 0.5~\mathrm{sec}/\mathrm{copper~cable}}{1~\mathrm{sec}/\mathrm{electronic~circuit}} = 1.5~\mathrm{copper~cable~factories}\]

This is a simple example with a lot of one’s in the equation, so let me just show you the full equation:

\[F = \frac{I_E \times I_C}{P_E \times P_C}\]

where \(F\) is the number of required factories, \(I_E\) is the amount of energy the ingredient’s recipe takes, \(I_C\) is the count of the ingredient the recipe takes, \(P_E\) is the amount of energy the product’s recipe takes, and \(P_C\) is the count of the products the recipe yields.

This equation, when applied to each ingredient of a given recipe and recursively down the recipe tree, allows us to answer the questions we asked before. From this we can determine exactly both the number of items as well as the number of factories producing those items required to produce an item at a given rate.

Displaying Data

Next, I needed a nice concise way of showing this data to the user. I decided to use my favorite GUI library, PyQt5, and build a custom widget to display these recipe trees.

The recipe tree widget builds a recursive layout that displays the product at the top and lays out the recipe trees of each ingredient in a horizontal layout below it. I then customized the widget painter to draw lines over the widget from the product icon to each ingredient icon, to further emphasize the tree relationships.

Here’s what I did for displaying the actual data:

  • Next to each item’s icon, I display the number of that item requried to produce the item above it. So if the item above it says ×3 and the recipe calls for 2 of that item, it will show a ×6.
  • Under each item is the number of that recipe required to produce that many items. So if the recipe produces 2 of the item and the item has a ×5 next to it, this number will show ×2.5. The icon next to this number indicates the simplest tool required to craft the recipe.
  • Next to the recipe count is the amount of energy required to execute that many recipes. So if the recipe count is ×4 and each recipe takes 10 energy, this will show 40🗲.

Here’s what the recipe tree looks like for electronic circuits:

Recipe tree for electronic circuits.

This one diagram tells us a lot. Here are a few facts I’ll pick out:

  • Making 1 electronic circuit requires 3 copper cables and 1 iron plate.
  • Making 1 electronic circuit eventually requires 1.5 copper ore and 1 iron ore.
  • I need 1.5 factories producing copper cable and 1 factory producing iron plate for every factory producing electronic circuits.
  • In terms of time required, the iron plates are probably going to be the limiting factor, since the iron plate requirement takes 3.5 energy and the copper cable requirement takes only 1.5 energy. This is harder to be sure about since actual time required depends on the assembling machine tier being used.

Let’s see what it looks like for something a bit more complicated, like a construction robot:

Recipe tree for construction robots.

And here’s what it looks like for something ridiculous like power armor MK2:

Recipe tree for power armor MK2. Yikes!

These diagrams are extremely useful to Factorio players because they can tell you:

  • Exactly how many factories you need producing ingredients to support a specific recipe
  • What ratio of ingredients you need to keep in stock to support a recipe
  • How long certain recipes will take
  • How many raw materials certain recipes consume

The last two points require only summing values in the diagram. I added this as a sidebar in my application that shows the totals:

Recipe totals for construction robots.

Currently my code isn’t really in a shareable state quite yet, but once I clean it up a bit I’ll throw it on GitHub.

What are the Parallels Between Factorio and Software Development?

This is a bit of an aside, but I think this talk touches on a lot of great points about how a good Factorio player acts a lot like a software developer: