Java — использование нескольких стеков, чтобы разрешить метод «отмены»

Я работаю над игрой в крестики-нолики и хочу реализовать метод отмены. Я считаю, что лучший способ сделать это — просто настроить еще один (несколько?) стеков и сделать копию только что сделанных «ходов». Затем, если вызывается отмена, просто выберите последний ход и снова заполните игровое поле.

Так что да, у меня есть идея, но я не могу понять, как ее реализовать.

Кое-что из того, что у меня есть:

Устанавливать:

public void set(Position p, int v, int n) throws IOException { 
    if (board[p.x][p.y][p.z]!= 0) throw new IOException("Position taken");

    //Restrict 222 until all other's have been used
    if (n != 26) {
        if (p.x == 1 && p.y == 1 && p.z ==1) {
            throw new IOException("[2,2,2] cannot be played until all other positions have been taken");
        }
    }

    //Enforce x=1 for first 9, x=3 for next 9
    if (n < 9 ) {
        if (p.x != 0) throw new IOException("Please play on x=1 for the first 9 moves");
    }

    if (n >= 9 && n < 18) {
        if (p.x != 2) throw new IOException("Please play on x=3 for the first 9 moves");
    }

    board[p.x][p.y][p.z] = v;
}

Затем есть метод доски для построения доски, метод отображения и, конечно же, один для проверки 3-х подряд.

Спасибо за любой совет


person John Redyns    schedule 11.12.2010    source источник
comment
Поиск шаблона дизайна Memento в GOF   -  person pastjean    schedule 11.12.2010


Ответы (3)


Существует шаблон проектирования для отмены и повтора. Шаблон разработки команд. Это включает в себя

public interface ICommand{
   void execute();
   void undo();
   void redo();
}

реализуйте вышеуказанный интерфейс для выполнения вашего перемещения, execute инкапсулирует ваше действие.

class MoveCommand implements ICommand{//parameter to store current board state
  public MoveCommand(){
    // new board state is validated
  }
  public void execute(){
    // change the board state
  }
 public void undo(){ // restore
 }
 public void redo(){ // apply again if possible
 }
}

теперь создайте новый класс, который будет CommandDispatcher

class CommandDispatcher{
 private List<ICommand> commands = new ArrayList<ICommand>();
 public CommandDispatcher(){
 }
 private ICommand currentCommand = null;
 public void setCommand(ICommand cmd){
   currentCommand  = cmd;
   cmd.execute();
   commands.add(cmd);
 }
 public void undoAll(){
    for(ICommand cmd : commands){cmd.undo();}
}
 public void undo(){
 commands.remove(commands.size()-1);
 currentCommand = commands.get(commands.size()-1)
}
public void redo(){
if(null!=currentCommand) currentCommand.redo();
}

}

Таким образом, вы можете сохранить состояние вашего приложения и предотвратить получение исключений нулевого указателя. Метод redo() вызовет метод execute(). Я просто добавил это для ясности.

person rxx    schedule 11.12.2010
comment
Несмотря на то, что я не работаю над игрой в крестики-нолики, я узнал кое-что очень полезное из вашего ответа! - person Zaven Nahapetyan; 11.12.2010

Перейдите непосредственно к книге Gang of Four Шаблоны проектирования. и прочтите раздел о шаблоне Command. Это то, над чем вы работаете — и довольно неплохо с этим справляетесь — и это легко реализовать на Java, как только у вас появится идея.

person Charlie Martin    schedule 11.12.2010

Я бы предположил, что у вас есть объект, который инкапсулирует «Move», который имеет метод apply (BoardState s) и аналогичный метод unapply. Затем вы можете сохранить стек/список из них. Undo извлекается из стека и не применяется к текущему состоянию доски.

Поскольку ваши методы применения/отмены применения являются обратимыми, это, вероятно, один из самых простых и эффективных методов его решения (и работает для более сложных проблем, если метод применения запоминает любое состояние, которое он переопределяет).

Если это неприемлемое решение, я бы посоветовал вам подробнее объяснить, как работает ваш код, - пересмотреть все числа и что означает n, потому что мне это не совсем понятно.

person DaveC    schedule 11.12.2010