Commit | Line | Data |
---|---|---|
f7f0bfe5 LW |
1 | class CubeState { |
2 | public Integer index; | |
3 | public boolean alive; | |
4 | public List<Integer> neighbors; | |
5 | ||
6 | public CubeState(Integer index, boolean alive, List<Integer> neighbors) { | |
7 | this.index = index; | |
8 | this.alive = alive; | |
9 | this.neighbors = neighbors; | |
10 | } | |
11 | } | |
12 | ||
13 | class Life extends SCPattern { | |
14 | public final int TIME_BETWEEN_RUNS = 100; | |
15 | public final int MAX_DEAD_BRIGHTNESS = 40; | |
16 | private final SinLFO xPos = new SinLFO(0, model.xMax, 5000); | |
17 | private final SinLFO yPos = new SinLFO(0, model.yMax, 5000); | |
18 | ||
19 | public List<CubeState> cube_states; | |
20 | public int time_since_last_run; | |
21 | public boolean any_changes_this_run; | |
22 | ||
23 | public Life(GLucose glucose) { | |
24 | super(glucose); | |
1c56d2f1 | 25 | outputCubeInfo(); |
f7f0bfe5 LW |
26 | initCubeStates(); |
27 | time_since_last_run = 0; | |
28 | any_changes_this_run = false; | |
29 | addModulator(xPos).trigger(); | |
30 | addModulator(yPos).trigger(); | |
31 | } | |
32 | ||
33 | public void run(double deltaMs) { | |
34 | Integer i = 0; | |
35 | CubeState cube_state; | |
36 | ||
37 | time_since_last_run += deltaMs; | |
38 | ||
39 | if(time_since_last_run < TIME_BETWEEN_RUNS) { | |
40 | return; | |
41 | } | |
42 | any_changes_this_run = false; | |
43 | ||
44 | for (Cube cube : model.cubes) { | |
45 | cube_state = this.cube_states.get(i); | |
46 | ||
47 | if(shouldBeAlive(i)) { | |
48 | lightLiveCube(cube); | |
49 | } else { | |
50 | lightDeadCube(cube); | |
51 | } | |
52 | i++; | |
53 | } | |
54 | ||
55 | if(!any_changes_this_run) { | |
56 | randomizeCubeStates(); | |
57 | } | |
58 | ||
59 | time_since_last_run = 0; | |
60 | } | |
61 | ||
62 | public void outputCubeInfo() { | |
63 | int i = 0; | |
64 | for (Cube c : model.cubes) { | |
65 | print("Cube " + i + ": " + c.x + "," + c.y + "," + c.z + "\n"); | |
66 | ++i; | |
67 | } | |
68 | print("Edgeheight: " + Cube.EDGE_HEIGHT + "\n"); | |
69 | print("Edgewidth: " + Cube.EDGE_WIDTH + "\n"); | |
70 | print("Channelwidth: " + Cube.CHANNEL_WIDTH + "\n"); | |
71 | } | |
72 | ||
73 | private void initCubeStates() { | |
74 | List<Integer> neighbors; | |
75 | boolean alive = false; | |
76 | CubeState cube_state; | |
77 | this.cube_states = new LinkedList<CubeState>(); | |
78 | Integer i = 0; | |
79 | ||
80 | for (Cube c : model.cubes) { | |
81 | neighbors = findCubeNeighbors(c, i); | |
1c56d2f1 | 82 | alive = true; |
f7f0bfe5 LW |
83 | cube_state = new CubeState(i, alive, neighbors); |
84 | this.cube_states.add(cube_state); | |
85 | ++i; | |
86 | } | |
87 | } | |
88 | ||
89 | private void randomizeCubeStates() { | |
1c56d2f1 LW |
90 | print("randomizing!\n"); |
91 | ||
92 | float f = (xPos.getValuef() / model.xMax) * 10; | |
93 | int mod_value = max(2, (int) f); | |
94 | ||
95 | for (CubeState cube_state: this.cube_states) { | |
96 | if( (cube_state.index % mod_value == 0) == cube_state.alive) { | |
f7f0bfe5 LW |
97 | cube_state.alive = !cube_state.alive; |
98 | } | |
99 | } | |
100 | } | |
101 | ||
102 | public List<Integer> findCubeNeighbors(Cube cube, Integer index) { | |
103 | List<Integer> neighbors = new LinkedList<Integer>(); | |
104 | Integer i = 0; | |
105 | ||
106 | for (Cube c : model.cubes) { | |
107 | if(index == i) { | |
108 | i++; | |
109 | continue; | |
110 | } | |
111 | ||
112 | if(abs(c.x - cube.x) < (Cube.EDGE_WIDTH * 2) && abs(c.y - cube.y) < (Cube.EDGE_HEIGHT * 2)) { | |
1c56d2f1 | 113 | print("Cube " + i + " is a neighbor of " + index + "\n"); |
f7f0bfe5 LW |
114 | neighbors.add(i); |
115 | } | |
116 | ||
117 | i++; | |
118 | } | |
119 | ||
120 | return neighbors; | |
121 | } | |
122 | ||
123 | public boolean shouldBeAlive(Integer index) { | |
124 | CubeState cube_state = this.cube_states.get(index); | |
125 | Integer alive_neighbor_count = countLiveNeighbors(cube_state); | |
126 | ||
127 | boolean before_alive = cube_state.alive; | |
128 | ||
129 | if(cube_state.alive) { | |
130 | if(alive_neighbor_count < 2 || alive_neighbor_count > 3) { | |
131 | cube_state.alive = false; | |
132 | } else { | |
133 | cube_state.alive = true; | |
134 | } | |
135 | ||
136 | } else { | |
137 | if(alive_neighbor_count == 3) { | |
138 | cube_state.alive = true; | |
139 | } else { | |
140 | cube_state.alive = false; | |
141 | } | |
142 | } | |
143 | ||
144 | this.cube_states.set(index, cube_state); | |
145 | ||
146 | if(before_alive != cube_state.alive) { | |
147 | any_changes_this_run = true; | |
148 | } | |
149 | return cube_state.alive; | |
150 | } | |
151 | ||
152 | public Integer countLiveNeighbors(CubeState cube_state) { | |
153 | Integer count = 0; | |
154 | CubeState neighbor_cube_state; | |
155 | ||
156 | for(Integer neighbor_index: cube_state.neighbors) { | |
157 | neighbor_cube_state = this.cube_states.get(neighbor_index); | |
158 | if(neighbor_cube_state.alive) { | |
159 | count++; | |
160 | } | |
161 | } | |
162 | ||
163 | return count; | |
164 | } | |
165 | ||
166 | public void lightLiveCube(Cube cube) { | |
167 | for (LXPoint p : cube.points) { | |
168 | float hv = max(0, lx.getBaseHuef() - abs(p.x - xPos.getValuef())); | |
169 | float bv = max(0, 100 - abs(p.y - yPos.getValuef())); | |
170 | colors[p.index] = lx.hsb( | |
171 | hv, | |
172 | 100, | |
173 | //bv | |
174 | 75 | |
175 | ); | |
176 | } | |
177 | } | |
178 | ||
179 | public void lightDeadCube(Cube cube) { | |
180 | for (LXPoint p : cube.points) { | |
181 | float hv = max(0, lx.getBaseHuef() - abs(p.x - xPos.getValuef())); | |
182 | float bv = max(0, MAX_DEAD_BRIGHTNESS - abs(p.y - yPos.getValuef())); | |
183 | ||
184 | colors[p.index] = lx.hsb( | |
185 | hv, | |
186 | 100, | |
187 | //bv | |
188 | 10 | |
189 | ); | |
190 | } | |
191 | } | |
192 | ||
193 | } |