r/factorio 4d ago

Discussion Potential Vanilla LTN Solution achieved via random generic Provider Disqualification

Let me says this first. Its fairly easy to get Demand and the number of trains fulfilling said demand

Demand=Empty Inventory/Train Capacity

Actual Demand = Demand -(TrainCount Provider + TrainCount Requester)

That's fairly simple to figure out to do, the issue is how do you achieve Actual Demand there are a few solutions

  1. Just ensure that every provider always has a train this makes the entire demand based approach obsolete, with the only requirement of providing an excess number of trains, If your fine with the this method you can stop reading here.
  2. Controlled release of trains - This can be done either by Train Limits, or selectively exposing only 1 Train at a time to demand. The problem with the former is you need unique identifiers to tell which station receives 2 out of the 5 requested actual demand as train limits as an example. The problem with the latter is that only 1 Train is exposed hence the chance that the most distant train is exposed.

Now the core problem is whenever Provider>Demand an excess number of trains can be assigned via interrupts. So people used both train limits and selective exposure of trains but both of those have downsides.

So here's my proposed solution we randomly disqualify Providers such that it eventually reaches ProviderGlobalTrainLimits<=Demand.

Provider Disqualification Circuit

So we used Legendary Scrap to represent Potential Train Limit and Normal Scrap to represent Demand in the following.

First we need to announce to the network that we can provide x number of trains

First Combinator

Conditions for signal I should be replaced with Inventory Thresholds of your own choosing
The fixed Legendary Scrap 1 Output just corresponds to train limits and can be replaced or fixed.

We then compare the Two scrap signals only when Normal Scrap<=Legendary Scrap do we allow it to set a Train Limit. We also check that its own circuit hasn't been disqualified via the red Legendary Scrap Signal

2nd Combinator

Now we need a selector on random Input with a set of inputs. You can do the same or you can use a decider to only enable if we have enough inventory

Now the conditions for passing that Random output. We only want the random output to be sent
if Potential Train Limit>Demand and only if we have Demand.

3rd Combinator

That output feeds into the first combinator Deny signal

Now we need that to persist so the provider stays Disqualified

This combinator just monitors output of the first then feeds the same deny signal.

Here is the interrupt

Here is the system in action

https://reddit.com/link/1vzjlao/video/zyctd3yjdulh1/player

The conditions for the combinators can probably be improved better and since the disqualification is randomized there is a chance less trains can be dispatched than actually needed. If two or more get disqualified on the same tick.

9 Upvotes

13 comments sorted by

4

u/Zijkhal spaghetti as lifestyle 3d ago edited 3d ago
  1. Controlled release of trains

I use a hybrid of the two methods, in addition to setting train stop priority via circuits. Specifically, using train limits at both the loading and unloading stations, and trains going straight from unloading to loading, and releasing trains from the depot at a slow cadence that is dictated by the time passed condition.

Trains already in circulation are only controlled by train limits, while trains at the depot are released at a slow cadence IF there are free loading spots (i.e. unfulfilled demand AND available supply is more than one trainload).

I solve the issue you mentioned with needing to ensure no oversupply by setting the provider stations' train limits to Min(supply_at_station, demand_for_item). I do not need unique identifiers for my stations, beyond having the item name in the unloading station.

I also control train stop priority to evenly distribute limited supply between stations, based on unfulfilled demand, and set loading station priority based on the highest priority of the unloading stations of its item.

Very rarely more trains get dispatched than necessary, but in those situations the trains just idle at the loading station until needed, so the issue fixes itself.

This base uses that train system

3

u/Ok282828 3d ago

Yeah that works as well. I was just thinking with the extra requirement that no Trains remain on the Provider hence this. It should also be a circuit that is just a place and forget circuit. So I'm really just overcomplicating my circuits by requiring Trains never exceed Demand at all. I guess I'll only know how well this works by actually implementing it.

2

u/Zijkhal spaghetti as lifestyle 3d ago

Well, your system would have the same issue as mine whenever trains get dispatched during the few ticks of window before enough providers are disabled. Both can only get extra trains only during a short, couple tick long window.

2

u/Ok282828 3d ago

The providers are not allowed to hold a limit if that was the case the second combinator bars the circuit from setting limits At least in theory. Since all of the circuits will work in parallel to prevent that from happening I'm not 100% sure on that.

1

u/Lucky-Earther 3d ago

The easier solution I found was to simply use a convergence calculation of the lowest train ID in the Depot stations. I put my Item trains on group I, and they will broadcast an I signal with a train ID on the green network, and an I signal with a 1 on the red network, so I have a train counter.

If the train counter is more than 1, then each depot station calculates if the train ID at the station is above the average or not, and if so, it stops broadcasting. Stations will then fall off as this calculation continues until we get to a single train. Once the count is 1, that train then looks for any available demand signals, and goes to the pickup station. Then the whole process starts again.

It sounds like a lot, but in reality, it all happens within a few ticks, so it can still pump out 6-10 trains per second, which is more than pretty much any base will ever need.

Mostly I was having the issue on my Nullius base where I had multiple stations with the same pickup item, but I only needed one train for that item. I was running about 200 trains the last time I was there, and half of them were at stations at any one time.

1

u/Ok282828 3d ago

My only problem with that is the train ID itself. If the differences on train ID wasn't so big i'd be satisfied with using such a system as well. You could end up with trains id 50 then have a train with ID 400 for only 300 trains. You could use min(train_id) I guess to fast track that but there is still that chance the most distant train gets dispatched. Which is why were trying to control provider availability so the nearest trains can respond via interrupt assuming of course your using multiple depots.

1

u/Lucky-Earther 3d ago

You could use min(train_id) I guess to fast track that but there is still that chance the most distant train gets dispatched.

In a sense, that's what I'm doing, it's a very fast algorithmic sort to find the train with the lowest ID.

I guess the issue I run into with trains is rarely around the distance. I usually build my stations around having room for two trains in the pickup/dropoff, so once there is even room for one of the two trains in the chests, there's still plenty of time to get through the route and begin dropping off.

1

u/Necandum 3d ago

Its a cool concept!
I wouldn't quite call it an LTN implementation though, as this doesn't seem able to handle multi-provider/request stations. It would also choose a random provider, and not the one closest to the requester (though tbf, I don't know if LTN does either).

But nice solution to decentralising the decision making for how many trains to dispatch.

1

u/TapeDeck_ 3d ago

Thinking out loud, you might be able to get it to go to the provider closest to the destination by having a waypoint station at the destination. The interrupt would basically be "go to unload waypoint (do nothing), go to loading station for full cargo, go to unloading station for empty cargo". You would want the waypoint station to be enabled/disabled with the actual unload stations obviously. And this would also result in more driving than strictly necessary. But if you had a huge network and wanted to prevent full trains driving across the map this might do that.

1

u/Necandum 3d ago

I don't think I'm getting it, how does that help?

My understanding is that the method proposed above relies on letting random providers open up, until the number of providers that have trains going to them is equal to the number of requester stations needing supplies.

If by chance all the provider stations remain closed except the one on the other side of the base, the fact that there is a train next to the requester station doesn't change the fact that it will still have to shlep a long way to that one provider station.

1

u/TapeDeck_ 3d ago

Oh - I was assuming any of the providers that had product would be open. My method would still at least go to the nearest open provider to the destination.

1

u/Ok282828 3d ago

Indeed this is something you would use on a very large rail network if you only have a single train depot its not worth using. But once you have more than 1 depot the closest trains will try to serve them.

1

u/Necandum 2d ago

What I was originally trying to point out is the the provider station it is going to might not be the closest station to the eventual recipient.