Основываясь на ответе SimonW , вот явный алгоритм:
Позвольте squares
быть массивом, индексированным местоположениями игрока, и содержащий, для каждого возможного местоположения, или индекс другого местоположения или специальное значение NULL
. (Вы можете сохранить это как разреженный массив.) Возможные значения записей в этом массиве могут быть интерпретированы следующим образом:
- Если
squares[S]
есть NULL
, квадрат S
может свободно двигаться.
- Если
squares[S] == S
игрок не S
может или не может двигаться, или два (или более) игрока пытались перейти S
одновременно, и оба были отклонены.
- В противном случае
squares[S]
будет содержать индекс квадрата, с которого игрок хочет перейти на квадрат S
.
На каждом ходу инициализируйте все записи squares
в NULL
и затем запустите следующий алгоритм:
for each player:
current := the player's current location;
target := the location the player wants to move to (may equal current);
if squares[target] is NULL:
squares[target] := current; // target is free, mark planned move
else
// mark the target square as contested, and if necessary, follow
// the pointers to cancel any moves affected by this:
while not (target is NULL or squares[target] == target):
temp := squares[target];
squares[target] := target;
target := temp;
end while
// mark this player as stationary, and also cancel any moves that
// would require some else to move to this square
while not (current is NULL or squares[current] == current):
temp := squares[current];
squares[current] := current;
current := temp;
end while
end if
end for
После этого снова просмотрите список игроков и переместите тех, кто в состоянии это сделать:
for each player:
current := the player's current location;
if not squares[current] == current:
move player;
end if
end for
Поскольку каждый ход может быть спланирован только один раз и отменен не более одного раза, этот алгоритм будет запущен за O ( n ) времени для n игроков, даже в худшем случае.
(Увы, этот алгоритм не остановит игроков от переключения мест или пересечения путей по диагонали. Возможно, будет возможно адаптировать к нему двухшаговый трюк Гаджета , но совершенно наивный способ сделать это не сработает, и я слишком устал чтобы найти лучший способ только сейчас.)