Goals:
- Load exact amount of multiple item types, no matter which chest holds which items.
- Use all 12 possible inserter locations (single cargo wagon assumed for now).
- Have each inserter running at max speed, moving the maximum possible stack size based on contents of its source chest.
- Queue up items for next train while the current train is loading (or at least ensure this can be done in future).
- Do *not* supply the train via bots; that would be too easy.
- When there are only a few items left to transfer, inserters may skip their turn (due to having precalculated the wrong stack size); so the throughput won't quite reach the theoretical maximum.
Describing how it works in detail (maybe too much detail)
https://youtu.be/d90H9KUAMUg
Logic of Each Section
- Memory cell containing number of requested items to be loaded, decreased during the loading process.
- Left box limits values from A to the range [1-12], passes this onto the F wire. Right box simply passes values from A onto the G wire.
- Train arrival starts a 26-tick clock. Each inserter has a unique circuit signal, and these are triggered sequentially two ticks apart. (`A`, None, `B`, None, `C`, None, `D`, None, etc.) 12 inserters * 2 ticks each = 24 ticks, so not every timeslot is filled. These signals are sent with the value -2^30-1, or -1073741825. (one more than half-way to `min_i32`)
- Check what resources are available in this chest. Resources present are all output as the same value, 2^30.
- (This logic is repeated for each chest-inserter pair.)
- (F1) - Increment/decrement logic used to determine what stack size should be used for this inserter. Uses resource counts from the F wire (written by B logic), and only considers resource counts where the resources are in the chest as read by B. Increments/decrements a signal that's specific to this chest-inserter pair. Can only increment/decrement by +1/-1 per tick, so this value on it's own might be outdated by the time it's read (this is handled by later logic).
- (F2) - Stores increment/decrement values for each chest-inserter pair, and injects some constants needed by F1. Also carefully ignores values from B as they are passed along the F wire to F1.
- Combines clock signals from C with stack size signals from F2 and resources-required signals from B; and passes these on to H for each chest-insterter pair. Resources-required signals here may also be decreased by just-moved signals coming from I.
- Outputs a very-positive value (close to MAX_i32) for each resource signal when:
- Clock value indicates it's this inserter's turn to fire. (`-2^30-1`)
- Resource type is needed, as read from G. (`-count`)
- Resource type is present in the chest as indicated by D. (`-2^30`)
- Computed stack size is equal or less than the number of this resource required. (`+stack_size`)
- The signal from H indicates which resources can be picked up. However, we don't want to do this if the previous inserter just grabbed a resource, and this inserter also grabbing the same resource would cause too many to be added to the train.
In the same tick that signals arrive from H, the previously-activated inserter will pulse what it's just picked up. The resource values from H are close to MAX_i32, so the previous inserter picking up a particular resource can cause this value to overflow, disabling this filter, and causing the insterter to try and grab something else instead.
Also note that the computed stack size doesn't come via H, but instead comes to from F2 via I. - Items picked up by each inserter will need to reduce subsequent insertions. Insertion hand pulses are propagated back out to A, while making sure every step of the computation involving the resource-needed count is updated along the way.
P.S. - I deliberately avoided checking whether someone's solved this problem already; way more fun to have a go at solving it myself. I think it's probably time to go see what exists out there already...