Игра Grundy's и многие другие подобные игры могут быть решены с помощью такого алгоритма:
//returns a Move object representing the current player's optimal move, or null if the player has no chance of winning
function bestMove(GameState g){
for each (move in g.possibleMoves()){
nextState = g.applyMove(move)
if (bestMove(nextState) == null){
//the next player's best move is null, so if we take this move,
//he has no chance of winning. This is good for us!
return move;
}
}
//none of our possible moves led to a winning strategy.
//We have no chance of winning. This is bad for us :-(
return null;
}
Реализации GameState и Move зависят от игры.Для игры Гранди оба просты.
GameState
хранит список целых чисел, представляющих размер каждой кучи в игре.
Move
хранит целое число initialHeapSize
, иresultingHeapSizes
список целых чисел.
GameState::possibleMoves
перебирает свой список размеров кучи и определяет юридические деления для каждого из них.
GameState::applyMove(Move)
возвращает копию GameState, кромеданный ход применяется к доске.
GameState::possibleMoves
может быть реализовано для "классической" игры Grundy's следующим образом:
function possibleMoves(GameState g){
moves = []
for each (heapSize in g.heapSizes){
for each (resultingHeaps in possibleDivisions(heapSize)){
Move m = new Move(heapSize, resultingHeaps)
moves.append(m)
}
}
return moves
}
function possibleDivisions(int heapSize){
divisions = []
for(int leftPileSize = 1; leftPileSize < heapSize; leftPileSize++){
int rightPileSize = heapSize - leftPileSize
if (leftPileSize != rightPileSize){
divisions.append([leftPileSize, rightPileSize])
}
}
return divisions
}
Модифицируя это, чтобы использовать "разделить на любое количество неравных куч "Правило - это всего лишь вопрос изменения реализации possibleDivisions
.
Я не рассчитал это точно, но у неоптимизированного bestMove есть довольно сумасшедший худший случайво время выполнения.Как только вы начнете придавать ему начальное состояние около 12 камней, вы получите долгое время ожидания.Таким образом, вы должны реализовать памятка для повышения производительности.
Для достижения наилучших результатов сохраняйте отсортированный список размеров кучи каждого GameState и отбрасывайте все кучи размером 2 или 1.