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