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