Основываясь на ответе 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 игроков, даже в худшем случае.
(Увы, этот алгоритм не остановит игроков от переключения мест или пересечения путей по диагонали. Возможно, будет возможно адаптировать к нему двухшаговый трюк Гаджета , но совершенно наивный способ сделать это не сработает, и я слишком устал чтобы найти лучший способ только сейчас.)