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 }