Pre-boarding bug?


In the first image, you can see a triangle station with a count down timer… a nearly empty train has just left for the star station, but many star passengers were left behind. Often this scenario comes up, and later arriving trains pick up the slack, almost as if they were preboarded for a later train. (You can see in image 1, an orange train is just loading passengers that could have been taken by the green train.)

Very irritatingly, the second image shows the count down timer still threatening after the orange train leaves. Had the green train taken all the star passengers, most of those queued plus passengers at the triangle station would be on their way.

I think when a train is loading, it should always take as many passengers as possible – that seems more true to how transit systems work.


It’s the way pathfinding in MM works. The passengers take what the system thinks is the quickest route. So that may not have been by taking that train. They won’t pick up passengers if the system has deemed another train that is imminently arriving to be the better option.


I agree, algorithms can be very smart… But they have their limitations … This MM algorithm fortifies the countdown timer… The only way to recover is to release the lines and then dispatch the train. The operators are getting restless … It is time to revolt against the machine.


Sounds like a lot of work


It seems the release line that is cancelled is the problem here, the precalculated path of that train was not faster, it turned the moment you canceled the forthgoing path, so did not load for the star station.

Find it a weird level setup anyhow :stuck_out_tongue:


I don’t understand your message – what “forthgoing path” did I cancel? I didn’t know I could cancel things?

The green line was dispatched to clear the count down timer. But the algorithm blocked it from loading stars. Simple as that. All I did was hit pause and took screen shots while this was going on.

re: your comments about weird. Huh? Does that have something to do with this?


Here you see the “old” green line direction.

The path for the train was most probably leaving station that way, so at that moment the stars did not enter the train. So, when you cancelled the track, it left station to the next station, that happened to be the STAR station and not the ROUND station, so it left without extra stars as passengers since it was just turning and already finished it’s pickup fase.


I see and understand what you’re saying about the “cancelled green” line. tx for the explanation.

In this episode, the green line is always between just one station pair – so I would have cancelled all of green, and then replaced it with the green pair pictured. Normally the green pair pictured would be cancelled already as well, but I wanted photos. Sometimes I have 3 or 4 cancelled greens active at the same time.

I don’t know if your explanation is correct for this situation – but I might be able to come up with a better picture when it comes up again.

This cancelling thing seems sensitive. Sometimes trains release all their passengers, and sometimes they leave empty because I’ve touched the line somewhere by accident. I never made the connection with the scenario pictured her.



I don’t have neither logs nor screenshots with me, but I have the same feeling like “Transit Tourist”.
Certainly the previous deletion of the green line has something to do with the boarding.
But I often observe similar non-boarding behaviour on new lines or only-gently-modified lines. With only small modifications, the turnback can’t be the reason. And as reported, this little bug may destroy your game.

Could the programmers = pathfinding&boarding algorithm makers please have a closer look into this?


They will but I think they may be off for Christmas until the new year


Hey all! Thanks for all of the info for this. We are away from the office until the 8th (and Peter, who is the only one who understands the full depth of the pathfinding code, is away until the 15th). I’ll have him take a look and get back to you when he returns. I would try to weigh in my thoughts but the last thing I want to do is give you the wrong info.

Thanks on your patience on this. And happy holidays too!


What’s causing the problem is a combination of selfish passengers and the intricacies of how passengers estimate which train will be the fastest to a particular station. In situations like these, where you have two lines taking slightly different routes to the same special station, with trains very near to each other, the inaccuracies of our estimation become apparent.

When a train is stopped at a station and has finished disembarking, each boarding tick (0.83s at normal speed, to sync with the audio) it asks the passengers waiting at the station if they want to board. This kicks off a full pathfind for that passenger (we never reuse paths, as the situation can change quickly). When the pathfind is complete, the passenger has a full path to a destination station (if one exists); board train 1 on the orange line, hop off at circle station 5, wait 2.8s, board train 5 on the red line, etc. If the first step is boarding the train in question, then it hops on, otherwise the train will ask the next passenger. If all the passengers waiting at the station want to board different trains then it’ll leave.

The complexity is in the estimation of ‘how long in the future will train X leave station Y and arrive at station Z’ (we have a function called EstimatedTimeFromStationToStation). Estimating the time for the train that’s currently at the station is the easiest, but even then we can’t know precisely how long it will take; it doesn’t know for sure how many passengers are yet to board, so doesn’t know when it will depart. So it’s inaccurate before we’ve even left the first station. In the example you’ve got above, the star passengers will be asking the orange train when it will arrive at the star station after leaving the circle station—the orange train needs to make a call if it will be stopping at the circle station, as this impacts the time dramatically. If it has to stop to drop off even one passenger, the amount of time it takes just to decelerate and accelerate again is several seconds. We use a heuristic based on how many passengers the train is currently holding and how far in the future we’re trying to estimate; any more than a couple of stations in the future and we just give up and add a constant time value per station. When we try to be smart about it and guess more intelligently, we only introduce more inconsistencies into the system and passengers flip-flop paths.

This is why passengers suddenly decide to stop boarding the green train and hop on the orange train instead. When the orange train was approaching the triangle station, it was probably using a more conservative estimate for how long it would likely be at the circle station, so the green train was definitely faster (as even a 0.1s penalty would tip it). When the orange train arrives, the algorithm can be more accurate as now it knows it likely won’t have to stop at the circle station, so the estimate is more aggressive (see below, †). Then the time estimates will be roughly the same, and the passenger counts on each train will swing the estimate. More passengers on a train will increase the estimated time-to-arrival as it implies more loading / unloading time. As soon as no star passengers decide to take the green train, it’ll take off even if more centralised planning would have had stars load onto the green train to leave space for the crosses on the orange train. We do do some work to combat that issue through the reservation system (more on that below), but in general passengers are selfish and don’t care at all if their optimal solution makes the situation worse overall. Just like a real commuter!

