1 module caLib.lattices.TwoDimDenseLattice;
2 
3 import caLib_abstract.neighbourhood : isNeighbourhood;
4 import caLib_abstract.util : formatBehaviour;
5 import caLib.neighbourhoods.TwoDimMooreNeighbourhood;
6 
7 import caLib_util.misc : mod;
8 import std.algorithm.searching : canFind;
9 
10 
11 
12 auto create_TwoDimDenseLattice(Ct, Nt)(int width, int height, Nt* neighbourhood)
13 if(isNeighbourhood!(Nt, 2))
14 in
15 {
16     assert(width > 0 && height > 0);
17     assert(neighbourhood !is null);
18 }
19 body
20 {
21     return create_TwoDimDenseLattice(width, height, neighbourhood, 0, 0);
22 }
23 
24 
25 
26 auto create_TwoDimDenseLattice(Ct, Nt)(int width, int height, Nt* neighbourhood,
27     Ct emptyCellState, Ct initialCondition)
28 if(isNeighbourhood!(Nt, 2))
29 in
30 {
31     assert(width > 0 && height > 0); 
32     assert(neighbourhood !is null);
33 }
34 body
35 {
36     return create_TwoDimDenseLattice(width, height, neighbourhood,
37         emptyCellState, (int x, int y) { return initialCondition; });
38 }
39 
40 
41 
42 auto create_TwoDimDenseLattice(Ct, Nt)(int width, int height, Nt* neighbourhood,
43     Ct emptyCellState, Ct delegate(int x, int y) initialCondition)
44 if(isNeighbourhood!(Nt, 2))
45 in
46 {
47     assert(width > 0 && height > 0);
48     assert(neighbourhood !is null);
49 }
50 body
51 {
52     return new TwoDimDenseLattice!(Ct, Nt)(width, height, neighbourhood,
53         emptyCellState, initialCondition);
54 }
55 
56 
57 
58 struct TwoDimDenseLattice(Ct, Nt) if(isNeighbourhood!(Nt, 2))
59 {
60 
61 private: 
62 
63     Nt* neighbourhood;
64 
65     int width;
66     int height;
67 
68     Ct[] a, b;
69     Ct[]* lattice, latticeNextGen;
70 
71     Ct emptyCellState;
72 
73 public: 
74 
75     alias CellStateType = Ct;
76     alias NeighbourhoodType = Nt;
77     enum uint Dimension = 2;
78 
79     this(int width, int height, Nt* neighbourhood, Ct emptyCellState,
80         Ct delegate(int x, int y) initialCondition)
81     in
82     {
83         assert(width > 0 && height > 0);
84         assert(neighbourhood !is null);
85     }
86     body
87     {
88         this.width = width;
89         this.height = height;
90 
91         this.neighbourhood = neighbourhood;
92 
93         this.emptyCellState = emptyCellState;
94 
95         a.length = width * height;
96         b.length = width * height;
97         lattice = &a;
98         latticeNextGen = &b;
99 
100         foreach(row; 0 .. height)
101         {
102             foreach(col; 0 .. width)
103             {
104                 lattice[0][row * width + col] = initialCondition(col, row);
105             }
106         }
107     }
108 
109 
110 
111     Ct get(string behaviour)(int x, int y)
112     {
113         immutable string[] behaviour = formatBehaviour!behaviour;
114 
115         static if(behaviour[0] == "torus")
116         {
117             return lattice[0].ptr[mod(y, height) * width + mod(x, width)];
118         }
119         else static if(behaviour[0] == "bounded" 
120             && behaviour.canFind("assumeInBounds"))
121         {
122             return lattice[0].ptr[y * width + x];
123         }
124         else static if(behaviour[0] == "bounded")
125         {
126             if(x >= 0 && x < width && y >= 0 && y < height)
127             {
128                 return lattice[0].ptr[y * width + x];
129             }
130             else
131             {
132                 return emptyCellState;
133             }
134         }
135         else static if(behaviour[0] == "_test")
136         {
137             return Ct.init;
138         }
139         else
140         {
141             static assert(0, "TwoDimDenseLattice get method dosen't have a \""
142                 ~ behaviour ~"\" behaviour");
143         }
144     }
145 
146 
147 
148     Ct get(int x, int y)
149     {
150         return get!"bounded"(x, y);
151     }
152 
153 
154 
155     void set(string behaviour)(int x, int y, Ct newValue)
156     {
157         immutable string[] behaviour = formatBehaviour!behaviour;
158 
159         static if(behaviour.canFind("instant")) {
160             alias latticeToChange = lattice;
161         } else {
162             alias latticeToChange = latticeNextGen;
163         }
164 
165         static if(behaviour[0] == "torus")
166         {
167             latticeToChange[0].ptr[mod(y, height) * width + mod(x, width)]
168                 = newValue;
169         }
170         else static if(behaviour[0] == "bounded"
171             && behaviour.canFind("assumeInBounds"))
172         {
173             latticeToChange[0].ptr[y * width + x] = newValue;
174         }
175         else static if(behaviour[0] == "bounded")
176         {
177             if(x >= 0 && x < width && y >= 0 && y < height)
178             {
179                 latticeToChange[0].ptr[y * width + x] = newValue;
180             }
181         }
182         else static if(behaviour[0] == "_test")
183         {
184 
185         }
186         else
187         {
188             static assert(0, "TwoDimDenseLattice set method dosen't have a \""
189                 ~ behaviour ~"\" behaviour");
190         }
191     }
192 
193 
194 
195     void set(int x, int y, Ct newValue)
196     {
197         set!"bounded"(x, y, newValue);
198     }
199 
200 
201 
202     Ct[] getNeighbours(string behaviour)(int x, int y)
203     {
204         enum string behaviourString = behaviour;
205         immutable string[] behaviour = formatBehaviour!behaviour;
206 
207         static if(behaviour[0] == "torus"
208                || behaviour[0] == "bounded")
209         {
210             Ct[] neighbours;
211             foreach(coord ; neighbourhood.getNeighboursCoordinates(x, y))
212             {
213                 neighbours ~= [get!behaviourString(coord[0], coord[1])];
214             }
215             return neighbours;
216         }
217         else static if(behaviour[0] == "_test")
218         {
219             return Ct[].init;
220         }
221         else
222         {
223             static assert(0, "TwoDimDenseLattice getNeighbours method dosen't" 
224                 ~ "have a \"" ~ behaviour ~ "\" behaviour");
225         }
226     }
227 
228 
229 
230     Ct[] getNeighbours(int x, int y)
231     {
232         return getNeighbours!"bounded"(x, y);
233     }
234 
235 
236 
237     void iterate(string behaviour)(Ct delegate(Ct cellState, Ct[] neighbours,
238         int x, int y) rule)
239     {
240         immutable string[] behaviour = formatBehaviour!behaviour;
241 
242         // optimized for moore neighbourhood
243         static if(behaviour[0] == "all" && is(Nt : TwoDimMooreNeighbourhood))
244         {
245             Ct[] neighbours;
246             Ct cellState;
247             Ct newCellState;
248             foreach (x; 0 .. width)
249             {
250                 neighbours = getNeighbours(x, 0);
251                 cellState = get!"bounded-assumeInBounds"(x, 0);
252                 foreach(y; 0 .. height)
253                 {
254                     set(x, y, rule(cellState, neighbours, x, y));
255 
256                     newCellState = neighbours[6];
257                     neighbours = [
258                         neighbours[3], cellState,   neighbours[4],
259                         neighbours[5],              neighbours[7],
260                         get(x-1, y+2), get(x, y+2), get(x+1, y+2)];
261                     cellState = newCellState;
262                 }
263             }
264         }
265         // generic
266         else static if(behaviour[0] == "all")
267         {
268             foreach(y; 0 .. height)
269             {
270                 foreach(x; 0 .. width)
271                 {
272                     set(x, y, rule(get(x, y), getNeighbours(x, y), x, y));
273                 }
274             }
275         }
276         else static if(behaviour[0] == "_test")
277         {
278 
279         }
280         else
281         {
282             static assert(0, "TwoDimDenseLattice iterate method dosen't have a"
283                 ~ "\"" ~ behaviour ~"\" behaviour");
284         }
285     }
286 
287 
288 
289     void iterate(Ct delegate(Ct cellState, Ct[] neighbours,
290         int x, int y) rule)
291     {
292         iterate!"all"(rule);
293     }
294 
295 
296 
297     void nextGen(string behaviour)()
298     {
299         immutable string[] behaviour = formatBehaviour!behaviour;
300 
301         static if(behaviour[0] == "correct")
302         {
303             Ct[]* tmp = lattice;
304             lattice = latticeNextGen;
305             latticeNextGen = tmp;
306 
307             for(int i=0; i<width*height; i++)
308             {
309                 latticeNextGen[0].ptr[i] = emptyCellState;
310             }
311         }
312         else static if(behaviour[0] == "toggle")
313         {
314             lattice[0] = latticeNextGen[0].dup;
315         }
316         else static if(behaviour[0] == "flipp")
317         {
318             Ct[]* tmp = lattice;
319             lattice = latticeNextGen;
320             latticeNextGen = tmp;
321         }
322         else static if(behaviour[0] == "nothing")
323         {}
324         else static if(behaviour[0] == "_test")
325         {}
326         else
327         {
328             static assert(0, "TwoDimDenseLattice nextGen method dosen't have a"
329                 ~ "\"" ~ behaviour ~"\" behaviour");
330         }
331     }
332 
333     void nextGen()
334     {
335         nextGen!"correct"();
336     }
337 
338     int[2] getLatticeBounds()
339     out(result)
340     {
341         assert(result[0] > 0 && result[1] > 0);
342     }
343     body
344     {
345         return [width, height];
346     }
347 }
348 
349 
350 
351 version(unittest)
352 {
353     import caLib_abstract.lattice : isLattice;
354     import caLib_abstract.neighbourhood : Neighbourhood;
355 }
356 
357 
358 
359 unittest
360 {
361     alias Lattice = TwoDimDenseLattice!(int, Neighbourhood!2);
362     static assert( isLattice!(Lattice, int, 2));
363 }