1 module caLib.lattices.TwoDimMargolusBlockLattice;
2 
3 //import caLib_abstract.Base;
4 
5 //import caLib_abstract.Lattice;
6 //import caLib_abstract.latticeDecorators.BlockLattice;
7 //import caLib_abstract.latticeDecorators.BoundedLattice;
8 
9 //import caLib.neighbourhoods.TwoDimMargolusNeighbourhood;
10 
11 import caLib_util.misc : mod;
12 
13 import std.stdio;
14 
15 template create_TwoDimMargolusBlockLattice(CellStateType)
16 {
17     alias Ct = CellStateType;
18 
19     auto create_TwoDimMargolusBlockLattice(int width, int height)
20     {
21         return new TwoDimMargolusBlockLattice!(Ct)(width, height);
22     }
23 
24     auto create_TwoDimMargolusBlockLattice(int width, int height,
25         CellStateType emptyCellState, CellStateType initialCondition)
26     {
27         return new TwoDimMargolusBlockLattice!(Ct)(width, height, emptyCellState,
28         	initialCondition);
29     }
30 
31     auto create_TwoDimMargolusBlockLattice(int width, int height, CellStateType emptyCellState, 
32     	CellStateType delegate(int x, int y) initialCondition)
33     {
34         return new TwoDimMargolusBlockLattice!(Ct)(width, height,
35             emptyCellState, initialCondition);
36     }
37 }
38 
39 struct TwoDimMargolusBlockLattice(CellStateType)
40 {
41     /*
42     * get behaviours
43     *     "torus"
44     *     "bounded"
45     *     "bounded-assumeInBounds"
46     *
47     * set behaviours
48     *     "torus"
49     *     "bounded"
50     *     "bounded-assumeInBounds"
51     *
52     * getNeighbours behaviours
53     *     "torus"
54     *     "bounded"
55     *     "bounded-assumeInBounds"
56     *
57     * iterate behaviours
58     *     "all"
59     *
60     * nextGen behaviours
61     *     "correct"
62     *     "toggle"
63     *     "flipp"
64     *
65     * getBlock behaviours
66     *     "torus"
67     *     "bounded"
68     *     "bounded-assumeInBounds"
69     *
70     * setBlock behaviours
71     *     "torus"
72     *     "bounded"
73     *     "bounded-assumeInBounds"
74     */
75 
76 private:
77 
78 	alias Ct = CellStateType;
79 
80 	TwoDimMargolusNeighbourhood* neighbourhood;
81 
82 	int width;
83 	int height;
84 
85     int blocksWidth;
86     int blocksHeight;
87 
88 	Ct[] lattice;
89 
90 	Ct emptyCellState;
91 
92 public:
93 
94 	Base!(TwoDimLattice!Ct
95 		, TwoDimBlockLattice!Ct
96 		, TwoDimBoundedLattice) base;
97 	alias base this; 
98 
99 	this(int width, int height)
100     {
101         this(width, height, Ct.init, Ct.init);
102     }
103 
104     this(int width, int height, Ct emptyCellState, Ct initialCondition)
105     {
106         auto initialConditionFunc = (int x, int y) { return initialCondition; };
107         this(width, height, emptyCellState, initialConditionFunc);
108     }
109 
110     this(int width, int height, Ct emptyCellState, Ct delegate(int x, int y) initialCondition)
111     in
112     { assert(width > 0 && height > 0); }
113     body
114     {
115     	this.width = width + ((width & 1) == 1 ? 1 : 0);
116     	this.height = height + ((height & 1) == 1 ? 1 : 0);
117 
118     	this.neighbourhood = new TwoDimMargolusNeighbourhood();
119 
120     	this.emptyCellState = emptyCellState;
121 
122     	this.lattice.length = this.width * this.height;
123     	foreach(row; 0 .. this.height)
124     	{
125     		foreach(col; 0 .. this.width)
126     		{
127     			lattice[row * this.width + col] = initialCondition(col, row);
128     		}
129     	}
130     }
131 
132     Ct get(string behaviour)(int x, int y)
133     {
134         static if(behaviour == "torus")
135         {
136             return lattice.ptr[mod(y, height) * width + mod(x, width)];
137         }
138         else static if(behaviour == "bounded")
139         {
140             if(x >= 0 && x < width && y >= 0 && y < height)
141             {
142                 return lattice.ptr[y * width + x];
143             }
144             else
145             {
146                 return emptyCellState;
147             }
148         }
149         else static if(behaviour == "bounded-assumeInBounds")
150         {
151             return lattice.ptr[y * width + x];
152         }
153         else
154         {
155             return base.get!behaviour(x, y);
156         }
157     }
158 
159     Ct get(int x, int y)
160     {
161         return get!"bounded"(x, y);
162     }
163 
164     void set(string behaviour)(int x, int y, Ct newValue)
165     {
166         static if(behaviour == "torus")
167         {
168             lattice.ptr[mod(y, height) * width + mod(x, width)] = newValue;
169         }
170         else static if(behaviour == "bounded")
171         {
172             if(x >= 0 && x < width && y >= 0 && y < height)
173             {
174                 lattice.ptr[y * width + x] = newValue;
175             }
176         }
177         else static if(behaviour == "bounded-assumeInBounds")
178         {
179             lattice.ptr[y * width + x] = newValue;
180         }
181         else
182         {
183             base.set!behaviour(x, y);
184         }
185     }
186 
187     void set(int x, int y, Ct newValue)
188     {
189         set!"bounded"(x, y, newValue);
190     }
191 
192     Ct[] getNeighbours(string behaviour)(int x, int y)
193     {
194         static if(behaviour == "torus"
195                || behaviour == "bounded"
196                || behaviour == "bounded-assumeInBounds")
197         {
198             Ct[] neighbours;
199             foreach(coord ; neighbourhood.getNeighboursCoordinates(x, y))
200             {
201                 neighbours ~= [get!behaviour(coord[0], coord[1])];
202             }
203             return neighbours;
204         }
205         else
206         {
207             return base.getNeighbours!behaviour(x, y);
208         }
209     }
210 
211     Ct[] getNeighbours(int x, int y)
212     {
213         return getNeighbours!"bounded"(x, y);
214     }
215 
216     void iterate(string behaviour)(void delegate(int x, int y) iterator)
217     {
218         static if(behaviour == "all")
219         {
220             for(int row=0; row<height; row++) {
221                 for(int col=0; col<width; col++) {
222                     iterator(col, row);
223                 }
224             }
225         }
226         else
227         {
228             base.iterate!behaviour(iterator);
229         }
230     }
231 
232     void iterate(void delegate(int x, int y) iterator)
233     {
234         iterate!"all"(iterator);
235     }
236 
237     void nextGen(string behaviour)()
238     {
239         static assert(0, "Error, this method cannot be used with this lattice");
240     }
241 
242     void nextGen()
243     {
244         neighbourhood.shift();
245     }
246 
247     Ct[] getBlock(string behaviour)(int x, int y)
248 	{
249         static if(behaviour == "torus"
250                || behaviour == "bounded" 
251                || behaviour == "bounded-assumeInBounds")
252         {
253             int[] block;
254 
255             foreach(coord; neighbourhood.getBlockCoordinates(x, y))
256             {
257                 block = [get!behaviour(coord[0], coord[1])] ~ block;
258             }
259             return block;
260         }
261         else
262         {
263             return base.getBlock!behaviour(x, y);
264         }	
265 	}
266 
267 	Ct[] getBlock()(int x, int y)
268 	{
269 		return getBlock!"bounded"(x, y);
270 	}
271 
272 	void setBlock(string behaviour)(int x, int y, Ct[] newBlock)
273 	{
274 		static if(behaviour == "torus"
275                || behaviour == "bounded" 
276                || behaviour == "bounded-assumeInBounds")
277         {
278             foreach(coord; neighbourhood.getBlockCoordinates(x, y))
279             {
280                 set!behaviour(coord[0], coord[1], newBlock[0]);
281                 newBlock = newBlock[1..newBlock.length];
282             }
283         }
284         else
285         {
286             return base.setBlock!behaviour(x, y);
287         }
288 	}
289 
290 	void setBlock()(int x, int y, Ct[] newBlock)
291 	{
292 		setBlock!"bounded"(x, y, newBlock);	
293 	}
294 
295 	void iterateBlocks(string behaviour)(void delegate(int x, int y) iterator)
296 	{
297 		static if(behaviour == "all")
298         {
299             foreach(row; 0 .. width/2)
300             {
301                 foreach(col; 0 .. height/2)
302                 {
303                     iterator(col, row);
304                 }
305             }
306         }
307         else
308         {
309             base.iterateBlocks!"behaviour"(iterator);
310         }
311 	}
312 
313 	void iterateBlocks()(void delegate(int x, int y) iterator)
314 	{
315 		iterateBlocks!"all"(iterator);	
316 	}
317 
318 	Size[2] getLatticeSize()()
319 	{
320 		return [Size(0, width), Size(0, height)];
321 	}
322 }