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 import caLib_abstract.neighbourhood : Neighbourhood; 38 39 40 41 /** 42 * Tests if something is a $(B Lattice). 43 * 44 * returns `true` if `T` is a $(B Lattice) of $(I dimension) `N`, Storing cells of type `Ct`. 45 * 46 * A $(B Lattice) is the most basic form of a $(LATTICE). 47 * It must define the functions: $(BR) 48 * `Ct get(string)(Coord)`, `Ct get(Coord)`, $(BR) 49 * `void set(string)(Coord, Ct)`, `void set(Coord, Ct)`, $(BR) 50 * `Ct[] getNeighbours(string)(Coord)`, `Ct[] getNeighbours(Coord)`, $(BR) 51 * `void iterate(string)(ubyte delegate(Ct cellState, Ct[] neighbours, Coord c))`, 52 * `void iterate(ubyte delegate(Ct cellState, Ct[] neighbours, Coord c))`, $(BR) 53 * `void nextGen(string)()`, `void nextGen()`, $(BR) 54 * Where `Coord` is an alias for a typetuple containing `int`'s, one `int` for each 55 * $(I dimension) (in a 3 dimensional $(B Lattice) `Coord` would be: `(int, int, int)`). 56 * 57 * Params: 58 * T = type to be tested 59 * Ct = type of the cells the $(B Lattice) should contain 60 * N = number of dimensions 61 * 62 * Returns: true if T is a $(B Lattice), false if not 63 */ 64 template isLattice(T, Ct, uint N) 65 { 66 alias Coord = Repeat!(N, int); 67 68 static if(hasCellStateType!T && hasDimension!T && hasNeighbourhoodType!T) 69 { 70 enum isLattice = 71 T.Dimension == N && 72 is(T.CellStateType : Ct) && 73 isNeighbourhood!(T.NeighbourhoodType, N) && 74 is(typeof(T.init.get!"_test"(Coord.init)) : Ct) && 75 is(typeof(T.init.get(Coord.init)) : Ct) && 76 is(typeof(T.init.set!"_test"(Coord.init, Ct.init)) : void) && 77 is(typeof(T.init.set(Coord.init, Ct.init)) : void) && 78 is(typeof(T.init.getNeighbours!"_test"(Coord.init)) : Ct[]) && 79 is(typeof(T.init.getNeighbours(Coord.init)) : Ct[]) && 80 is(typeof(T.init.iterate!"_test"((Ct cellState, Ct[] neighbours, Coord c) 81 { return Ct.init; })) : void) && 82 is(typeof(T.init.iterate((Ct cellState, Ct[] neighbours, Coord c) 83 { return Ct.init; })) : void) && 84 is(typeof(T.init.nextGen!"_test"()) : void) && 85 is(typeof(T.init.nextGen()) : void); 86 } 87 else 88 { 89 enum isLattice = false; 90 } 91 92 } 93 94 unittest 95 { 96 static assert( isLattice!(Lattice!(int, 1), int, 1)); 97 static assert( isLattice!(Lattice!(int, 2), int, 2)); 98 static assert( isLattice!(Lattice!(int, 3), int, 3)); 99 100 static assert(!isLattice!(Lattice!(int, 3), uint, 2)); 101 static assert(!isLattice!(Lattice!(int, 1), uint, 1)); 102 } 103 104 105 106 /// $(IS_ANY Lattice) 107 template isAnyLattice(T) 108 { 109 static if(hasCellStateType!T && hasDimension!T) 110 enum isAnyLattice = isLattice!(T, T.CellStateType, T.Dimension); 111 else 112 enum isAnyLattice = false; 113 } 114 115 unittest 116 { 117 static assert( isAnyLattice!(Lattice!(char, 1))); 118 static assert( isAnyLattice!(BoundedLattice!(float, 2))); 119 static assert(!isAnyLattice!string); 120 } 121 122 123 124 /// Example of a $(B Lattice) 125 struct Lattice(Ct, uint N, neighbourhood=Neighbourhood!N) 126 if(isNeighbourhood!(neighbourhood, N)) 127 { 128 alias CellStateType = Ct; 129 alias NeighbourhoodType = neighbourhood; 130 enum uint Dimension = N; 131 132 alias Coord = Repeat!(N, int); 133 134 Ct get(string s)(Coord) { return Ct.init; } 135 Ct get(Coord) { return Ct.init; } 136 137 void set(string s)(Coord, Ct) {} 138 void set(Coord, Ct) {} 139 140 Ct[] getNeighbours(string s)(Coord) { return new Ct[0]; } 141 Ct[] getNeighbours(Coord) { return new Ct[0]; } 142 143 void iterate(string s)(Ct delegate(Ct, Ct[], Coord)) {} 144 void iterate(Ct delegate(Ct, Ct[], Coord)) {} 145 146 void nextGen(string s)() {} 147 void nextGen() {} 148 } 149 150 /// 151 unittest 152 { 153 static assert(isLattice!(Lattice!(int, 2), int, 2)); 154 static assert(isAnyLattice!(Lattice!(char, 3))); 155 } 156 157 158 159 /** 160 * Tests if something is a $(B BoundedLattice). 161 * 162 * returns `true` if `T` is a $(B BoundedLattice) of $(I dimension) `N`, Storing cells of type `Ct`. 163 * False if not. 164 * 165 * A $(B BoundedLattice) is a $(LATTICE) with a fixed size. It's function `getLatticeBounds` 166 * returns a list of `uint`'s representing the length of the $(I lattice's) $(I dimensions) 167 * 168 * A $(B BoundedLattice) is a $(B Lattice) with the additional function: `void getLatticeBounds()`. 169 * 170 * Params: 171 * T = type to be tested 172 * Ct = type of the cells the $(B BoundedLattice) should contain 173 * N = number of dimensions 174 * 175 * Returns: true if T is a $(B BoundedLattice), false if not 176 */ 177 template isBoundedLattice(T, Ct, uint N) 178 { 179 alias Coord = Repeat!(N, int); 180 181 enum isBoundedLattice = 182 isLattice!(T, Ct, N) && 183 is(typeof(T.init.getLatticeBounds()) : int[N]); 184 } 185 186 unittest 187 { 188 static assert( isLattice!(BoundedLattice!(int, 1), int, 1)); 189 static assert( isLattice!(BoundedLattice!(int, 2), int, 2)); 190 static assert( isLattice!(BoundedLattice!(int, 3), int, 3)); 191 static assert( isBoundedLattice!(BoundedLattice!(int, 1), int, 1)); 192 static assert( isBoundedLattice!(BoundedLattice!(int, 2), int, 2)); 193 static assert( isBoundedLattice!(BoundedLattice!(int, 3), int, 3)); 194 195 static assert(!isBoundedLattice!(BoundedLattice!(int, 3), uint, 2)); 196 static assert(!isBoundedLattice!(BoundedLattice!(int, 1), uint, 1)); 197 } 198 199 200 201 ///$(IS_ANY BoundedLattice) 202 template isAnyBoundedLattice(T) 203 { 204 static if(hasCellStateType!T && hasDimension!T) 205 enum isAnyBoundedLattice = isBoundedLattice!(T, T.CellStateType, T.Dimension); 206 else 207 enum isAnyBoundedLattice = false; 208 } 209 210 unittest 211 { 212 static assert(!isAnyBoundedLattice!(Lattice!(char, 1))); 213 static assert( isAnyBoundedLattice!(BoundedLattice!(float, 2))); 214 static assert(!isAnyBoundedLattice!string); 215 } 216 217 218 219 /// Example of a $(B BoundedLattice) 220 struct BoundedLattice(Ct, uint N) 221 { 222 Lattice!(Ct, N) lattice; 223 alias lattice this; 224 225 int[N] getLatticeBounds() { 226 // "return int[N]"" makes compiler think 227 // "int[N]" is a call to "opIndex" 228 int[N] a; return a.init; 229 } 230 } 231 232 /// 233 unittest 234 { 235 static assert(isBoundedLattice!(BoundedLattice!(int, 3), int, 3)); 236 static assert(isAnyLattice!(BoundedLattice!(char, 7))); 237 }