First of all, what is the problem?
Currently, inserter's stack size is not configurable to all, so you cannot be sure that inserter will put exact amount needed items into the furnace. As a result, furnace will occasionally stuck with several iron plates inside and preventing other items smelting.
Theoretical solutions:
There are two possible solutions for this problem:
1) inserting exact amount of items for each recipe.
2) or inserting extra items, in order to complete incomplete recipe.
Second solution is the solution of this post.
Goals:
Initially, I decided to create belt-based Smart Furnace with the highest possible efficiency (I am talking about beacons), but later I found that robot-based version is almost identical and even a little bit easier in designing.
In order to achieve highest efficiency I've chosen sandwich design: one line full of furnaces, one line full of beacons, and again from the beginning.
Designing:
Because extra logic should be located somewhere far away from furnaces, we need to provide a sufficient data from these furnaces. So, I came to a 3 combinators version: first combinator is used to send orders from the controller (item type for smelting), second combinator sends back amount of inserted items, and third combinator is used to read input storage buffer.
- we can read all output chests from all furnace blocks at the same time (without extra combinators, just an extra wire), and check is it possible to fit this value in a single chest. If this is possible then we have a strong guarantee that output buffer in each furnace chest has enough free space.
- in the same way we can solve this problem with input buffer: let's say that requester chest requests 400 iron ore, then we can read all input chests and check if this value is bigger than "(requested value in requester chest + items that may be accidentally delivered by robots) * (num chests - 1)", in our case: (400+3)*(2 - 1) = 403 items. But this value doesn't guarantee that we have enough items inside 4-th chest for smelting, so we need to slightly increase this value (details you will find below).
Controller:
Our controller should be able to process up to 200 (amount of unique signals) different furnace blocks at the same time, so we should minimize usage of loop-based solution, and use only "Each" operation. Basically controller does next things for each furnace block:
- store current smelting item type
- receive information about amount of inserted items, and check is current recipe complete
- If previous recipe is fully completed controller selects new item type using information about available resources in each block and required items
- also, it guarantees that item type cannot be changed unless recipe is completed
"Desired items" - 2 iron ore and 1 copper ore. This means we want to have 2 furnace blocks processing iron ore, and 1 furnace block should process copper ore, other furnaces should sleep. This logic may vary from player to player, someone prefer to smelt everything which is possible, others - to not waste energy.
In particular, this logic unit has two minor issues related to bounding between "desired items" and furnace blocks:
1) if "desired items" 2 iron ore, then first and second furnace block will try to process iron ore, and if they don't have enough iron ore inside they will wait.
2) if previously first and second furnace block was associated with stone, third one with iron ore, and fourth one with copper ore (2-1-1-0 configuration), and we change desired items to 1-1-2-0 then second furnace block will be switched from stone to iron ore, and third furnace block will be switched from iron ore to copper ore. As you can see this is not optimal, so this user-defined logic unit may be improved in future...
Controller in action:
Here I will describe different situation with different stack sizes and how controller reacts on them.
New item type selection happens at the end of each example.
Inserter capacity 1:
- Iron/copper ore: 1 ore will be inserted in furnace, 1 output
- Steel: 1 iron plate will be inserted 5 times, 1 output
- Stone: 1 stone will be inserted 2 times, 1 output
Inserter capacity 2:
- Iron/copper ore: 2 ore will be inserted in furnace, 2 output
- Steel: 2 iron plates will be inserted 5 times, 2 output
- Stone: 2 stones will be inserted 1 times, 1 output
Inserter capacity 3:
- Iron/copper ore: 3 ore will be inserted in furnace, 3 output
- Steel: 3 iron plates will be inserted 5 times, 3 output
- Stone: 3 stones will be inserted 2 times, 3 output
And one exotic example (inserter capacity was upgraded from 1 to 2 while smart furnace had 4 iron plates inside)
4 iron plates + 2 new iron plates => 1 steel will be produced, 1 remaining item.
1 + 2 new iron plates + 2 new iron plates => 1 steel, and new item selection
Controller is designed to handle these cases correctly.
It is important to mention that inserters don't wait extra ticks for the controller response, because each furnace know what item type it should produce after current one. Also, 8 ticks are needed to update controller and this is less than inserter's half-rotation.
Various analyzes:
This part was added to explain important details/properties/possible issues with this Smart Furnace. Warning! Math below.
Finally, if you've read to this place you deserve to see this build in action.
For testing purposes I am using two different requests: stone and steel.
At the beginning all 9 furnace blocks should process only stone, each X-th tick we will add additional steel block and remove stone block. After 9 steel blocks we will move back in the same way.
Productivity graph (X = 800 ticks):
Next step is to build belt-based smart furnace, looks like it will be almost identical, but with several minor differences.
Original thresholds formula is:
(requested value in requester chest + items that may be accidentally delivered by robots) * (num chests - 1) + (Least common multiple of "inserter stack size" and "recipe size") * num inserters per chest * 3.
Why 3? because first value is necessary to ensure that we have enough items for recipe, second may be used during upgrading to higher stack size, and third may be used on the low energy (because combinator may delay stop signal from the controller).