Somewhere on the list of "Obvious Combinator Applications", one can surely find "Smart Furnace Control Circuit". And this is one where combinators can definitely do a better job of it. So today I finally took a crack at it.
I've always been unsatisfied with smart furnace designs. The control circuit idea seemed to add nothing that you couldn't do simply by directly using logistics net storage values on the smart inserters instead of number of pickaxes, science packs, or other token items. With or without a control circuit, all the designs I've seen had particular limitations: If you need a ton of both iron and copper smelted, the division of labor breaks down and it tries to load both ores into all furnaces. And if you want to expand the smart furnace, you have to either extend existing rows (not necessarily ideal) or you have to re-assign the threshold values to half of the inserters on all the existing rows, no matter which end you expand from.
(The row that runs when you need any amount of iron only runs when you need a large amount of copper, and vice versa. When adding another 10 rows to a 10 row furnace, you can leave iron ore running when less than 1 to 10 iron picks or 1000 to 10,000 iron plates are in the system, and add rows that run when less than 11 to 20 picks or 11,000 to 20,000 iron plates are in the system, and having the last added row run when 1 science pack or 1000 copper plates are in the system, counting upward back in the other direction, but then you have to renumber the first ten rows for 11 to 20 science packs or 11k to 20k copper plates.)
Combinators can solve both of these problems.
While the fact that you have to wire up the storage chests does mean that you can't read the entire logistics network, not relying on the logistics system for your counting does have benefits as well as drawbacks. And it's not too hard to wire up the output passive providers while you're wiring up the inserters anyway. It's even easier to wire up an array of storage chests if you prefer active providers.
The biggest benefit is that you aren't forced to use logistics bots. I'm currently working on a belt-fed smart furnace layout which I plan to post screenshots of once complete. The input and output will both be via train, and the idea is that whatever amount a train takes away out of the loading buffer chests will get quickly replaced, regardless of which type of plate was shipped out (as long as sufficient ore is present on the input buffer and ore belts).
Another benefit is that you can set up a wired smart furnace like this long before you finish all the research for logistics bots, much less build a logistics network with enough roboports, bots, and power to handle the input and output requirements of any smart furnace large enough to be useful.
But we're here for the combinators, and that's the part that I've just completed work on!
Imgur Album
The images and their descriptions in the album have the details of wiring and configuration, but to understand what's going on I'd recommend reading the explanation below.
The desired logic for optimal smart furnace control uses the following math, in simplest form:
IronNeeded = IronStored - IronDesired
CopperNeeded = CopperStored - CopperDesired
Divisor = IronNeeded + CopperNeeded
IronRows = FurnaceRows * IronNeeded / Divisor
CopperRows = FurnaceRows * CopperNeeded / Divisor
FurnaceRows, IronDesired, and CopperDesired will be set as constants. IronStored and CopperStored will be read from storage. The rest will be calculated. Ideally, we should avoid a divide by zero condition when no iron or copper needs to be smelted. And we also want our output signals to be readable in such a way that we can simply number our furnace rows from 1 to N and set both the copper and iron input conditions to match the row number. With combinators, that's a simple one-step calculation after everything else is done!
Additionally, because doing division with combinators always rounds down, we need to add in another step to finesse the numbers so it will effectively round to the nearest integer instead. This can often done by adding 0.5 before rounding, but combinators can't handle fractions. We can work around this by adding half of the divisor to the numerator before performing the division, which has the same effect. Taking all that into account, the first three lines remain the same, and the rest becomes:
If Divisor < 1, Add 1
RoundingFactor = Divisor / 2
IronRows = (RoundingFactor + FurnaceRows * IronNeeded) / Divisor
CopperRows = (RoundingFactor + FurnaceRows * CopperNeeded) / Divisor
IronControl = IronRows + 1
CopperControl = FurnaceRows - CopperRows
I'll transmit the IronControl value on Signal A, and CopperControl on Signal B. (You could use different signal choices, but I'd recommend not using an item type for these, especially not iron and copper, because any quantity of that item somehow making its way into the wired-up storage area would interfere.)
The final math step done for each of these control signals allows for very easy smart inserter configuration, both when initially building and when expanding the smart furnace, and no reconfiguration of old rows will ever be required. The first row is set to load iron when A > 1, and copper when B < 1. Row 2 loads iron when A > 2, and copper when B < 2. Row 3: A > 3, B < 3. And so on.
Additionally, thanks to all that math, there should (theoretically) never be a situation in which both inserters are allowed to load different ores simultaneously into the same row - but even if there is, it will only affect a single row and only for extremely precise ratios of copper to iron in storage, so the situation would be very fleeting.