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.