1 /** 2 * This module defines the notion of a $(LATTICE). A $(LATTICE) is the 3 * data structure in wich all the $(I cells) are stored. Each generation, 4 * a $(RULE) changes the cells in the $(LATTICE). The most common example 5 * of a $(LATTICE) is a infinite square grid. Each square is the $(I cell) and it 6 * can contain any data such as a number or color. All of the $(I cells) then 7 * have a x,y coordinates associated with them. But some $(LATTICE)s can have 8 * other $(I dimensions), like a 3-dimensional grid of cubes where each cube have an 9 * x,y,z coordinate. Or it can have som other shape, like a grid with hexagons 10 * instead of squares. The only limitation is that the coordinates must be integers. 11 * 12 * This module provides templates for testing whether a given object is a $(LATTICE), 13 * and what kind of $(LATTICE) it is. 14 * 15 * $(CALIB_ABSTRACT_DESC) 16 * 17 * Macros: 18 * IS_ANY = 19 * Tests if something is a $(B $0). 20 * $(DDOC_BLANKLINE) 21 * returns $(DDOC_BACKQUOTED true) if $(DDOC_BACKQUOTED T) is a $(B $0). of 22 * any $(I dimension), Storing any type of cells. 23 * $(DDOC_BLANKLINE) 24 * This template is the same as $(B is$0) but the $(I dimension) and type 25 * of cells need not be specified. Refer to $(B is$0) for more details about 26 * what a $(B $0) is. 27 * $(DDOC_BLANKLINE) 28 * $(DDOC_PARAMS T type to be tested) 29 * $(DDOC_RETURNS $(B true) if $(B T) is any $(B $0), $(B false) if not) 30 */ 31 32 module caLib_abstract.lattice; 33 34 import std.meta : Repeat; 35 import caLib_abstract.util : hasCellStateType, hasDimension, hasNeighbourhoodType; 36 import caLib_abstract.neighbourhood : isNeighbourhood; 37 38 39 40 /** 41 * Tests if something is a $(B Lattice). 42 * 43 * returns `true` if `T` is a $(B Lattice) of $(I dimension) `N`, Storing cells of type `Ct`. 44 * 45 * A $(B Lattice) is the most basic form of a $(LATTICE). 46 * It must define the functions: $(BR) 47 * `Ct get(string)(Coord)`, `Ct get(Coord)`, $(BR) 48 * `void set(string)(Coord, Ct)`, `void set(Coord, Ct)`, $(BR) 49 * `Ct[] getNeighbours(string)(Coord)`, `Ct[] getNeighbours(Coord)`, $(BR) 50 * `void iterate(string)(void delegate(Coord position))`, `void iterate(void delegate(Coord position))`, $(BR) 51 * `void nextGen(string)()`, `void nextGen()`, $(BR) 52 * Where `Coord` is an alias for a typetuple containing `int`'s, one `int` for each 53 * $(I dimension) (in a 3 dimensional $(B Lattice) `Coord` would be: `(int, int, int)`). 54 * 55 * Params: 56 * T = type to be tested 57 * Ct = type of the cells the $(B Lattice) should contain 58 * N = number of dimensions 59 * 60 * Returns: true if T is a $(B Lattice), false if not 61 */ 62 template isLattice(T, Ct, uint N) 63 { 64 alias Coord = Repeat!(N, int); 65 66 static if(hasCellStateType!T && hasDimension!T && hasNeighbourhoodType!T) 67 { 68 enum isLattice = 69 T.Dimension == N && 70 is(T.CellStateType : Ct) && 71 isNeighbourhood!(T.NeighbourhoodType, N) && 72 is(typeof(T.init.get!"_test"(Coord.init)) : Ct) && 73 is(typeof(T.init.get(Coord.init)) : Ct) && 74 is(typeof(T.init.set!"_test"(Coord.init, Ct.init)) : void) && 75 is(typeof(T.init.set(Coord.init, Ct.init)) : void) && 76 is(typeof(T.init.getNeighbours!"_test"(Coord.init)) : Ct[]) && 77 is(typeof(T.init.getNeighbours(Coord.init)) : Ct[]) && 78 is(typeof(T.init.iterate!"_test"((Coord c) {})) : void) && 79 is(typeof(T.init.iterate((Coord c) {})) : void) && 80 is(typeof(T.init.nextGen!"_test"()) : void) && 81 is(typeof(T.init.nextGen()) : void); 82 } 83 else 84 { 85 enum isLattice = false; 86 } 87 88 } 89 90 unittest 91 { 92 static assert( isLattice!(Lattice!(int, 1), int, 1)); 93 static assert( isLattice!(Lattice!(int, 2), int, 2)); 94 static assert( isLattice!(Lattice!(int, 3), int, 3)); 95 96 static assert(!isLattice!(Lattice!(int, 3), uint, 2)); 97 static assert(!isLattice!(Lattice!(int, 1), uint, 1)); 98 } 99 100 101 102 ///$(IS_ANY Lattice) 103 template isAnyLattice(T) 104 { 105 static if(hasCellStateType!T && hasDimension!T) 106 enum isAnyLattice = isLattice!(T, T.CellStateType, T.Dimension); 107 else 108 enum isAnyLattice = false; 109 } 110 111 unittest 112 { 113 static assert( isAnyLattice!(Lattice!(char, 1))); 114 static assert( isAnyLattice!(BoundedLattice!(float, 2))); 115 static assert( isAnyLattice!(BlockLattice!(int, 3))); 116 static assert(!isAnyLattice!string); 117 } 118 119 120 121 /** 122 * Tests if something is a $(B BoundedLattice). 123 * 124 * returns `true` if `T` is a $(B BoundedLattice) of $(I dimension) `N`, Storing cells of type `Ct`. 125 * False if not. 126 * 127 * A $(B BoundedLattice) is a $(LATTICE) with a fixed size. It's function `getLatticeBounds` 128 * returns a list of `uint`'s representing the length of the $(I lattice's) $(I dimensions) 129 * 130 * A $(B BoundedLattice) is a $(B Lattice) with the additional function: `void getLatticeBounds()`. 131 * 132 * Params: 133 * T = type to be tested 134 * Ct = type of the cells the $(B BoundedLattice) should contain 135 * N = number of dimensions 136 * 137 * Returns: true if T is a $(B BoundedLattice), false if not 138 */ 139 template isBoundedLattice(T, Ct, uint N) 140 { 141 alias Coord = Repeat!(N, int); 142 143 enum isBoundedLattice = 144 isLattice!(T, Ct, N) && 145 is(typeof(T.init.getLatticeBounds()) : uint[N]); 146 } 147 148 unittest 149 { 150 static assert( isLattice!(BoundedLattice!(int, 1), int, 1)); 151 static assert( isLattice!(BoundedLattice!(int, 2), int, 2)); 152 static assert( isLattice!(BoundedLattice!(int, 3), int, 3)); 153 static assert( isBoundedLattice!(BoundedLattice!(int, 1), int, 1)); 154 static assert( isBoundedLattice!(BoundedLattice!(int, 2), int, 2)); 155 static assert( isBoundedLattice!(BoundedLattice!(int, 3), int, 3)); 156 157 static assert(!isBoundedLattice!(BoundedLattice!(int, 3), uint, 2)); 158 static assert(!isBoundedLattice!(BoundedLattice!(int, 1), uint, 1)); 159 } 160 161 162 163 ///$(IS_ANY BoundedLattice) 164 template isAnyBoundedLattice(T) 165 { 166 static if(hasCellStateType!T && hasDimension!T) 167 enum isAnyBoundedLattice = isBoundedLattice!(T, T.CellStateType, T.Dimension); 168 else 169 enum isAnyBoundedLattice = false; 170 } 171 172 unittest 173 { 174 static assert(!isAnyBoundedLattice!(Lattice!(char, 1))); 175 static assert( isAnyBoundedLattice!(BoundedLattice!(float, 2))); 176 static assert(!isAnyBoundedLattice!(BlockLattice!(int, 3))); 177 static assert(!isAnyBoundedLattice!string); 178 } 179 180 181 182 /** 183 * Tests if something is a $(B BlockLattice). 184 * 185 * returns `true` if `T` is a $(B BlockLattice) of $(I dimension) `N`, Storing cells of type `Ct`. 186 * 187 * A $(B BlockLattice) is a $(B Lattice) with the additional functions: $(BR) 188 * `Ct[] getBlock(string)(Coord)`, `Ct[] getBlock(Coord)`, $(BR) 189 * `void setBlock(string)(Coord, Ct[])`, `void setBlock(Coord, Ct[])`, $(BR) 190 * `void iterateBlocks(string)(void delegate(Coord position))`, `void iterate(void delegate(Coord position))`, $(BR) 191 * Where `Coord` is an alias for a typetuple containing `int`'s, one `int` for each 192 * $(I dimension) (in a 3 dimensional $(B BlockLattice) `Coord` would be: `(int, int, int)`). 193 * 194 * Params: 195 * T = type to be tested 196 * Ct = type of the cells the $(B BlockLattice) should contain 197 * N = number of dimensions 198 * 199 * Returns: true if T is a $(B BlockLattice), false if not 200 */ 201 template isBlockLattice(T, Ct, uint N) 202 { 203 alias Coord = Repeat!(N, int); 204 205 enum isBlockLattice = 206 isLattice!(T, Ct, N) && 207 is(typeof(T.init.getBlock!""(Coord.init)) : Ct[]) && 208 is(typeof(T.init.getBlock(Coord.init)) : Ct[]) && 209 is(typeof(T.init.setBlock!""(Coord.init, Ct[].init)) : void) && 210 is(typeof(T.init.setBlock(Coord.init, Ct[].init)) : void) && 211 is(typeof(T.init.iterateBlocks!""((Coord c) {})) : void) && 212 is(typeof(T.init.iterateBlocks((Coord c) {})) : void); 213 } 214 215 unittest 216 { 217 static assert( isLattice!(BlockLattice!(int, 1), int, 1)); 218 static assert( isLattice!(BlockLattice!(int, 2), int, 2)); 219 static assert( isLattice!(BlockLattice!(int, 3), int, 3)); 220 static assert( isBlockLattice!(BlockLattice!(int, 1), int, 1)); 221 static assert( isBlockLattice!(BlockLattice!(int, 2), int, 2)); 222 static assert( isBlockLattice!(BlockLattice!(int, 3), int, 3)); 223 224 static assert(!isBlockLattice!(BlockLattice!(int, 3), uint, 2)); 225 static assert(!isBlockLattice!(BlockLattice!(int, 1), uint, 1)); 226 } 227 228 229 230 ///$(IS_ANY BlockLattice) 231 template isAnyBlockLattice(T) 232 { 233 static if(hasCellStateType!T && hasDimension!T) 234 enum isAnyBlockLattice = isBlockLattice!(T, T.CellStateType, T.Dimension); 235 else 236 enum isAnyBlockLattice = false; 237 } 238 239 unittest 240 { 241 static assert(!isAnyBlockLattice!(Lattice!(char, 1))); 242 static assert(!isAnyBlockLattice!(BoundedLattice!(float, 2))); 243 static assert( isAnyBlockLattice!(BlockLattice!(int, 3))); 244 static assert(!isAnyBlockLattice!string); 245 } 246 247 248 249 version(unittest) 250 { 251 import caLib_abstract.neighbourhood : Neighbourhood; 252 253 struct Lattice(Ct, uint N) 254 { 255 alias CellStateType = Ct; 256 alias NeighbourhoodType = Neighbourhood!Dimension; 257 enum uint Dimension = N; 258 259 alias Coord = Repeat!(N, int); 260 261 Ct get(string s)(Coord) { return Ct.init; } 262 Ct get(Coord) { return Ct.init; } 263 264 void set(string s)(Coord, Ct) {} 265 void set(Coord, Ct) {} 266 267 Ct[] getNeighbours(string s)(Coord) { return new Ct[0]; } 268 Ct[] getNeighbours(Coord) { return new Ct[0]; } 269 270 void iterate(string s)(void delegate(Coord)) {} 271 void iterate(void delegate(Coord)) {} 272 273 void nextGen(string s)() {} 274 void nextGen() {} 275 } 276 277 struct BoundedLattice(Ct, uint N) 278 { 279 Lattice!(Ct, N) lattice; 280 alias lattice this; 281 282 uint[N] getLatticeBounds() { 283 // "return uint[N]"" makes compiler think 284 // "uint[N]" is a call to "opIndex" 285 uint[N] a; return a.init; 286 } 287 } 288 289 struct BlockLattice(Ct, uint N) 290 { 291 alias Coord = Repeat!(N, int); 292 293 Lattice!(Ct, N) lattice; 294 alias lattice this; 295 296 Ct[] getBlock(string behaviour)(Coord){ return new Ct[0]; } 297 Ct[] getBlock()(Coord) { return new Ct[0]; } 298 299 void setBlock(string behaviour)(Coord, Ct[]) {} 300 void setBlock()(Coord, Ct[]) {} 301 302 void iterateBlocks(string s)(void delegate(Coord) d) {} 303 void iterateBlocks()(void delegate(Coord) d) {} 304 } 305 }