To avoid the situation where five passengers want to hop onto one free seat on the fastest train, and therefore skip a slightly slower, emptier, train, passengers reserve sets on inbound trains which only they can hop on. They can only reserve seats on trains that are about to arrive at the station they’re waiting at (or almost at, if their train is asking its passengers if they want to disembark at the station it’s pulling in to). So this would potentially avoid the issue, as both the triangles and crosses can’t all reserve seats on the orange train, so you’d think some would flip to the green train. Now it comes down to the ordering of the passengers, and (again) how the time estimation works. Because the star passenger is asked before the cross, it (selfishly) decides to take the orange train, and so reserves a seat. To save time, we reuse the pathfinding result for the subsequent stars at the station, so they reserve on the orange train as well (while seats are available). The crosses do the same, however the seats run out, so the leftover run their own pathfind, but assume they can’t use the orange train on the first link as all seats are reserved. They could take the green train, disembark at the star, then embark orange there, however we penalise transfers to encourage passengers to take direct routes (transfers are very difficult to estimate - I wrote about that here: The further in the future we’re scheduling a transfer, the earlier we have to think we will arrive before the second train; so if it’s five stations in the future our ETA must be 2.5s before the train we’re transferring to, ten stations in advice 5s before, etc.). In this case the penalty will be enough that the cross doesn’t think it will make it, so will have to wait until the orange train goes on another complete circuit and hits the star station again — at which point the best path is to sit tight and get picked up by the orange train at the triangle station, instead of boarding earlier and taking a joyride on the green train (passengers don’t want to take up train capacity needlessly). Again, passengers are selfish and don’t care about other passengers, overcrowding stations, etc. If the first passenger was a cross rather than a star, you probably wouldn’t have noticed anything.

So it’s all a very complicated way of saying that having two similar ways of getting to a special station can make the passengers appear confused!

I would like to find the time to work on a more accurate time estimation system, but even if it does get implemented it’ll never solve every case perfectly as the estimates will always be that, an estimate. To predict everything perfectly requires we know the optimal path for each passenger … which is what we’re trying to work out! There are changes that we could make to solve the case you’ve presented, but then we’d introduce different observable problems elsewhere. After a number of years of revising how the pathfinding works we’ve come to realise there is no perfect answer, and trying to chase it is playing whack-a-mole.

† As an aside, it might have to stop at the circle station after all—a circle passenger could spawn at the triangle station while the train is boarding, or another train could drop one off, etc., (although this would require far fewer passengers to be waiting at the station, as stations are FIFO by passenger type).


Thank you Peter for this incredible explanation of how everything works.

After thinking about this some… I kind of like the “commuter mentality” that you’ve built in to the algorithm, and I guess I must accept the judgement of the herd instead of blaming the algorithm.

It is so true about “real commuters”. Vancouver has a notorious route # 99 – “cross town express” – busiest bus route in Canada. So popular, that people take it even though it might not be the fastest route to where they’re going. Over 50,000 riders a day, and probably a quarter of them would get to their destination faster if they took the alternative direct route available. No amount of propaganda from the city could get these extra passengers to take the quicker options, so the 99 operates like a sardine can pretty well all day long.


I’m gonna pretend I understood that. It sounds nearly as complex as the informal seating rules on my train to school in the mornings. But you don’t have 3 rules about armrests along with subcommittees for bikes, the elderly and the disabled.


Ha, we have a similar route in Wellington — the only bus that goes to a suburb at the top of a hill is also the only bus that goes to the * bottom * of the hill, so it gets flooded by people just wanting to head uptown, instead of legitimate commuters. They (partially) solved it by instituting a minimum fare during peak times, but that’s outside of the scope of Mini Metro. :slight_smile:

Glad you found it interesting. You asked at the right time, when my work on the pathfinding refactor was fresh in my mind so I still understand what’s going on under the hood! I don’t want to try to pretend that it all works perfectly — there are definite improvements that can be made. I’d like to get to them at some point, just comes down to where our development time is best spent.


Hmm Wellington…


In Tilburg, The Netherlands, we have a bus that goes to a family park called “The Efteling”. In the morning it is filled from City to Park, in the evening it is Park to City. The fun thing is; it is a public bus. So, you dont need to go to the park to use it. In the evening the Bus is driving empty from City to Park. When going to my mom near the Efterling in the evening, I always take the empty Efteling bus since it has zero stops on the way there and is always faster as all other lines, which are filled up 75% to 100% at that time ;).


Truth be told, I’d way rather have a new map than a fix to my favorite complaint.

But I was thinking, if peak fares aren’t in the scope of Mini Metro, have you considered fare evaders???

For example, here in Vancouver, the transit service dispatches free “bus bridge” buses, to reduce congestion affecting a specific line. I think there’s a lot of fare evasion on those bus bridges, and it would probably be a simple thing to have your graphics person draw in some fare evaders to fill up those half empty MM trains I’m complaining about. They haven’t paid a fare, so they won’t be counted as passenger trips completed, and therefore won’t affect anything you’ve already got under the hood. Seems like an easy fix for empty seats. Maybe even use a stuck out tongue as a passenger icon!


I agree with transit on the new map. If someone starts getting really sniffy You could make it so you have a different coding process that monitors passengers pathfinding. If they consistently fail to get on a train to their destination then they could be relocated to a different station or just killed entirely. (New horror movie: All Change) note that they can only be killed at a station and not on a train. But people may complain you were manipulating scores…