/* -*- c++ -*- FILE: History.h RCS REVISION: $Revision: 1.18 $ COPYRIGHT: (c) 1999 -- 2003 Melinda Green, Don Hatch, and Jay Berkenbilt - Superliminal Software LICENSE: Free to use and modify for non-commercial purposes as long as the following conditions are adhered to: 1) Obvious credit for the source of this code and the designs it embodies are clearly made, and 2) Ports and derived versions of 4D Magic Cube programs are not distributed without the express written permission of the authors. DESCRIPTION: This class implements move history including marks and bidirectional movements. */ #ifndef HISTORY_H #define HISTORY_H #include // RESERVED MARKS // // The marks defined below are reserved for special internal use. // // Special behavior for macros: when a macro is applied, the // MACRO_START mark is placed in the history. When the macro is // finished, the MACRO_END mark is placed in the history. This allows // for fast undo over macros. // // Special behavior for full scrambles: when a full scramble is // performed, the SCRAMBLE_BOUNDARY mark is placed in the history. It // then takes special action on the part of the user to undo past this // mark. // // A user could confound this by manually inserting a reserved mark in // the logfile, but we won't worry about that case for now. The // interface for creating marks should exclude creation of the marks // defined below. #define MARK_MACRO_OPEN ((int)'[') #define MARK_MACRO_CLOSE ((int)']') #define MARK_SCRAMBLE_BOUNDARY ((int)'|') class Preferences; class History { private: Preferences& preferences; class PolygonManager4D *polymgr; int length; int debug; struct historynode { int stickerid; int dir; int slicesmask; int mark; struct historynode *prev, *next; /* doubly linked list */ }; struct historynode *first, *last, *current; int isSane(); void deleteNode( struct historynode *node); void insertNode(struct historynode *node_to_insert_before, int stickerid, int dir, int slicesmask, int mark); struct historynode* getPrevious(); int size(); int goBackwardsTowardsMark(int mark, /* INPUT */ struct stickerspec *sticker, /* OUTPUT */ int *Dir, /* OUTPUT */ int *Slicesmask); /* OUTPUT */ int goForwardsTowardsMark(int mark, /* INPUT */ struct stickerspec *sticker, /* OUTPUT */ int *Dir, /* OUTPUT */ int *Slicesmask); /* OUTPUT */ int atMark(int mark); public: History(Preferences&, class PolygonManager4D *polymgr); ~History(); // length = -1 means no change to length void reset(int length = -1); void deleteLast(); void destroy(); void append(int stickerid, int dir, int slicesmask); /* * If there is a "current", delete it and everything after it. */ void truncate(); /* * Set current to be the beginning of the list. */ void goToBeginning(); void goToEnd(); /* * Put a single move into the history. * This clears the history after * the current point, so a "redo" is impossible afterwards. */ void apply(struct stickerspec *sticker, int dir, int slicesmask); /* * Truncate (i.e. delete everything past current), * remove non-moves (marks), * merge rotates, * put rotates before the twists, * put opposite-face twists in canonical order, * merge same-face twists. * This is usually done in preparation for a "cheat" solve. * * FIX THIS-- this should be done on the fly, as the cheat-solve is happening * (doing it like this causes a long wait if the history is long). */ void compress(); /* * Back up one move in the history, returning a move * that would undo the last move. * Returns 1 on success, 0 if there is nothing to undo. */ int undo( struct stickerspec *sticker, /* OUTPUT */ int *Dir, /* OUTPUT */ int *Slicesmask); /* OUTPUT */ /* * Go forward one move in the history, returning the move * to redo. This is only valid if a move was undone. * Returns 1 on success, 0 if there is nothing to redo. */ int redo( struct stickerspec *sticker, /* OUTPUT */ int *Dir, /* OUTPUT */ int *Slicesmask); /* OUTPUT */ /* * Clear the history */ void clear(); /* * Mark current position with the given string (only uses the first character). */ void mark(int mark); /* * Executes a history_undo or history_redo and returns 1 on success. * Returns 0 if already at the mark, * -1 if no such mark. */ int goTowardsMark(int mark, /* INPUT */ struct stickerspec *sticker, /* OUTPUT */ int *Dir, /* OUTPUT */ int *Slicesmask, /* OUTPUT */ bool forwards_first = false); /* * Make a note that the puzzle is currently in a solved state * so that hitting the "cheat" button will not make it go past * this state. Actually this is probably not necessary since * the program can check by itself. */ void noteSolved(); void dump(FILE *fp); int read(FILE *fp); int countTwists(); int atMacroOpen(); int atMacroClose(); int atScrambleBoundary(); }; #endif // Local Variables: // c-basic-offset: 4 // c-comment-only-line-offset: 0 // c-file-offsets: ((defun-block-intro . +) (block-open . 0) (substatement-open . 0) (statement-cont . +) (statement-case-open . +4) (arglist-intro . +) (arglist-close . +) (inline-open . 0)) // indent-tabs-mode: nil // End: