Contact Info

sean [at] coreitpro [dot] com gpg key

Mastodon

sc68cal on Libera

Programming Space Platforms in Factorio

I have recently relapsed into my Factorio addiction with the introduction of the new Space Age DLC.

Originally, my addiction focused around building train networks to move resources around my factory and resupply my artillery outposts.

With the new Space Age DLC there are whole new worlds to explore, and a whole new set of programming challenges to master.

Anane is my primary space platform that travels between Nauvis, Vulcanus, and Fulgora, transporting manufactured goods and resources between these planets. In Factorio’s Space Age DLC there are many resources that only exist on certain planets, which requires you to build a space logistics system to move resources and manufactured goods from where they can be produced, to where they are used.

Programming a flight schedule with a safety check

The first programming challenge was to create an automated schedule for Anane between all the planets that I have discovered so far, while ensuring that the platform does not leave the safety of Nauvis until enough supplies have been manufactured for a journey. Having a space platform run out of fuel mid-journey, or be destroyed by collisions with asteroids because it ran out of ammunition for turrets would be as costly as it would be embarrassing.

Anane flys between Vulcanus, Nauvis, and Fulgora in a specified order, with a special programming condition set for Nauvis. Anane only leaves Nauvis if the circuit condition Checkmark is greater than 0.

The Checkmark signal is generated by a decider combinator, based on inputs from a circuit network that is connected to a set of storage tanks for water, thruster oxidizer, thruster fuel, as well as a logistics belt of ammunition for turrets. The decider combinator has the conditions programmed for the minimum amounts of these resources that are required in order to fly to another planet.

Flights between Nauvis and the other planets involve flying through asteroid belts, which pose a danger to space platforms. Asteroid defense is accomplished by using turrets, which shoot ammunition at asteroids in order to break them up into smaller pieces. These smaller pieces do not damage the space platform if they collide with the platform.

Shipping goods between planets

Anane is programmed to pick up items manufactured on each planet, like for example the following are manufactured on Vulcanus and transported to Nauvis and Fulgora.

Tungsten carbide is produced on Vulcanus and transported to Fulgora1 for the manufacture of speed module 3’s in electromagnetic plants.

Managing the nuclear reactor

Originally, Anane was a solar powered space platform. However, as time passed it became clear that solar power was not sufficient for the frequency of flights between planets that was required in order to progress further in the game in a reasonable amount of time. As a result, a small nuclear reactor was installed on the space platform, with nuclear fuel being supplied from Nauvis where I had my main nuclear powered megabase.

For efficiency the nuclear reactor is managed via a decider combinator that only inserts fuel when required, so that no nuclear fuel is ever wasted.

Steam stored in tanks is used as the slack in the power system. Nuclear power plants “burn” the nuclear fuel and generate heat and there’s no way to pause or slow this process down. When more energy is produced than consumed, the excess energy is stored as steam in tanks and the system only inserts fuel into the nuclear reactor when the steam amount dips below a threshold.

Observant factorio players will see that I have a logistics belt that takes spent fuel out of the nuclear reactor and tosses it off the space platform, to float endlessly in space (there is no EPA to stop me).

Asteroid Mining System

When I first started out building Anane, it was taking far too long to get to the point where the safety check circuit was emitting a Checkmark with a value of 1, as described in the first section, due to a bottleneck around oxidizer and thruster fuel production.

Oxidizer and thruster fuel is manufactured by mining the asteroids that the turrets destroy. The problem is that asteroids only appear at random intervals, and non-uniform distribution of the of 3 types of asteroids.

The asteroid pieces are transferred from the asteroid collectors on the front of the space platform down to my “sushi belt”2

Sushi belts are a bit complicated because you have to ensure that you keep the belt balanced by consuming all the ingredients that are on the belt, and managing the addition of ingredients onto the belt. If you don’t keep the production and consumption in balance, the belt fills up and ingredients don’t move around the belt to locations where they can get picked up and used, and then the whole system deadlocks.

Preventing deadlocks

Anane’s sushi belt is controlled by an arithmetic combinator which reads the contents of the belt and totals them up.

The total is then sent to a belt section which has an enable/disable program set, where it only puts more items on the sushi belt if it’s below 300 items total.

Managing the collection of asteroids

The first version of my asteroid mining system used a circuit network that would count the number of different asteroid types contained on the belt (there are 3, and you need all 3 for fuel) and use decider combinators with logic that would generate a signal to the asteroid collectors, when the counts for specific asteroid types dipped below a certain level. The signals sent would set the filters on the collectors, which would then selectively pick up new asteroid chunks, based on the filters that the circuit network set.

With this version of the circuit network Anane would fly between planets, shoot a ton of asteroids into chunks, and then only pick up a tiny fraction of the total available. This was due to a limitation where there was no way to get rid of excess asteroid kinds if too many already were on the belt. The only way to handle excess asteroids was to wait for them to eventually get consumed by the manufacturing processes.

So, the redesign had to behave as follows:

  • Keep the belt from filling up with too many items and deadlocking
  • Keep a tally of the existing asteroid kinds on the belt
  • Collect asteroids in a least-amount-to-most priority (collect asteroids that we have too few of, first)
  • Manage asteroid reprocessing in the asteroid crushers when there is too many of a specific kind of asteroid, in order to keep the belt from deadlocking and free up space on the belt for new asteroids to be put on the sushi belt.

The first and second problem are solved by the existing arithmetic combinator and the gate, with no changes.

