1 module caLib.rules.TotalisticRule; 2 3 import std.math : pow; 4 import std.bigint; 5 import std.conv : to; 6 import std.array : appender; 7 import caLib_abstract.lattice : isAnyLattice; 8 import caLib_abstract.neighbourhood : isStaticNeighbourhood; 9 10 11 import std.stdio; 12 13 14 15 auto create_TotalisticRule(Lt)(Lt* lattice, BigInt ruleNumber) 16 { 17 return new TotalisticRule!Lt(lattice, ruleNumber); 18 } 19 20 21 22 auto create_TotalisticRule(Lt)(Lt* lattice, ubyte[] ruleSet) 23 in 24 { assert(TotalisticRule!Lt.configurations == ruleSet.length); } 25 body 26 { 27 return new TotalisticRule!Lt(lattice, ruleSet); 28 } 29 30 31 32 struct TotalisticRule(Lt) 33 if(isAnyLattice!Lt && Lt.Dimension == 2 && is(Lt.CellStateType : ubyte) 34 && isStaticNeighbourhood!(Lt.NeighbourhoodType, 2) && Lt.NeighbourhoodType.NeighboursAmount+1 < uint.max) 35 { 36 37 private: 38 39 Lt* lattice; 40 41 BigInt ruleNumber; 42 ubyte[] ruleSet; 43 44 public: 45 46 enum uint configurations = pow(2, Lt.NeighbourhoodType.NeighboursAmount+1); 47 BigInt maxRuleNumber; 48 49 this(Lt* lattice, BigInt ruleNumber) 50 in 51 { assert(ruleNumber <= calculateMaxRuleNumber); } 52 body 53 { 54 this(lattice, createRuleSetFromNumber(ruleNumber)); 55 } 56 57 58 59 this(Lt* lattice, ubyte[] ruleSet) 60 in 61 { assert(TotalisticRule!Lt.configurations == ruleSet.length); } 62 body 63 { 64 this.lattice = lattice; 65 66 this.ruleSet = ruleSet; 67 this.ruleNumber = createNumberFromRuleSet(ruleSet); 68 69 maxRuleNumber = calculateMaxRuleNumber(); 70 } 71 72 73 74 void applyRule() 75 { 76 lattice.iterate((int x, int y) 77 { 78 auto neighbours = lattice.getNeighbours(x, y); 79 80 uint n = lattice.get(x, y) << neighbours.length; 81 foreach(i; 0 .. neighbours.length) 82 { 83 n += neighbours[i] << i; 84 } 85 86 lattice.set(x, y, ruleSet[n]); 87 }); 88 89 lattice.nextGen(); 90 } 91 92 93 94 BigInt getRuleNumber() { return ruleNumber; } 95 ubyte[] getRuleSet() { return ruleSet.dup; } 96 97 98 99 private: 100 101 private static ubyte[] createRuleSetFromNumber(BigInt ruleNumber) 102 out(result) 103 { 104 assert(TotalisticRule!Lt.configurations == result.length); 105 } 106 body 107 { 108 string binaryRuleString = toBinaryString(ruleNumber); 109 110 ubyte[] ruleSet = new ubyte[TotalisticRule!Lt.configurations]; 111 foreach(i; 0 .. binaryRuleString.length) 112 { 113 ruleSet[i] = to!ubyte( 114 binaryRuleString[binaryRuleString.length-1-i] - '0'); 115 } 116 117 return ruleSet; 118 } 119 120 121 122 private static BigInt createNumberFromRuleSet(const ubyte[] ruleSet) 123 in 124 { 125 assert(TotalisticRule!Lt.configurations == ruleSet.length); 126 } 127 body 128 { 129 BigInt n = BigInt("0"); 130 foreach(i; 0 .. configurations) 131 { 132 if(ruleSet[i] == 1) 133 { 134 BigInt k = BigInt("1"); 135 foreach(j; 0 .. i) 136 { 137 k *= 2; 138 } 139 n += k; 140 } 141 } 142 return n; 143 } 144 145 146 147 private static BigInt calculateMaxRuleNumber() 148 { 149 BigInt n = BigInt("1"); 150 foreach(i; 0 .. configurations) { n *= 2; } 151 return n-1; 152 } 153 154 155 156 private static string toBinaryString(const BigInt num) 157 { 158 string hex = num.toHex(); 159 auto bin = appender!string(); 160 161 foreach(s; hex) 162 { 163 if(s != '_') 164 bin.put(hexToBinary(s)); 165 } 166 167 return bin.data; 168 } 169 170 171 172 private static string hexToBinary(char hex) 173 { 174 string bin = 175 [ 176 '0':"0000", '1':"0001", '2':"0010", '3':"0011", '4':"0100", 177 '5':"0101", '6':"0110", '7':"0111", '8':"1000", '9':"1001", 178 'A':"1010", 'B':"1011", 'C':"1100", 'D':"1101", 'E':"1110", 179 'F':"1111" 180 ].get(hex,null); 181 182 assert(bin != null); 183 return bin; 184 } 185 }