I think you can solve such a problem by introducing simple priority rules or additional gameplay elements. You may see these as instances of suggestions by DMGregory, so I'm just building up additional ideas on top of his answer.
Collision as a failure, by design
Who goes first? Nobody.
When two robots attempt to move into the same cell, a race condition occurs, and this can lead to a collision. Games such as RGB Express integrate collisions in their mechanics: puzzles must be solved by entangling actor paths without causing car accidents. This aspect prevails when trying to solve puzzles with a perfect solution (i.e. minimum distance possible).
If your game implements this mechanic, the player will always know what happens when crossing paths and will be required to avoid these scenarios. As a consequence, you must design puzzles accordingly.
Edge cases: None (I can think of), since this can also be considered a safe fallback case.
Collision as a failure, with a loophole
Who goes first? Nobody, unless...
Before thinking about priority rules, we let players solve possible collisions on their own. Since robots are programmed by players, they could get access to a TryMove command (as opposed to the base Move):
- Move: moves robots towards a direction, without further checks
- TryMove: IF the next cell is going to be free next step THEN move there ELSE perform actions
Example: the same scenario described in your question, the top robot (T) moves with Move and the left one (L) with TryMove. T is going to move from
(2,2) no matter what; L is smarter: it knows that it can't move to
(2,2) right away, then it does something else.
Possible something elses:
- Pause execution for the current step, then continue from the current TryMove instruction (wait until the cell is free/untargeted next step)
- Pause and wait, but TryMove switches to Move (only one chance to avoid collisions)
- Pause and wait up to n steps, then:
- Switch TryMove to Move as above
- Declare failure and halt execution
Edge cases: Two or more robots with a TryMove command meet each other: they could all halt or crash into each other.
You could assume that robots perform commands provided by players, but have a certain degree of freedom when it comes to decision-making and conflict resolution. Their "firmware" may contain instructions to solve order execution when meeting other fellow robots along the path. These are similar to common driving rules that apply to drivers.
Who goes first? Major path first, minor path last.
If paths aren't totally arbitrary, and your levels feature well-defined pathways, robots moving along main routes are entitled to go first. Then, robots crossing roads or merging to the main routes shall give priority to others before moving or turning.
Edge cases: Robots may attempt to move against the flow. Two robots try to perform the same action one opposite to another.
Who goes first? Oncoming traffic first, emerging traffic last.
Similar to above, but priority goes to robots that didn't turn recently. Working with your example: if robot T turned around 5 cells from North before meeting robot L, which previously turned and moved for 10 more cells, then L goes first. This is because L was already travelling when it bumped into T.
Edge cases: If two robots previously moved for the same distance, this may cause a conflict (collision) or require a different fallback criterion.
Who goes first? Relative left/right first.
In such a case, priority must be given to robots coming from one's left or right side. In your example, T goes first if priority is given to left-coming traffic; L goes first otherwise.
Edge cases: Four robots simultaneously approach the same cell from the four directions.
Who goes first? Heavy first/last, light last/first.
If there're different types of robots, you can define priority based on their weight, size, role or any trait of choice. Heavy-duty machines may need to move first, or lightweight drones may have priority since they move faster and can disengage the crossroad first.
Edge cases: Two vehicles of the same type bump into each other: their priority can be determined by the next trait in the hierarchy, but for identical machines, priority may not be well-determined.
Who goes first? Y'all don't, I DO.
Players can mark certain units with a control flag which guarantees priority over any other robot. While priority flags are an added mechanic and a limited resource, they become useful when it comes to resolving conflicts amongst multiple robots:
- Three robots bump into each other from North, East and West
- Unit N is flagged for priority, while others aren't: N goes first
- Units E and W wait for N to move over, then resolve their mutual conflict by applying a different criterion
This is a variation of "Collision as a failure, with a loophole", but the game mechanic involved is a property rather than a different command for the robots.
Edge cases: A priority-flagged robot goes first, but its movement is effectively obstructed by the mere presence of another robot. Multiple priority-flagged robots are involved in the conflict.
Depending on your design needs, you may consider using one or more of the above solutions. They don't conflict with each other and can be also arranged in a hierarchy of criteria, where an always-safe fallback solution is reached when other measures have failed.