The third behavior was accomplished by a pair of selector combinators which take the signals from the sushi belt, sort them, and then select one signal and emit it as an output. One picks the least common item on the belt, and the second one picks the second least common one, by index.

The final behavior was the most complicated.

Managing asteroid reprocessing

A selector combinator reads the contents of the sushi belt, sorts the signals in descending order, then outputs the first signal. This signal output is the asteroid type that is the most populous on the sushi belt, and the population.

A constant combinator is configured to emit a signal for each asteroid kind, with a value of 1 to ensure that even when there is no asteroid kind on the belt of that type, the selector combinator still sorts the signals correctly

There are a trio of decider combinators that have been programmed where if the count is too large for an asteroid kind, they emit the reprocessing signal for that asteroid kind.

Reprocessing has a 40% chance of producing the same asteroid, then 20% chance of producing the other two types of asteroid piece (2x20%), and then a 20% chance of just crushing it and returning nothing. This accomplishes two goals at once: if the crusher destroys the asteroid completely, a spot is freed up for a new one to be added from the collectors, or that the asteroid is crushed and replaced with an asteroid of a different kind. In the worst case, the same asteroid is returned from the crushing operation and a small amount of buffer space in the sushi belt is consumed (old asteroid + new one from the gate). This will most likely trigger another reprocessing.

But there’s some delicate balancing you have to do in the circuit network, which is what the two decider combinators do in the middle.

Implementing a memory cell

Each game tick, the circuit network sends all the signals, including signals from all the combinators as they do their programming logic. Crushing an asteroid takes multiple game ticks.

Without the two decider combinators, asteroid crushers were getting the signal to start crushing an asteroid, but then a second game tick would occur, and sometimes the signals would change and tell it to crush another asteroid kind, before the first crush had completed. The crusher would empty itself, and then start again. As a result, crushers would start an operation and then get cancelled by the circuit network changing mid-operation.

So, you have to create a memory cell with decider combinators where it remembers the recipe that is being called for, and then a way to clear that memory cell after the crusher has completed a cycle. This is also known as a flip-flop or latch.

Crushers have a circuit network feature where they will send a signal when the current crushing job has completed, and I use that signal as the way to clear the memory cell.

The input to this decider combinator comes in on the green wire, which is connected to the outputs from the decider combinators described in the previous section, that emit the crushing signals.

The combinator is then wired with a red wire, in a loop where the output is connected back into the input of itself. The decider combinator’s output is then wired into the asteroid crusher, and the asteroid crusher is in turn wired into the input side of the decider combinator. The crusher emits the Checkmark signal after a crush cycle as been completed. The decider combinator, in turn emits a signal for which asteroid type to reprocess, as long as Checkmark condition is equal to 0. When the crusher completes a job cycle, the Checkmark condition is set to 1 which then is processed by the combinator, the logic evaluates to false and the output of the combinator is cleared, thereby resetting the memory of the decider combinator itself (via the loop).

Anyway now my spaceship has tons of fuel, correctly crushes asteroid fragments when there’s too many of a certain kind, and I have a huge buffer of stored asteroid fragments that can be fed into the system. This allows Anane to fly between Vulcanus and Fulgora non-stop with no pauses at Nauvis to wait for the Checkmark signal from the safety check circuit.

At this rate, I’ll be able to beat the game in a couple thousand hours!

Bugs

Here’s a funny bug I had in programming my space platform, along the way

Nuclear power death spiral

Originally, my nuclear power control system also took water amounts into account when deciding whether or not to insert nuclear fuel into the reactor.

The decider combinator for controlling fuel insertion into the nuclear reactor had a condition for water storage, that was set far too high. 25K water is a full water storage tank, and this condition was incorrect. I had been worried about putting fuel into the reactor when there wasn’t enough water to boil, but I ended up creating a far worse problem: no power.

At one point, the water level got below 25K and no fuel was being put into the reactor. This caused a death spiral where there was not enough power to do the asteroid processing that would create more water, and the platform eventually ran out of oxidizer and was stuck on Fulgora. I was incredibly lucky that this happened on Fulgora because ice is able to be produced from scrap recycling, so I flew an emergency payload of ice to Anane and built a one-off belt to move the ice from storage and into the water processing part of the platform.

I thought the problem was solved, until it yet again happened over Vulcanus and the death spiral occurred again. I was lucky (yet again!) where the thruster fuel was the resource that ran out first, and I was able to send an emergency payload of carbon from Vulcanus and route it to the thruster fuel processing part of the platform from storage.

Had the conditions been reversed, where Anane ran out of ice around Vulcanus or ran out of carbon around Fulgora, I would have been completely screwed since those planets do not have those resources for emergency shipment.

Removing the condition around water and fixing some bottlenecks in my water production system fixed this death spiral, and subsequent testing has shown that only a minimal amount of water reserve is required to keep the platform powered, since the rate of asteroid processing and production of water now far outweighs the consumption of water by the nuclear reactor, boilers, turbines, and oxidizer production.

Footnotes
  1. Electromagnetic plants have huge productivity bonuses where you get more items manfuactured, for the same amount of inputs which justifies the cost of flying tungsten carbide to Fulgora for production of speed modules. 

  2. Sushi belt is defined as:

    The strategy of mixing many different types of items on transport
    belts to supply machines that need some or all of those items. It sacrifices
    throughput for compactness (and beauty). It looks colorful and diverse like a
    tray of sushi. Its perhaps most popular application is supplying labs with
    science packs. Sometimes called sushi bar or rainbow belt.
    

    https://wiki.factorio.com/Glossary