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