ptx0 wrote: Sun Feb 16, 2020 10:23 pm
it's not that big of a computational leap either, the train pathfinder is already iterating serially through each possible segment in the list, it just now must check (as it did at one time before) whether the next block would be already occupied by itself. the block IDs are the same and it would be as simple as saying "if current_block_id === next_block_id".
Simply saying "just check if block ids are same" is not problem solving. First of all: train pathfinder gets its performance because of
optimal substructure. This means that when pathfinder goes through nodes, if node is already expanded, it will never be expanded again because that would mean there was shorter path after expansion, that would mean there is priority queue implementation issue or there is negative weight somewhere. None of these apply here. Since every node will be expanded at most once, pathfinder is not allowed to "back off" some amount of nodes.
- 81140-rail-nodes.png (134.28 KiB) Viewed 4249 times
Here if path goes from left of node 1, when node 1 is expanded, nodes 2 and 3 are added to open set and their current cost from start is set. Node 2 is processed next, this adds node 4 into open set with cost set, node 2 is closed. Next is node 3: when expanding it could update node 4 but cost by this path is higher, node 3 is closed. Next goes node 4 - if it would be the final node (train stop at the end), path would be reconstructed based of information from which node path came from (4 from 2, 2 from 1, 1 from start). There is no good (by performance) place to add check if current nodes block was already visited. It would require visiting whole cameFrom history of nodes when expanding every node that would be CPU expensive, or for every node would require keeping set of all blocks that were visited so far, that would be memory expensive. And that information would be useless because now trains would be prevented from choosing any path that would contain same block twice, even if train could not collide with itself. There is also no shortcut of "lets check if given block was already visited" because this would make every junction broken as expanding one leg would prevent other leg from being expanded.
Lets say we solved above issue and we found a way to detect during nodes expansion which nodes should not be expanded because train would collide with itself. In above sketch, lets assume segment under node 1 crosses somewhere with segments under node 4. Train is long enough that when path goes through node 2, train will collide with itself but when going through node 3, it will pass without a collision. So now when expanding node 4, your check would say "do not go that way, there would be a collision" and pathfinder would either return "no path" (wrong, since there exists path through node 3), or would be forced to reevaluate already closed nodes (node 4 but going from node 3). That would mean performance of pathfinder would drop a lot and for every rail segment there would be a lot more nodes to expand (every node would be related to another history of decisions, so there would be node 4a - for path going from node 2 - and 4b
- for path going from node 3) and this amount could increase a lot in case of multiple paths of same cost in a cascade.
Another problem to solve would be how to decide if train will fit on a given path. By simply taking length of train you will be off when train goes through curves since joint distances are not counted along rails. There would be also need to check at which distance rail segments would collide and how to handle cases where 2 rails would collide with each other multiple times. Doing perfect train movement simulation would be CPU expensive.
Lets say another approach would be taken: Make it impossible for a train to pass a red signal (even when trains are not interested in signals, they are interested in blocks and their reservations, signals are only artifacts that are computed based of blocks state - that would be in fact "prevent train from entering a new block that is already occupied, even if it is occupied by itself"). In case of path that would go through one block multiple times, train would have to slow before signal that goes to that block for the second time since braking point would not be able to pass that signal as block could still be occupied by back of that train. What if all signals in between would be rail chain signals? Should train be allowed to stop in the middle of intersection? That would be a bug since trains that enters chain signal section should be able to leave (that is it reserves all necessary blocks or none of them). Or should it be prevented from acquiring reservation for whole chain signal section? that would again require trains length that would not be exact, or whole trains movement simulation that would be CPU expensive.
Another issue: Trains reserve signals in advance based on its braking distance. What if that braking distance would require block's reservation twice (train is going fast or has slow deceleration) when train is not yet inside that block? That is, there would be something like "Train -- block a -- block b -- block a --> braking distance". To prevent this from happening, braking point would be not allowed to reserve "block a" for second time and whole "multiple reservations" solution could be thrown away through a window.
ptx0 wrote: Mon Feb 17, 2020 12:58 am
your tone when approaching this issue leaves much to be desired, considering you aren't even a developer, please, go away.
*cough*
ptx0 wrote: Mon Feb 17, 2020 7:34 am
wut? because the pathfinder would decide whether the path were valid in the early phase and not send a train somewhere it can't go.
But i will not be changing pathfinder as to prevent them from colliding since pathfinder works under assumption of 0-length train and collisions when happen, are quite funny