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 }