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