1 module caLib.simulations.HppLatticeGasSimulation; 2 3 import std.algorithm.searching : countUntil; 4 import caLib.lattices.TwoDimDenseLattice; 5 import caLib.renderers.TwoDimBasicRenderer; 6 import caLib_util.structs : Simulation, create_Simulation; 7 import caLib_util.structs : Color; 8 9 public import caLib_util.graphics : Window; 10 11 import std.stdio; 12 13 14 15 auto create_HppLatticeGasSimulation(int width, int height, 16 ubyte delegate(int x, int y) initialCondition, Window window) 17 { 18 auto lattice = create_TwoDimDenseLattice(width, height, 19 new DummyNeighbourhood(), ubyte(0), initialCondition); 20 21 auto rule = new HppLatticeGasRule(lattice); 22 23 auto renderer = create_TwoDimBasicRenderer(lattice, new HppLatticeGasPalette(), window); 24 25 return create_Simulation(lattice, rule, renderer); 26 } 27 28 29 30 struct HppLatticeGasRule 31 { 32 33 private: 34 35 alias Lt = TwoDimDenseLattice!(ubyte, DummyNeighbourhood); 36 37 Lt* lattice; 38 int latticeWidth; 39 int latticeHeight; 40 41 static immutable ubyte[] ruleSet = 42 (){ 43 ubyte[] ruleSet; 44 45 ruleSet.length = 16; 46 foreach(ubyte i; 0 .. 16) 47 { 48 ruleSet[i] = i; 49 50 if(i == 3) 51 ruleSet[i] = 12; 52 if(i == 12) 53 ruleSet[i] = 3; 54 } 55 56 ruleSet.length = 32; 57 foreach(ubyte i; 16 .. 32) 58 { 59 ruleSet[i] = 60 (i << 1 & 2) + 61 (i >> 1 & 1) + 62 (i << 1 & 8) + 63 (i >> 1 & 4) + 64 16; 65 } 66 67 return ruleSet; 68 }(); 69 70 public: 71 72 this(Lt* lattice) 73 { 74 this.lattice = lattice; 75 this.latticeWidth = lattice.getLatticeBounds[0]; 76 this.latticeHeight = lattice.getLatticeBounds[1]; 77 } 78 79 void applyRule() 80 { 81 foreach(y; 0 .. latticeHeight) 82 { 83 foreach(x; 0 .. latticeWidth) 84 { 85 ubyte afterTransportation = 86 (lattice.get!"torus"(x+1, y) & 1) + 87 (lattice.get!"torus"(x-1, y) & 2) + 88 (lattice.get!"torus"(x, y+1) & 4) + 89 (lattice.get!"torus"(x, y-1) & 8) + 90 (lattice.get!"bounded-assumeInBounds"(x,y) & 16); 91 92 ubyte afterCollision = ruleSet[afterTransportation]; 93 94 lattice.set!"bounded-assumeInBounds"(x, y, afterCollision); 95 } 96 } 97 lattice.nextGen(); 98 } 99 100 void applyRuleReverse() {} 101 } 102 103 104 105 private struct HppLatticeGasPalette 106 { 107 alias CellStateType = ubyte; 108 alias DisplayValueType = Color; 109 110 Color getDisplayValue(string behaviour)(ubyte cellState) 111 { 112 uint intensity = cast(ubyte)( 113 (cellState >> 0 & 1) + (cellState >> 1 & 1) + 114 (cellState >> 2 & 1) + (cellState >> 3 & 1)) * 255/4; 115 116 return Color(intensity + (intensity << 8) + (intensity << 16)); 117 } 118 119 Color getDisplayValue(ubyte cellState) 120 { 121 return getDisplayValue!""(cellState); 122 } 123 } 124 125 126 127 private struct DummyNeighbourhood 128 { 129 static immutable int Dimension = 2; 130 int[2][] getNeighboursCoordinates(int x, int y) { return []; } 131 } 132 133 134 135 version(unittest) 136 { 137 import caLib_abstract.neighbourhood : isNeighbourhood; 138 import caLib_abstract.rule : isReversibleRule; 139 } 140 141 142 143 unittest 144 { 145 static assert(isNeighbourhood!(DummyNeighbourhood, 2)); 146 static assert(isReversibleRule!(HppLatticeGasRule)); 147 }