1 // This file is part of Golly. 2 // See docs/License.html for the copyright notice. 3 4 /** 5 * This is the pure abstract class any life calculation algorithm 6 * must support. As long as a life algorithm implements this 7 * interface, it can be invoked by our driver code. 8 */ 9 #ifndef LIFEALGO_H 10 #define LIFEALGO_H 11 #include "bigint.h" 12 #include "viewport.h" 13 #include "liferender.h" 14 #include "lifepoll.h" 15 #include "readpattern.h" 16 #include "platform.h" 17 #include <cstdio> 18 // moving the include vector *before* platform.h breaks compilation 19 #ifdef _MSC_VER 20 #pragma warning(disable:4702) // disable "unreachable code" warnings from MSVC 21 #endif 22 #include <vector> 23 #ifdef _MSC_VER 24 #pragma warning(default:4702) // enable "unreachable code" warnings 25 #endif 26 using std::vector; 27 #include <iostream> 28 29 // this must not be increased beyond 32767, because we use a bigint 30 // multiply that only supports multiplicands up to that size. 31 const int MAX_FRAME_COUNT = 32000 ; 32 33 /** 34 * Timeline support is pretty generic. 35 */ 36 class timeline_t { 37 public: timeline_t()38 timeline_t() : recording(0), framecount(0), savetimeline(1), 39 start(0), inc(0), next(0), end(0), frames() {} 40 int recording, framecount, base, expo, savetimeline ; 41 bigint start, inc, next, end ; 42 vector<void *> frames ; 43 } ; 44 45 class lifealgo { 46 public: lifealgo()47 lifealgo() : generation(0), increment(0), timeline(), grid_type(SQUARE_GRID) 48 { poller = &default_poller ; 49 gridwd = gridht = 0 ; // default is an unbounded universe 50 unbounded = true ; // most algorithms use an unbounded universe 51 } 52 virtual ~lifealgo() ; 53 virtual void clearall() = 0 ; 54 // returns <0 if error 55 virtual int setcell(int x, int y, int newstate) = 0 ; 56 virtual int getcell(int x, int y) = 0 ; 57 virtual int nextcell(int x, int y, int &v) = 0 ; 58 void getcells(unsigned char *buf, int x, int y, int w, int h) ; 59 // call after setcell/clearcell calls 60 virtual void endofpattern() = 0 ; 61 virtual void setIncrement(bigint inc) = 0 ; 62 virtual void setIncrement(int inc) = 0 ; 63 virtual void setGeneration(bigint gen) = 0 ; getIncrement()64 const bigint &getIncrement() { return increment ; } getGeneration()65 const bigint &getGeneration() { return generation ; } 66 virtual const bigint &getPopulation() = 0 ; 67 virtual int isEmpty() = 0 ; 68 // can we do the gen count doubling? only hashlife 69 virtual int hyperCapable() = 0 ; 70 virtual void setMaxMemory(int m) = 0 ; // never alloc more than this 71 virtual int getMaxMemory() = 0 ; 72 virtual const char *setrule(const char *) = 0 ; // new rules; returns err msg 73 virtual const char *getrule() = 0 ; // get current rule set 74 virtual void step() = 0 ; // do inc gens 75 virtual void draw(viewport &view, liferender &renderer) = 0 ; 76 virtual void fit(viewport &view, int force) = 0 ; 77 virtual void findedges(bigint *t, bigint *l, bigint *b, bigint *r) = 0 ; 78 virtual void lowerRightPixel(bigint &x, bigint &y, int mag) = 0 ; 79 virtual const char *writeNativeFormat(std::ostream &os, char *comments) = 0 ; setpoll(lifepoll * pollerarg)80 void setpoll(lifepoll *pollerarg) { poller = pollerarg ; } readmacrocell(char *)81 virtual const char *readmacrocell(char *) { return "Cannot read macrocell format." ; } 82 83 // Verbosity crosses algorithms. We need to embed this sort of option 84 // into some global shared thing or something rather than use static. setVerbose(int v)85 static void setVerbose(int v) { verbose = v ; } getVerbose()86 static int getVerbose() { return verbose ; } 87 DefaultRule()88 virtual const char* DefaultRule() { return "B3/S23"; } 89 // return number of cell states in this universe (2..256) NumCellStates()90 virtual int NumCellStates() { return 2; } 91 // return number of states to use when setting random cells NumRandomizedCellStates()92 virtual int NumRandomizedCellStates() { return NumCellStates() ; } 93 94 // timeline support 95 virtual void* getcurrentstate() = 0 ; 96 virtual void setcurrentstate(void *) = 0 ; 97 int startrecording(int base, int expo) ; 98 pair<int, int> stoprecording() ; getbaseexpo()99 pair<int, int> getbaseexpo() 100 { return make_pair(timeline.base, timeline.expo) ; } 101 void extendtimeline() ; 102 void pruneframes() ; gettimelinestart()103 const bigint &gettimelinestart() { return timeline.start ; } gettimelineend()104 const bigint &gettimelineend() { return timeline.end ; } gettimelineinc()105 const bigint &gettimelineinc() { return timeline.inc ; } getframecount()106 int getframecount() { return timeline.framecount ; } isrecording()107 int isrecording() { return timeline.recording ; } 108 int gotoframe(int i) ; 109 void destroytimeline() ; savetimelinewithframe(int yesno)110 void savetimelinewithframe(int yesno) { timeline.savetimeline = yesno ; } 111 112 // support for a bounded universe with various topologies: 113 // plane, cylinder, torus, Klein bottle, cross-surface, sphere 114 unsigned int gridwd, gridht ; // bounded universe if either is > 0 115 bigint gridleft, gridright ; // undefined if gridwd is 0 116 bigint gridtop, gridbottom ; // undefined if gridht is 0 117 bool boundedplane ; // topology is a bounded plane? 118 bool sphere ; // topology is a sphere? 119 bool htwist, vtwist ; // Klein bottle if either is true, 120 // or cross-surface if both are true 121 int hshift, vshift ; // torus with horizontal or vertical shift 122 123 const char* setgridsize(const char* suffix) ; 124 // use in setrule() to parse a suffix like ":T100,200" and set 125 // the above parameters 126 127 const char* canonicalsuffix() ; 128 // use in setrule() to return the canonical version of suffix; 129 // eg. ":t0020" would be converted to ":T20,0" 130 131 bool CreateBorderCells() ; 132 bool DeleteBorderCells() ; 133 // the above routines can be called around step() to create the 134 // illusion of a bounded universe (note that increment must be 1); 135 // they return false if the pattern exceeds the editing limits 136 137 bool unbounded; 138 // algorithms that uses a finite universe should set this flag false 139 // so the GUI code won't call CreateBorderCells or DeleteBorderCells 140 141 vector<int> clipped_cells; 142 // algorithms that uses a finite universe need to save live cells 143 // that might be clipped when a setrule call reduces the size of 144 // the universe (this allows the GUI code to restore the cells 145 // if the rule change is undone) 146 147 enum TGridType { SQUARE_GRID, TRI_GRID, HEX_GRID, VN_GRID } ; getgridtype()148 TGridType getgridtype() const { return grid_type ; } 149 150 protected: 151 lifepoll *poller ; 152 static int verbose ; 153 int maxCellStates ; // keep up to date; setcell depends on it 154 bigint generation ; 155 bigint increment ; 156 timeline_t timeline ; 157 TGridType grid_type ; 158 159 private: 160 // following are called by CreateBorderCells() to join edges in various ways 161 void JoinTwistedEdges() ; 162 void JoinTwistedAndShiftedEdges() ; 163 void JoinShiftedEdges() ; 164 void JoinAdjacentEdges(int pt, int pl, int pb, int pr) ; 165 void JoinEdges(int pt, int pl, int pb, int pr) ; 166 // following is called by DeleteBorderCells() 167 void ClearRect(int top, int left, int bottom, int right) ; 168 } ; 169 170 /** 171 * If you need any static information from a lifealgo, this class can be 172 * called (or overridden) to set up all that data. Right now the 173 * functions do nothing; override if you need that info. These are 174 * called one by one by a static method in the algorithm itself, 175 * if that information is available. The ones marked optional need 176 * not be called. 177 */ 178 class staticAlgoInfo { 179 public: 180 staticAlgoInfo() ; ~staticAlgoInfo()181 virtual ~staticAlgoInfo() { } ; 182 183 // mandatory setAlgorithmName(const char * s)184 void setAlgorithmName(const char *s) { algoName = s ; } setAlgorithmCreator(lifealgo * (* f)())185 void setAlgorithmCreator(lifealgo *(*f)()) { creator = f ; } 186 187 // optional; override if you want to retain this data setDefaultBaseStep(int)188 virtual void setDefaultBaseStep(int) {} setDefaultMaxMem(int)189 virtual void setDefaultMaxMem(int) {} 190 191 // minimum and maximum number of cell states supported by this algorithm; 192 // both must be within 2..256 193 int minstates; 194 int maxstates; 195 196 // default color scheme 197 bool defgradient; // use color gradient? 198 unsigned char defr1, defg1, defb1; // color at start of gradient 199 unsigned char defr2, defg2, defb2; // color at end of gradient 200 // if defgradient is false then use these colors for each cell state 201 unsigned char defr[256], defg[256], defb[256]; 202 203 // default icon data (in XPM format) 204 const char **defxpm7x7; // 7x7 icons 205 const char **defxpm15x15; // 15x15 icons 206 const char **defxpm31x31; // 31x31 icons 207 208 // basic data 209 const char *algoName ; 210 lifealgo *(*creator)() ; 211 int id ; // my index 212 staticAlgoInfo *next ; 213 214 // support: give me sequential algorithm IDs getNumAlgos()215 static int getNumAlgos() { return nextAlgoId ; } 216 static int nextAlgoId ; 217 static staticAlgoInfo &tick() ; 218 static staticAlgoInfo *head ; 219 static staticAlgoInfo *byName(const char *s) ; 220 static int nameToIndex(const char *s) ; 221 } ; 222 #endif 223