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 }