I'm somewhat new to the game, and I've been playing around with trains. In the past, when I've run up against a UI issue, I've generally googled it and found out that, yes, the thing I wanted was already implemented, and I'd just missed the cue or tutorial that explained how. "Man, it sure would be nice if I could copy paste filter set- oh, I see, I just have to press this button and then this button, huzzah!" Etc etc. And to an extent, that has been the case with trains, such as learning that the textured surface in the GUI can be clicked and dragged to reorder train stops and conditions. However, it does not appear to be the case with nested OR.
TL;DR
I would like to suggest the ability to nest an OR() within an AND() when setting up wait conditions in train stop schedules, in order to greatly reduce the tedium of setting up complex wait conditions.What ?
I would like for train schedules to allow for an OR() nested within an AND(). There's not really any more what to it, other than GUI considerations.This would involve slightly widening the train schedule GUI to allow for a third switch position for the AND/OR operator. With only 2 conditions at a train stop, clicking would rotate between right AND and right OR, as is currently implemented. With 3 or more conditions, clicking would rotate between left OR, middle AND, and right OR.
Additionally, the logic to draw the AND brackets (and also governing AND in general) would need to also treat adjacent right ORs as AND.
Why ?
Now, I understand that Factorio trains currently use DNF to processes AND and OR statements in train stop logic, but I find this extremely tedious to work with. Let me give an example.Let's say I have a train, which goes from location A, built near a number of off-site ore deposits, and picks up iron ore, copper ore, and coal. The train then goes to location B, which is a smelting and manufacturing hub, and offloads the ore. I want the train to only stay at the stations as long as is necessary to offload needed resources. However, in some cases, my mining operation is overproducing a type of ore, or the demand for a particular kind of ore (such as coal, to run steam turbines at night when solar is offline) is variable.
So what I want to do is have the train check one of two conditions for each ore. If, either, the train contains 0 of that ore, or the buffer box that the train loads that type of ore into is full, then the condition for that ore is met. It would look something like:
OR
{
ββββAND
ββββ{
ββββββββOR
ββββββββ{
ββββββββββββItem.Count(Iron Ore = 0)
ββββββββββββCircuit.Condition(Iron Ore >= 800)
ββββββββ}
ββββββββOR
ββββββββ{
ββββββββββββItem.Count(Copper Ore = 0)
ββββββββββββCircuit.Condition(Copper Ore >= 800)
ββββββββ}
ββββββββOR
ββββββββ{
ββββββββββββItem.Count(Coal = 0)
ββββββββββββCircuit.Condition(Coal >= 800)
ββββββββ}
ββββ}
ββββInactivity(15)
ββββTime.Passed(120)
}
However, it is not possible to nest OR within AND. So instead, it looks like this:
OR
{
ββββAND
ββββ{
ββββββββItem.Count(Iron Ore = 0)
ββββββββItem.Count(Copper Ore = 0)
ββββββββItem.Count(Coal = 0)
ββββ}
ββββAND
ββββ{
ββββββββCircuit.Condition(Iron Ore >= 800)
ββββββββItem.Count(Copper Ore = 0)
ββββββββItem.Count(Coal = 0)
ββββ}
ββββ{
ββββββββItem.Count(Iron Ore = 0)
ββββββββCircuit.Condition(Copper Ore >= 800)
ββββββββItem.Count(Coal = 0)
ββββ}
ββββ{
ββββββββItem.Count(Iron Ore = 0)
ββββββββItem.Count(Copper Ore = 0)
ββββββββCircuit.Condition(Coal >= 800)
ββββ}
ββββ{
ββββββββCircuit.Condition(Iron Ore >= 800)
ββββββββCircuit.Condition(Copper Ore >= 800)
ββββββββItem.Count(Coal = 0)
ββββ}
ββββ{
ββββββββCircuit.Condition(Iron Ore >= 800)
ββββββββItem.Count(Copper Ore = 0)
ββββββββCircuit.Condition(Coal >= 800)
ββββ}
ββββ{
ββββββββItem.Count(Iron Ore = 0)
ββββββββCircuit.Condition(Copper Ore >= 800)
ββββββββCircuit.Condition(Coal >= 800)
ββββ}
ββββ{
ββββββββCircuit.Condition(Iron Ore >= 800)
ββββββββCircuit.Condition(Copper Ore >= 800)
ββββββββCircuit.Condition(Coal >= 800)
ββββ}
ββββInactivity(15)
ββββTime.Passed(120)
}
And every item that is being offloaded further increases the complexity. In actuality, I have a train going from an oil hub, picking up plastic, sulfur, solid fuel, batteries, and lubricant (5 items), dropping those off at the manufacturing hub, and in turn picking up iron plates, copper plates, and coal (3 items) from the manufacturing hub to take back to the oil hub for chemical processing. To prevent the train from just always sitting until Time.Passed(120), I need 256 condition lines for the manufacturing hub (2^5 * (5+3)), and 64 condition lines for the oil hub (2^3 * (5+3)).
Now maybe I've somehow missed something. Googling around seemed to confirm that, no, you can't nest an OR within an AND, and yes, if you want to do AND(OR(A,B),OR(C,D)) you actually need to do OR(AND(A,C),AND(A,D),AND(B,C),AND(B,D)), but maybe there is a simpler way to do this. I've only scratched on the surface of the circuit network - I'm using it to check the buffer boxes the train loads, and I've used it previously to disable loading inserters at one train stop if the buffer boxes at the destination are full (before I discovered I could use item filters in the train cars, which was a lot easier), but I've not really played around with the various combinators and the like. But it definitely seems like, to do what I want to do, this is what I have to do.
So I started doing that. I have a relatively passive playstyle, and a lot of the times I'm just letting automated processes run while I talk with friends or watch Youtube or whatever on the side, and then checking to see if there are any problems (like two trains stuck or a shortage of a particular resource or bugs have attacked my perimeter) or if I have the resources to do something fun (usually research, but I'm also currently waiting on uranium processing before starting up nuclear power for the first time). My train going between the oil hub and the main hub has 66 condition lines for the oil hub train stop (+2 for an inactivity and time passed failsafe). And it was mind numbing to put together. What we ended up with was:
OR
{
ββββAND
ββββ{
ββββββββItem.Count(Plastic Bar >= 1000)
ββββββββItem.Count(Sulfur >= 500)
ββββββββItem.Count(Solid Fuel >= 500)
ββββββββItem.Count(Battery >= 2000)
ββββββββItem.Count(Lubricant >= 25000)
ββββββββItem.Count(Iron Plate = 0)
ββββββββItem.Count(Copper Plate = 0)
ββββββββItem.Count(Coal = 0)
ββββ}
ββββAND
ββββ{
ββββββββItem.Count(Plastic Bar >= 1000)
ββββββββItem.Count(Sulfur >= 500)
ββββββββItem.Count(Solid Fuel >= 500)
ββββββββItem.Count(Battery >= 2000)
ββββββββItem.Count(Lubricant >= 25000)
ββββββββCircuit.Condition(Iron Plate >= 1600)
ββββββββItem.Count(Copper Plate = 0)
ββββββββItem.Count(Coal = 0)
ββββ}
ββββ{
ββββββββItem.Count(Plastic Bar >= 1000)
ββββββββItem.Count(Sulfur >= 500)
ββββββββItem.Count(Solid Fuel >= 500)
ββββββββItem.Count(Battery >= 2000)
ββββββββItem.Count(Lubricant >= 25000)
ββββββββItem.Count(Iron Plate = 0)
ββββββββCircuit.Condition(Copper Plate >= 1600)
ββββββββItem.Count(Coal = 0)
ββββ}
ββββ{
ββββββββItem.Count(Plastic Bar >= 1000)
ββββββββItem.Count(Sulfur >= 500)
ββββββββItem.Count(Solid Fuel >= 500)
ββββββββItem.Count(Battery >= 2000)
ββββββββItem.Count(Lubricant >= 25000)
ββββββββItem.Count(Iron Plate = 0)
ββββββββItem.Count(Copper Plate = 0)
ββββββββCircuit.Condition(Coal >= 800)
ββββ}
ββββ{
ββββββββItem.Count(Plastic Bar >= 1000)
ββββββββItem.Count(Sulfur >= 500)
ββββββββItem.Count(Solid Fuel >= 500)
ββββββββItem.Count(Battery >= 2000)
ββββββββItem.Count(Lubricant >= 25000)
ββββββββCircuit.Condition(Iron Plate >= 1600)
ββββββββCircuit.Condition(Copper Plate >= 1600)
ββββββββItem.Count(Coal = 0)
ββββ}
ββββ{
ββββββββItem.Count(Plastic Bar >= 1000)
ββββββββItem.Count(Sulfur >= 500)
ββββββββItem.Count(Solid Fuel >= 500)
ββββββββItem.Count(Battery >= 2000)
ββββββββItem.Count(Lubricant >= 25000)
ββββββββCircuit.Condition(Iron Plate >= 1600)
ββββββββItem.Count(Copper Plate = 0)
ββββββββCircuit.Condition(Coal >= 800)
ββββ}
ββββ{
ββββββββItem.Count(Plastic Bar >= 1000)
ββββββββItem.Count(Sulfur >= 500)
ββββββββItem.Count(Solid Fuel >= 500)
ββββββββItem.Count(Battery >= 2000)
ββββββββItem.Count(Lubricant >= 25000)
ββββββββItem.Count(Iron Plate = 0)
ββββββββCircuit.Condition(Copper Plate >= 1600)
ββββββββCircuit.Condition(Coal >= 800)
ββββ}
ββββ{
ββββββββItem.Count(Plastic Bar >= 1000)
ββββββββItem.Count(Sulfur >= 500)
ββββββββItem.Count(Solid Fuel >= 500)
ββββββββItem.Count(Battery >= 2000)
ββββββββItem.Count(Lubricant >= 25000)
ββββββββCircuit.Condition(Iron Plate >= 1600)
ββββββββCircuit.Condition(Copper Plate >= 1600)
ββββββββCircuit.Condition(Coal >= 800)
ββββ}
ββββInactivity(15)
ββββTime.Passed(120)
}
With nested OR, it would instead look like this:
OR
{
ββββAND
ββββ{
ββββββββItem.Count(Plastic Bar >= 1000)
ββββββββItem.Count(Sulfur >= 500)
ββββββββItem.Count(Solid Fuel >= 500)
ββββββββItem.Count(Battery >= 2000)
ββββββββItem.Count(Lubricant >= 25000)
ββββββββOR
ββββββββ{
ββββββββββββItem.Count(Iron Plate = 0)
ββββββββββββCircuit.Condition(Iron Plate >= 1600)
ββββββββ}
ββββββββOR
ββββββββ{
ββββββββββββItem.Count(Copper Plate = 0)
ββββββββββββCircuit.Condition(Copper Plate >= 1600)
ββββββββ}
ββββββββOR
ββββββββ{
ββββββββββββItem.Count(Coal = 0)
ββββββββββββCircuit.Condition(Coal >= 800)
ββββββββ}
ββββ}
ββββInactivity(15)
ββββTime.Passed(120)
}
This leads to... I don't want to call it a second request, so much as an alternative fix. If implementing nested OR is not possible (or rather, too technically complex to be deemed worth the effort), then I'd really like to extend the shift+right click/shift+left click function to be able to copy and paste wait conditions within a schedule. Using my oil hub example, there are 8 AND strings of 8 lines each, but in each of them, 5 lines, the conditions for the 5 resources being loaded at this site, are always the same. Being able to copy and paste those 5 lines 7 times, rather than having to manually add them every time, would have made the task a lot less tedious. Additionally, while there are 24 variable lines, there are only 6 unique lines, so copy pasting would potentially save a lot of time there as well. It'd certainly make the prospect of doing this for the manufacturing hub much less daunting. That isn't to say that you shouldn't consider implementing this if you do implement nested OR, but I think it would have a lot less utility in that instance.
Anyway, I hope all that makes sense and is correctly formatted, etc.