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