문제

I'm working on a tic tac toe game and am wanting to implement an undo method. What I feel is the best way to do this is just setup another (multiple?) stacks, and make a copy of the 'moves' that have just taken place. Then, if undo is called, just pop the last move and repopulate the game board.

So yeah, I have the idea, but can't figure out how to implement it.

Some of what I have:

To set:

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;
}

Then there is a board method to build the board, a display method, and of course one to check for 3 in a row.

Thanks for any advice

도움이 되었습니까?

해결책

There is design pattern to do undo and redo. The command design pattern. It involes

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

implement the above interface to perform your move, execute will encapsulate your action.

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
 }
}

now create a new class that will be 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();
}

}

This way you can preserve the state of your application and prevent yourself from getting nullpointer exceptions. The method redo() will call execute() method. I just added it for clarity.

다른 팁

Go directly to the Gang of Four Design Patterns book and read the section on the Command pattern. That's what you're working toward -- and making a pretty good job of it -- and it's straight forward to implement in Java once you get the idea.

I would suggest that you have an object that encapsulates a "Move" which has an apply(BoardState s) and a similar unapply method on it. Then you can keep a stack/list of these. Undo becomes a pop from stack and unapply to current board state.

Since your apply/unapply methods are reversable this is probably one of the simplest and most efficient methods of solving it (and works for more complex problems if the apply method remembers any state it overrides).

If this is not an acceptable solution then I would suggest you explain more how your code works - re all the numbers, and what n stands for, cos is not that clear to me.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top