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 modulecaLib_abstract.lattice;
33 34 importstd.meta : Repeat;
35 importcaLib_abstract.util : hasCellStateType, hasDimension, hasNeighbourhoodType;
36 importcaLib_abstract.neighbourhood : isNeighbourhood;
37 importcaLib_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 templateisLattice(T, Ct, uintN)
65 {
66 aliasCoord = Repeat!(N, int);
67 68 staticif(hasCellStateType!T && hasDimension!T && hasNeighbourhoodType!T)
69 {
70 enumisLattice =
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"((CtcellState, Ct[] neighbours, Coordc)
81 { returnCt.init; })) : void) &&
82 is(typeof(T.init.iterate((CtcellState, Ct[] neighbours, Coordc)
83 { returnCt.init; })) : void) &&
84 is(typeof(T.init.nextGen!"_test"()) : void) &&
85 is(typeof(T.init.nextGen()) : void);
86 }
87 else88 {
89 enumisLattice = false;
90 }
91 92 }
93 94 unittest95 {
96 staticassert( isLattice!(Lattice!(int, 1), int, 1));
97 staticassert( isLattice!(Lattice!(int, 2), int, 2));
98 staticassert( isLattice!(Lattice!(int, 3), int, 3));
99 100 staticassert(!isLattice!(Lattice!(int, 3), uint, 2));
101 staticassert(!isLattice!(Lattice!(int, 1), uint, 1));
102 }
103 104 105 106 /// $(IS_ANY Lattice)107 templateisAnyLattice(T)
108 {
109 staticif(hasCellStateType!T && hasDimension!T)
110 enumisAnyLattice = isLattice!(T, T.CellStateType, T.Dimension);
111 else112 enumisAnyLattice = false;
113 }
114 115 unittest116 {
117 staticassert( isAnyLattice!(Lattice!(char, 1)));
118 staticassert( isAnyLattice!(BoundedLattice!(float, 2)));
119 staticassert(!isAnyLattice!string);
120 }
121 122 123 124 /// Example of a $(B Lattice)125 structLattice(Ct, uintN, neighbourhood=Neighbourhood!N)
126 if(isNeighbourhood!(neighbourhood, N))
127 {
128 aliasCellStateType = Ct;
129 aliasNeighbourhoodType = neighbourhood;
130 enumuintDimension = N;
131 132 aliasCoord = Repeat!(N, int);
133 134 Ctget(strings)(Coord) { returnCt.init; }
135 Ctget(Coord) { returnCt.init; }
136 137 voidset(strings)(Coord, Ct) {}
138 voidset(Coord, Ct) {}
139 140 Ct[] getNeighbours(strings)(Coord) { returnnewCt[0]; }
141 Ct[] getNeighbours(Coord) { returnnewCt[0]; }
142 143 voiditerate(strings)(Ctdelegate(Ct, Ct[], Coord)) {}
144 voiditerate(Ctdelegate(Ct, Ct[], Coord)) {}
145 146 voidnextGen(strings)() {}
147 voidnextGen() {}
148 }
149 150 ///151 unittest152 {
153 staticassert(isLattice!(Lattice!(int, 2), int, 2));
154 staticassert(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 templateisBoundedLattice(T, Ct, uintN)
178 {
179 aliasCoord = Repeat!(N, int);
180 181 enumisBoundedLattice =
182 isLattice!(T, Ct, N) &&
183 is(typeof(T.init.getLatticeBounds()) : int[N]);
184 }
185 186 unittest187 {
188 staticassert( isLattice!(BoundedLattice!(int, 1), int, 1));
189 staticassert( isLattice!(BoundedLattice!(int, 2), int, 2));
190 staticassert( isLattice!(BoundedLattice!(int, 3), int, 3));
191 staticassert( isBoundedLattice!(BoundedLattice!(int, 1), int, 1));
192 staticassert( isBoundedLattice!(BoundedLattice!(int, 2), int, 2));
193 staticassert( isBoundedLattice!(BoundedLattice!(int, 3), int, 3));
194 195 staticassert(!isBoundedLattice!(BoundedLattice!(int, 3), uint, 2));
196 staticassert(!isBoundedLattice!(BoundedLattice!(int, 1), uint, 1));
197 }
198 199 200 201 ///$(IS_ANY BoundedLattice)202 templateisAnyBoundedLattice(T)
203 {
204 staticif(hasCellStateType!T && hasDimension!T)
205 enumisAnyBoundedLattice = isBoundedLattice!(T, T.CellStateType, T.Dimension);
206 else207 enumisAnyBoundedLattice = false;
208 }
209 210 unittest211 {
212 staticassert(!isAnyBoundedLattice!(Lattice!(char, 1)));
213 staticassert( isAnyBoundedLattice!(BoundedLattice!(float, 2)));
214 staticassert(!isAnyBoundedLattice!string);
215 }
216 217 218 219 /// Example of a $(B BoundedLattice)220 structBoundedLattice(Ct, uintN)
221 {
222 Lattice!(Ct, N) lattice;
223 aliaslatticethis;
224 225 int[N] getLatticeBounds() {
226 // "return int[N]"" makes compiler think227 // "int[N]" is a call to "opIndex"228 int[N] a; returna.init;
229 }
230 }
231 232 ///233 unittest234 {
235 staticassert(isBoundedLattice!(BoundedLattice!(int, 3), int, 3));
236 staticassert(isAnyLattice!(BoundedLattice!(char, 7)));
237 }