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 }