This project brilliantly applies complex evolutionary algorithms to solve intricate design problems, proving that high-level machine learning has practical utility beyond academic theory. It is a masterclass in using computational intelligence to decode and master the underlying logic of automation.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
A.I. Learns to Optimize Factorio BlueprintsAdded:
Building a blueprint is easy, but building an optimized blueprint, now that's complicated. Take a look at this wonderful little blueprint I've built that makes green circuits. You may notice that it has a bit of character.
But it has the same production as this blueprint, which is much more streamlined. Designing more efficient and organized blueprints take some skill and quite a bit of thought. But let's be honest, doing anything manually in a game about automation feels wrong. So, let's channel the true Factorio spirit and find a way to automate efficient blueprint design.
To automate the design process, we can leverage a form of machine learning known as a genetic algorithm. A genetic algorithm is a search and optimization technique that mimics the process of natural selection, where the fittest individuals are selected to reproduce and pass on their traits to the next generation. Using this idea, we can generate an initial population of blueprints and evaluate their performance using a fitness function.
From there, we will select the top-performing designs to serve as the basis for the next generation. We will create designs for the next generation by selecting from the top performers, combining their trades with one another, and potentially introducing random mutations. We can continue this process until we are satisfied with the results.
Let's take a look at how we can implement this process in Factorio. I've created a script that will set up a little test site for each blueprint in our generation. The size and number of these test sites can be changed according to our optimization parameters. Our blueprints will also need input and output interfaces. So, I've added an infinite chest and loader on the left side for each of the inputs, as well as a bottomless chest and loader on the right side for each output. These are also fully configurable based on what kind of blueprint we want to optimize.
Now that we have our evaluation infrastructure, we just need a way to generate blueprints to create the members of our population. If you watch my last video, you may already know how we will approach this. If you haven't seen it, then you should definitely check it out. I go into more depth behind the concept I'm about to cover here.
The easiest way we can generate a blueprint of a given size is to pick a random entity and a random direction for each cell.
This will work perfectly for entities that occupy a single cell. But when they are larger, we run into a slight issue.
Larger entities cannot be placed if they overlap with existing entities. While technically it is possible for larger entities to be placed if all overlapping cells have nothing in them, it is statistically improbable. The simplest solution I found is to place larger entities before smaller ones. This allows larger entities to be placed, but it does mean some smaller ones will be blocked.
To integrate this into the genetic algorithm, we also need to establish clear mechanics for reproduction and mutation. For reproduction, two designs with high fitness are chosen from the current population to generate an offspring for the next generation.
To create this new design, we can iterate through each cell and select the entity and its orientation from either the first or the second parent. This crossover technique ensures that the new design inherits a functional mix of traits from both parents. To prevent the algorithm from getting stuck in a local optimum, we can slightly mutate the design immediately after reproduction.
We can do this by iterating through each cell and applying a small percentage chance to trigger a random change.
When a mutation occurs, we will either change the entity type or its placement direction to a new random value.
One thing to keep in mind about using a genetic algorithm is that you don't necessarily need to be clever about how you generate traits for each individual, but you do need to be clever about how you evaluate their fitness.
The reason for this is because the algorithm will do the hard work of exploring possibilities and the fitness function will help direct the search towards the desired result. So how can we effectively evaluate our random blueprints? You might think we can let the blueprint process for some time and check how much of our desired product is placed in the output chest. While this is the ideal scenario, it's far from reality when generating completely random blueprints. Let's take a look at a few designs to help us create a better fitness function.
We'll start with a simple iron gear blueprint where iron plate is the only input and iron gears are the desired output. To reduce the search space, we will only allow the following entities: assembly machine, inserter, and transport belt.
As you can see, none of these will produce any iron gears in the output chest.
So, we need to get clever with our fitness function.
What are some of the qualities of these factories that resemble something productive?
Well, for starters, designs with an assembly machine are much more likely to produce something than ones without any.
Same for ones that have inserters, but we can also give them a boost if they are picking up or dropping off to a transport belt or assembly machine.
Additionally, we can give higher value to any assembly machine or belt with an iron gear in its inventory.
While not perfect, these simple qualities will help our fitness function select designs that have a higher potential for production.
All right, let's see some optimal iron gear blueprints.
Well, I feel like we're getting somewhere, but it didn't quite achieve the perfectly optimal blueprint I had in mind.
I let this run for a total of 464 generations at 1,024 blueprints per generation.
It seems as though we've hit a local minimum in the optimization process.
As you can see, it eventually got an assembly machine producing iron gears, but didn't get any into the output chest.
Subsequent generations over selected this suboptimal design and wasn't able to find anything better.
It was eventually able to manage getting some iron gears into the output chest.
However, it did not improve the design much after that. It seems as though we need a better way to generate blueprints that actually produce something. But before we get into more complicated generation techniques, let's take a moment to relax with another project I've been working on, Leaf Blower Simulator. This is a cozy online co-op game where you blow leaves around to clean up the environment. It's currently in early access on Steam with lots of new features and content coming in the future updates. There's a free demo available right now if you want to try it out with some friends. I'll leave a link in the description and if you enjoy it, please consider wish listing. It really goes a long way.
Also, feel free to leave some feedback.
I'm looking to improve the game in every way I can.
Also, if you're enjoying the video so far, consider subscribing. I have many more videos planned that you won't want to miss.
Now, let's get back to optimizing some blueprints.
So, we need to find a way to cut out the useless noise in our blueprints.
Ideally, we would be able to generate designs that have no wasted entities or flaws. Then, we would be able to optimize solely on the amount of production and the cost to build. Well, we are in luck. There's an algorithm that can do all of this called wave function collapse.
Wave function collapse is a procedural generation algorithm that can create complex patterns based on a predefined rule set and set of constraints.
The algorithm is best illustrated by a simple example. Say we have a map that is defined by a grid and we want to fill it with either land, coast, or sea tiles.
We can define rules for each of the tiles based on their adjacency to each other.
For land, we will say it can be adjacent to land on all sides, coast only on the left, right, and bottom, and not adjacent to sea at all.
Coast can be adjacent to land or sea on the left and right sides, only land above, and only sea below.
And sea has a similar rule set to land, but effectively the opposite.
This is all we need to run the wave function collapse algorithm to generate our map.
We begin with every cell in the map being in a superposition of every type of tile.
Then, we select the cell with the lowest entropy, which is a measure of uncertainty.
So, we will select the cell with the fewest tile options. In this case, they all have the same entropy, so we can pick a random cell and collapse it.
Meaning to select a tile from its possibilities. Let's choose coast for this cell. Once we collapse a cell, we need to update the surrounding cells according to our rule set. We know only a land tile can exist above a coast tile. And same for below with a sea tile.
For the sides, coast tiles cannot be next to another coast tile. So, we can remove that possibility from each. This will propagate out for any cells that have their possibilities changed and will continue until there's no more changes.
We've just finished the first collapse and now we will continue selecting the lowest entropy cell and collapsing until the entire map is complete. We can apply this same idea to Factorio since it is heavily reliant on adjacency rules.
Let's start first with belts since they are the most useful entity for moving items around. In the simplest case, we want belts to connect to each other in a straight line. So, we can define an east belt tile with the rules that an east belt can be placed to the left and to the right. Let's also add an empty tile, which means nothing will be placed in that cell. And we'll say that can go above and below the belt.
By creating a blueprint grid with these tiles as possibilities, we can collapse into numerous straight belts.
Now things get a little more difficult.
Turning the belt is not as simple as just defining an up and down belt that can be placed to the right of our east belt. Doing so would create some slop in the belt network since those belts can be connected from other directions.
We need to explicitly define each way that a belt can turn.
To turn upwards, we need to define a belt whose input is on the left and output above. We also need a belt that can accept items from below and output to the right. Similarly, we can define tiles for turning the belt downward.
Once we populate their adjacency rules to keep the belts connected, we can run the wave function collapse algorithm to see a more interesting belt network.
This is the basis of our belt network, and if we expand our tile definitions to include all four directions, we can [clears throat] get results that look like this.
When defining these rules, it's important to keep in mind that the wave function collapse algorithm does not know anything about Factorio or what we're trying to accomplish. It's only following the rules we give it. So, yes, these generations are correct according to our rules. We just need to be more specific.
What's not specific enough about what we've defined so far?
Well, for starters, there's no clear goal with what we're generating. There's no purpose for the belt to exist at all.
So, let's add back in the input and output interfaces from the iron gear blueprint.
Now, we have a more well-defined purpose.
Ideally, we want the input belt to start at the input interface, and we want the output belt to end at the output interface. Where the input belt stops and where the output belt begins does not matter, so we can add this into our rules.
We can first add a resource type to each belt tile to know what they carry. Using this, we can identify if a belt tile is an input belt or an output belt.
Now, we can add a step to our wave function collapse algorithm.
When collapsing a cell, we can check if the selected tile has any additional constraints and apply them to adjacent cells.
We can create an input belt constraint that will ensure the input side of the belt is connected to another input belt.
Similarly, we can create an output belt constraint to ensure the output side of that belt is connected to another output belt.
Using these additional constraints, our generations now look like this.
I'm glossing over a few other constraints I added to make it look this pretty, including one to prevent side loading as well as full loops.
But now, if we set the input and output to the same item, we've just made a very inefficient way to find the shortest path between two points.
Now let's try to add some production.
You may have been thinking, how can an assembler, which occupies a 3x3 space, be represented by a single tile?
Well, it's as simple as slicing the assembler up into single-cell pieces and defining special rules that will only allow for the pieces to be connected to one another.
When one piece of it is collapsed, the algorithm will propagate out eliminating any tiles other than the ones that create the assembler.
And finally, we get to inserters.
They can technically be placed next to any other entity, but since we want optimal results, we can define constraints to make sure they are useful.
We first will create an inserter tile for each item that can be moved around.
Their allowed rules will be populated with every other tile that satisfies its pickup and drop-off constraints.
A pickup constraint says inserters must be able to pick up the item they move.
So, the adjacent cell should provide that item. For instance, a transport belt carrying that item or the output of an assembly machine. Similarly, a drop-off constraint says inserters must be able to drop off any item they pick up. So, the adjacent cell should accept that item. For instance, a transport belt or the input of an assembly machine.
So, when we collapse a cell into an inserter, we must prune the invalid possibilities.
Now, what we've defined so far is still not enough to guarantee a productive blueprint. While we've outlined the rules for production, there's no guarantee an assembly machine or inserter will be placed. Oftentimes, applying the rules and constraints will back itself into a corner until the only thing left to pick is an empty tile.
Thankfully, we can apply even more constraints.
We can apply another form of constraint that happens on a global level instead of just for adjacent cells. These global constraints will be applied after every cell collapse to ensure our blueprint will be productive. I've applied global constraints to guarantee there's at least one assembly machine and that there are inserters to input each ingredient for the recipe as well as an inserter to remove the output. Finally, we have productive blueprints and we can simplify our fitness function to minimize the cost and maximize production in the output chest.
Before we can run our genetic algorithm to optimize our blueprints, we need to redefine what it means to reproduce and mutate. Each individual is not defined by cells of entities and directions anymore. They are defined by cells of tile possibilities.
One thing to note is that I've changed the collapse procedure to always pick the first remaining tile in a cell's possibilities to make the algorithm more deterministic. By altering the order of each cell's tile possibilities, we can reintroduce randomness that will give us something to pass on to the next generation. So, in reproducing, we will iterate through the grid and select the tile possibility ordering from one of the parents. And for mutations, we can have a small chance to reorder a particular cell's tile possibility list.
Now, let's see the optimization progress for an iron gear blueprint.
You can see the wave function collapse algorithm introduces a lot of variation amongst similar individuals. This is to be expected since changing what tile is selected for a single cell can have rippling effects further away. While it wasn't able to perfectly optimize the blueprint, I'm still impressed it was able to fit two working assembly machines in such a small space.
Let's try something a bit more complicated. Green circuits with the inputs of iron plate and copper cable.
Well, this one is taking much longer to compute than the last ones. Let's see what's going on here.
Here are some of the statistics of each of the blueprints we've tried so far.
I've even added the more typical green circuit blueprint with inputs of iron plate and copper plate. As the blueprint gets more complex, there are more tiles and it takes longer on average to generate. The wave function collapse algorithm is already not computationally efficient and we've also introduced many constraints which slows down computation even more.
Constraints increase the potential of backtracking and overall failure to generate.
All of these delays make for very slow generation evaluation which leads to much less coverage of the search space in a reasonable amount of time.
Overall, I think this project has been a success. We were able to generate various working blueprints and this can be expanded to work with all entities and eventually all different production lines.
I would like to look more into speeding up the algorithm, potentially using a compute cluster. So, let me know in the comments if you have any ideas or if you'd like to see more on this topic.
A lot of time and effort goes into creating videos like these and since you're still here, I'll give you a little sneak peek at some of my next projects. My goal is to work towards creating a fully autonomous bot to play Factorio and beat the game.
If that sounds interesting to you, then consider subscribing because those videos will be out soon.
Thank you so much for watching.
Related Videos
OpenHuman VS Hermes AI: Who Wins?
JulianGoldieSEO
285 viewsโข2026-05-29
Long-Running Agents โ Build an Agent That Never Forgets with Google ADK
suryakunju
142 viewsโข2026-05-30
This computer is made from real human brain cells. And you can buy it.
Talktmsmedia
3K viewsโข2026-05-28
BREAKING: Microsoftโs New Image Generating Model Beat Out GPT 1.5 and Nano Banana 2
aimmediahouse
122 viewsโข2026-06-03
I Made the Same Anime Fight Scene in Every AI Video Generator
NobleGooseAnime
295 viewsโข2026-05-30
Nvidia Bets Big On AI PCs | New Chip To Power Windows Laptops | Technology | AI Updates | N18S
cnnnews18
3K viewsโข2026-06-01
I Tested NEW Opus 4.8 on Four Projects (Updated LLM Leaderboard)
AICodingDaily
298 viewsโข2026-05-29
3D Platformer Update - NO CAPES
SolarLune
294 viewsโข2026-05-30











