1 /** 2 * This module defines the notion of a $(NEIGHBOURHOOD). A $(NEIGHBOURHOOD) 3 * defines what cells in the lattice that are "neighbours". Most ca $(RULE)s 4 * change the state of a $(I cell) depending on the $(I cells) $(I neighbours). 5 * 6 * It provides templates for testing whether a given object is a $(NEIGHBOURHOOD), 7 * and what kind of $(NEIGHBOURHOOD) it is. 8 * 9 * $(CALIB_ABSTRACT_DESC) 10 * 11 * Macros: 12 * IS_ANY = 13 * Tests if something is a $(B $0). 14 * $(DDOC_BLANKLINE) 15 * returns $(DDOC_BACKQUOTED true) if $(DDOC_BACKQUOTED T) is a $(B $0). of 16 * any dimension. 17 * $(DDOC_BLANKLINE) 18 * This template is the same as $(B is$0) but the dimension need not be 19 * specified. Refer to $(B is$0) for more details about what a $(B $0) is. 20 * $(DDOC_BLANKLINE) 21 * $(DDOC_PARAMS T type to be tested) 22 * $(DDOC_RETURNS $(B true) if $(B T) is any $(B $0), $(B false) if not) 23 */ 24 25 module caLib_abstract.neighbourhood; 26 27 import std.meta : Repeat; 28 import caLib_abstract.util : hasDimension, isDimensionsCompatible; 29 30 31 32 /** 33 * Tests if something is a $(B Neighbourhood). 34 * 35 * returns `true` if `T` is a $(B Neighbourhood) of dimension `N`. 36 * 37 * A $(B Neighbourhood) is the most basic form of a $(NEIGHBOURHOOD). 38 * It's `getNeighboursCoordinates` function takes a $(I cells) position 39 * and returns a list of coordinate pairs for it's neighbours positions. 40 * 41 * It must define the primitive: $(BR)`int[N][] getNeighboursCoordinates(Coord)`. $(BR) 42 * Where N is the dimension of the $(B Neighbourhood) and `Coord` is an 43 * alias for a typetuple containing `int`'s, one `int` for each 44 * dimension (in a 3 dimensional $(B Neighbourhood) `Coord` would be: `(int, int, int)`). 45 * 46 * Params: 47 * T = type to be tested 48 * N = number of dimensions 49 * 50 * Returns: true if T is a $(B Neighbourhood), false if not 51 */ 52 53 template isNeighbourhood(T, uint N) 54 { 55 alias Coord = Repeat!(N, int); 56 57 static if(hasDimension!T) 58 { 59 enum isNeighbourhood = 60 isDimensionsCompatible!(T.Dimension, N) && 61 is(typeof(T.init.getNeighboursCoordinates(Coord.init)) : int[N][]); 62 } 63 else 64 { 65 enum isNeighbourhood = false; 66 } 67 } 68 69 /// 70 unittest 71 { 72 struct A { 73 enum uint Dimension = 2; 74 int[2][] getNeighboursCoordinates(int x, int y) { 75 return [[x+1, y+1], [x+1, y], [x+1, y-1]]; 76 } 77 } 78 79 static assert( isNeighbourhood!(A, 2)); 80 static assert(!isNeighbourhood!(string, 1)); 81 } 82 83 unittest 84 { 85 static assert( isNeighbourhood!(Neighbourhood!(1), 1)); 86 static assert( isNeighbourhood!(Neighbourhood!(2), 2)); 87 static assert( isNeighbourhood!(Neighbourhood!(3), 3)); 88 static assert(!isNeighbourhood!(Neighbourhood!(3), 2)); 89 } 90 91 92 93 ///$(IS_ANY Neighbourhood) 94 template isAnyNeighbourhood(T) 95 { 96 static if(hasDimension!T) 97 enum isAnyNeighbourhood = isNeighbourhood!(T, T.Dimension); 98 else 99 enum isAnyNeighbourhood = false; 100 } 101 102 /// 103 unittest 104 { 105 struct Foo { 106 enum uint Dimension = 2; 107 108 int[Dimension][] getNeighboursCoordinates(int x, int y) { 109 return [[x+1, y+1], [x+1, y], [x+1, y-1]]; 110 } 111 } 112 113 static assert(! isNeighbourhood!(Foo, 3)); 114 static assert( isAnyNeighbourhood!(Foo )); 115 } 116 117 unittest 118 { 119 static assert( isAnyNeighbourhood!(Neighbourhood!(1))); 120 static assert( isAnyNeighbourhood!(StaticNeighbourhood!(2))); 121 static assert(!isAnyNeighbourhood!string); 122 } 123 124 125 126 /// Example of a $(B Neighbourhood) 127 struct Neighbourhood(uint N) 128 { 129 enum uint Dimension = N; 130 131 alias Coord = Repeat!(N, int); 132 133 int[N][] getNeighboursCoordinates(Coord) { int[N][]a; return a.init; } 134 } 135 136 /// 137 unittest 138 { 139 static assert(isNeighbourhood!(Neighbourhood!(2), 2)); 140 static assert(isAnyNeighbourhood!(Neighbourhood!(4))); 141 } 142 143 144 145 /** 146 * Tests if something is a $(B StaticNeighbourhood). 147 * 148 * returns `true` if `T` is a $(B StaticNeighbourhood) of dimension `N`. 149 * 150 * A $(B StaticNeighbourhood) is a $(NEIGHBOURHOOD) that never changes. 151 * If a particular $(I cell) has a particular $(I neighbour) it will always have 152 * that $(I neighbour). Also, if a $(I cell) where to have a neighbour "to the right" 153 * all other $(I cells) will also have a neighbour "to the right". 154 * A $(B StaticNeighbourhood) dosen't really add any additional functionality. 155 * All it does is having the a uint enum NeighboursAmount. 156 * 157 * Params: 158 * T = type to be tested 159 * N = number of dimensions 160 * 161 * Returns: true if T is a $(B StaticNeighbourhood), false if not 162 */ 163 template isStaticNeighbourhood(T, uint N) 164 { 165 alias Coord = Repeat!(N, int); 166 167 enum isStaticNeighbourhood = 168 isNeighbourhood!(T, N) && 169 is(typeof(T.NeighboursAmount) : uint) && 170 is(typeof(T.init.NeighboursAmount) : uint); 171 } 172 173 /// 174 unittest 175 { 176 struct A { 177 enum uint Dimension = 2; 178 enum uint NeighboursAmount = 1; 179 enum isStatic; 180 int[2][] getNeighboursCoordinates(int x, int y) { 181 return [[x+1, y+1]]; 182 } 183 } 184 185 static assert( isNeighbourhood!(A, 2)); 186 static assert( isStaticNeighbourhood!(A, 2)); 187 static assert(!isStaticNeighbourhood!(string, 1)); 188 } 189 190 unittest 191 { 192 static assert( isStaticNeighbourhood!(StaticNeighbourhood!(1), 1)); 193 static assert( isStaticNeighbourhood!(StaticNeighbourhood!(2), 2)); 194 static assert( isStaticNeighbourhood!(StaticNeighbourhood!(3), 3)); 195 196 static assert(!isStaticNeighbourhood!(StaticNeighbourhood!(3), 2)); 197 static assert(!isStaticNeighbourhood!(Neighbourhood!(1), 1)); 198 } 199 200 201 202 ///$(IS_ANY StaticNeighbourhood) 203 template isAnyStaticNeighbourhood(T) 204 { 205 static if(hasDimension!T) 206 enum isAnyStaticNeighbourhood = isStaticNeighbourhood!(T, T.Dimension); 207 else 208 enum isAnyStaticNeighbourhood = false; 209 } 210 211 /// 212 unittest 213 { 214 struct Foo { 215 enum uint Dimension = 2; 216 enum uint NeighboursAmount = 1; 217 int[2][] getNeighboursCoordinates(int x, int y) { 218 return [[x+1, y+1]]; 219 } 220 } 221 static assert(! isStaticNeighbourhood!(Foo, 3)); 222 static assert( isAnyStaticNeighbourhood!(Foo )); 223 } 224 225 unittest 226 { 227 static assert(!isAnyStaticNeighbourhood!(Neighbourhood!(1))); 228 static assert( isAnyStaticNeighbourhood!(StaticNeighbourhood!(2))); 229 static assert(!isAnyStaticNeighbourhood!string); 230 } 231 232 233 234 /// Example of a $(B StaticNeighbourhood) 235 struct StaticNeighbourhood(uint N) 236 { 237 Neighbourhood!N neighbourhood; 238 alias neighbourhood this; 239 240 enum uint NeighboursAmount = 0; 241 } 242 243 /// 244 unittest 245 { 246 static assert(isNeighbourhood!(StaticNeighbourhood!(2), 2)); 247 static assert(isStaticNeighbourhood!(StaticNeighbourhood!(2), 2)); 248 static assert(isAnyStaticNeighbourhood!(StaticNeighbourhood!(2))); 249 }