$20
1 Goals
? To build a Stack class by using an stl template.
? To be able to undo and redo moves.
2 Changes to Other Classes
Changes to the Game class. The Game::run() function displays a menu and accepts selections, which are processed by a switch. The switch should call action functions to carry out most of the user's choices. Try to limit the code that is actually inside teach case to three lines. If you have not already done so, move longer blocks of code out of the switch into separate functions.
Activate menu options undo and redo. Also instantiate two stacks of BoardState*s: the undo stack and the redo stack. Use the Stack class de?ned below, which is adapted from the stl Stack template. The undo stack always holds a copy of the current state of the game. The redo stack holds states that have been undone, until they are ready to be redone. The Game class has custody
of these dynamically allocated objects and is responsible for deallocating them whenever one is discarded.
Every time you make a move or turn o
? a possibility, another BoardState
? will be pushed onto the undo stack. When you ask to undo or redo an action, a BoardState
? will be popped from one
of the stacks and used to update the state of the Board. When you stop doing undos and redos
and again call move or turn
?, the redo history becomes invalid. Thus, any call to move or turno?
must zap (empty) the redo stack. At the end of a game, the undo stack contains a complete history
of your successful moves. (This history could be written to a ?le if anyone was interested in it.)
Add to the actions for the Move menu item. Immediately after the user makes a move, do the
following:
? Create a new BoardState object, initialized to the state after the move.
? Push the pointer onto the undo stack.
? Clear the redo stack.
Implement the undo menu item, keeping in mind that you can't undo unless the stack has 2 or
more BoardStates.
? Pop one BoardState* o? the undo stack, then
? Push the pointer onto the redo stack.
? Then restore the Board state to the state on top of the undo stack, as de?ned below.
Implement the redo menu item:
? Return without doing anything if the redo stack is empty.
? Pop one BoardState* o? the redo stack, then
? Push the pointer onto the undo stack.
? Then restore the Board state to the state on top of the undo stack, as de?ned below.
9: undo and redo CSCI 4526 / 6626 Fall 2016 2
Changes to the Board class. Add a function restoreState( BoardState* ). This will loop through the 81 squares in the parameter BoardState and copy the information into the State portion of each Square. Call this from the Game class after either an undo or a redo.
3 The Stack Class
Implementing a Stack. The standard template library has a template named stack<T that does approximately (but not exactly) what we want in this application. However, it is very easy to adapt the vector<T template and create a stack with the right functionality. Our strategy will be to instantiate the stl template as vector<BoardState* and at the same time, on the same line, derive the class Stack from it. Private derivation is needed to close o? access to many unwanted
vector<T functions. However, private derivation forces us to de?ne, in Stack, all of the functions we want to keep. In the derived class, you will need these functions; de?ne them all as inline functions:
? Constructor and destructor.
? void pop(); Delegate to vector::pop_back()
? BoardState* top(); Delegate to vector::top()
? void push( BoardState* ); Delegate to vector::push_back( BoardState* )
? int size(); Return the number of BoardStates on the stack (in the vector).
? void zap(); Empty the entire stack by popping everything o? it. Remember that this involves freeing dynamic memory.
This Stack class is an adapter class: it adapts vector to our needs by adding, removing, and renaming functions. The ?rst three functions, above, rename the functions inherited from vector.
To implement them, simply call the appropriate function from the vector class. One function, size(), has the same name as the underlying function in vector. For that one function, you must use the :: operator to call the size() function from the base class. (Otherwise, an attempt to delegate becomes an in?nite recursion and your program will end with a segmentation error. I unthinkingly tried it. Bad news!)