675f52eea529a0654cd5d1e8574ea9864a2d829f
[SugarCubes.git] / L8onWallace.pde
1 class L8onLife extends SCPattern {
2 // Controls the rate of life algorithm ticks, in milliseconds
3 private BasicParameter rateParameter = new BasicParameter("DELAY", 112.5, 0.0, 1000.0);
4 // Controls if the cubes should be randomized even if something changes. Set above 0.5 to randomize cube aliveness.
5 private BasicParameter randomParameter = new BasicParameter("RAND", 0.0);
6 // Controls the brightness of dead cubes.
7 private BasicParameter deadParameter = new BasicParameter("DEAD", 25.0, 0.0, 100.0);
8 // Controls the saturation.
9 private BasicParameter saturationParameter = new BasicParameter("SAT", 90.0, 0.0, 100.0);
10
11 public final double MIN_ALIVE_PROBABILITY = 0.2;
12 public final double MAX_ALIVE_PROBABILITY = 0.9;
13
14 private final SinLFO xPos = new SinLFO(0, model.xMax, 4500);
15 private final SinLFO zPos = new SinLFO(0, model.zMax, 2500);
16
17 class CubeState {
18 // Index of cube in glucose.model.cubes
19 public Integer index;
20 // Boolean which describes if cube is alive.
21 public boolean alive;
22 // List of this cubes neighbors
23 public List<Integer> neighbors;
24
25 public CubeState(Integer index, boolean alive, List<Integer> neighbors) {
26 this.index = index;
27 this.alive = alive;
28 this.neighbors = neighbors;
29 }
30 }
31
32 // Contains the state of all cubes by index.
33 private List<CubeState> cube_states;
34 // Contains the amount of time since the last cycle of life.
35 private int time_since_last_run;
36 // Boolean describing if life changes were made during the current run.
37 private boolean any_changes_this_run;
38 // Hold the new lives
39 private List<Boolean> new_lives;
40
41 public L8onLife(GLucose glucose) {
42 super(glucose);
43
44 //Print debug info about the cubes.
45 //outputCubeInfo();
46
47 initCubeStates();
48 time_since_last_run = 0;
49 any_changes_this_run = false;
50 new_lives = new ArrayList<Boolean>();
51
52 addParameter(rateParameter);
53 addParameter(randomParameter);
54 addParameter(deadParameter);
55 addParameter(saturationParameter);
56 addModulator(xPos).trigger();
57 addModulator(zPos).trigger();
58 }
59
60 public void run(double deltaMs) {
61 Integer i = 0;
62 CubeState cube_state;
63
64 any_changes_this_run = false;
65 new_lives.clear();
66 time_since_last_run += deltaMs;
67
68 for (Cube cube : model.cubes) {
69 cube_state = this.cube_states.get(i);
70
71 if(shouldLightCube(cube_state)) {
72 lightLiveCube(cube);
73 } else {
74 lightDeadCube(cube);
75 }
76
77 i++;
78 }
79
80 boolean should_randomize_anyway = (randomParameter.getValuef() > 0.5);
81 if(should_randomize_anyway || !any_changes_this_run) {
82 randomizeCubeStates();
83 } else {
84 applyNewLives();
85 }
86
87 if(time_since_last_run >= rateParameter.getValuef()) {
88 time_since_last_run = 0;
89 }
90 }
91
92 public void lightLiveCube(Cube cube) {
93 for (LXPoint p : cube.points) {
94 float hv = max(0, lx.getBaseHuef() - abs(p.z - zPos.getValuef()));
95 colors[p.index] = lx.hsb(
96 hv,
97 saturationParameter.getValuef(),
98 75
99 );
100 }
101 }
102
103 public void lightDeadCube(Cube cube) {
104 for (LXPoint p : cube.points) {
105 float hv = max(0, lx.getBaseHuef() - abs(p.x - xPos.getValuef()));
106 double dead_bright = deadParameter.getValuef() * Math.random();
107
108 colors[p.index] = lx.hsb(
109 hv,
110 saturationParameter.getValuef(),
111 dead_bright
112 );
113 }
114 }
115
116 public void outputCubeInfo() {
117 int i = 0;
118 for (Cube c : model.cubes) {
119 print("Cube " + i + ": " + c.x + "," + c.y + "," + c.z + "\n");
120 ++i;
121 }
122 print("Edgeheight: " + Cube.EDGE_HEIGHT + "\n");
123 print("Edgewidth: " + Cube.EDGE_WIDTH + "\n");
124 print("Channelwidth: " + Cube.CHANNEL_WIDTH + "\n");
125 }
126
127 private void initCubeStates() {
128 List<Integer> neighbors;
129 boolean alive = false;
130 CubeState cube_state;
131 this.cube_states = new ArrayList<CubeState>();
132 Integer i = 0;
133
134 for (Cube c : model.cubes) {
135 neighbors = findCubeNeighbors(c, i);
136 alive = true;
137 cube_state = new CubeState(i, alive, neighbors);
138 this.cube_states.add(cube_state);
139 ++i;
140 }
141 }
142
143 private void randomizeCubeStates() {
144 double prob_range = (1.0 - MIN_ALIVE_PROBABILITY) - (1.0 - MAX_ALIVE_PROBABILITY);
145 double prob = MIN_ALIVE_PROBABILITY + (prob_range * Math.random());
146
147 //print("Randomizing cubes! p = " + prob + "\n");
148
149 for (CubeState cube_state: this.cube_states) {
150 cube_state.alive = (Math.random() <= prob);
151 }
152 }
153
154 public List<Integer> findCubeNeighbors(Cube cube, Integer index) {
155 List<Integer> neighbors = new LinkedList<Integer>();
156 Integer i = 0;
157
158 for (Cube c : model.cubes) {
159 if(index != i) {
160 if(abs(c.x - cube.x) < (Cube.EDGE_WIDTH * 2) && abs(c.y - cube.y) < (Cube.EDGE_HEIGHT * 2)) {
161 //print("Cube " + i + " is a neighbor of " + index + "\n");
162 neighbors.add(i);
163 }
164 }
165
166 i++;
167 }
168
169 return neighbors;
170 }
171
172 public boolean shouldLightCube(CubeState cube_state) {
173 // Respect rate parameter.
174 if(time_since_last_run < rateParameter.getValuef()) {
175 any_changes_this_run = true;
176 return cube_state.alive;
177 } else {
178 boolean new_life = cycleOfLife(cube_state);
179 new_lives.add(new_life);
180 return new_life;
181 }
182 }
183
184 public void applyNewLives() {
185 int index = 0;
186 for(boolean liveliness: new_lives) {
187 CubeState cube_state = this.cube_states.get(index);
188 cube_state.alive = new_lives.get(index);
189 index++;
190 }
191 }
192
193 public boolean cycleOfLife(CubeState cube_state) {
194 Integer index = cube_state.index;
195 Integer alive_neighbor_count = countLiveNeighbors(cube_state);
196 boolean before_alive = cube_state.alive;
197 boolean after_alive = before_alive;
198
199 if(cube_state.alive) {
200 if(alive_neighbor_count < 2 || alive_neighbor_count > 3) {
201 after_alive = false;
202 } else {
203 after_alive = true;
204 }
205
206 } else {
207 if(alive_neighbor_count == 2) {
208 after_alive = true;
209 } else {
210 after_alive = false;
211 }
212 }
213
214 if(before_alive != after_alive) {
215 any_changes_this_run = true;
216 }
217
218 return after_alive;
219 }
220
221 public Integer countLiveNeighbors(CubeState cube_state) {
222 Integer count = 0;
223 CubeState neighbor_cube_state;
224
225 for(Integer neighbor_index: cube_state.neighbors) {
226 neighbor_cube_state = this.cube_states.get(neighbor_index);
227 if(neighbor_cube_state.alive) {
228 count++;
229 }
230 }
231
232 return count;
233 }
234 }
235
236 class L8onAutomata extends SCPattern {
237 // Controls if the points should be randomized even if something changes. Set above 0.5 to randomize cube aliveness.
238 private BasicParameter randomParameter = new BasicParameter("RAND", 0.0);
239 // Controls the rate of life algorithm ticks, in milliseconds
240 private BasicParameter rateParameter = new BasicParameter("DELAY", 75.0, 0.0, 1000.0);
241
242 private final SinLFO zPos = new SinLFO(0, model.zMax, 2500);
243
244 public final double MIN_ALIVE_PROBABILITY = 0.2;
245 public final double MAX_ALIVE_PROBABILITY = 0.9;
246
247 class PointState {
248 // Index of cube in glucose.model.cubes
249 public Integer index;
250 // Boolean which describes if cube is alive.
251 public boolean alive;
252
253 public PointState(Integer index, boolean alive) {
254 this.index = index;
255 this.alive = alive;
256 }
257 }
258
259 // Contains the state of all cubes by index.
260 private List<PointState> point_states;
261 // Contains the amount of time since the last cycle of life.
262 private int time_since_last_run;
263 // Boolean describing if life changes were made during the current run.
264 private boolean any_changes_this_run;
265 // Hold the new lives
266 private List<Boolean> new_states;
267
268 public L8onAutomata(GLucose glucose) {
269 super(glucose);
270
271 //Print debug info about the cubes.
272 //outputCubeInfo();
273
274 initPointStates();
275 randomizePointStates();
276 time_since_last_run = 0;
277 any_changes_this_run = false;
278 new_states = new ArrayList<Boolean>();
279
280 addParameter(randomParameter);
281 addParameter(rateParameter);
282 addModulator(zPos).trigger();
283 }
284
285 private void initPointStates() {
286 boolean alive = false;
287 PointState point_state;
288 this.point_states = new ArrayList<PointState>();
289 Integer i = 0;
290
291 for (LXPoint p : model.points) {
292 alive = true;
293 point_state = new PointState(i, alive);
294 this.point_states.add(point_state);
295 ++i;
296 }
297 }
298
299 public void run(double deltaMs) {
300 Integer i = 0;
301 PointState point_state;
302
303 any_changes_this_run = false;
304 new_states.clear();
305 time_since_last_run += deltaMs;
306
307 for (LXPoint p : model.points) {
308 point_state = this.point_states.get(i);
309
310 if(shouldLightPoint(point_state)) {
311 lightLivePoint(p);
312 } else {
313 lightDeadPoint(p);
314 }
315
316 i++;
317 }
318
319 boolean should_randomize_anyway = (randomParameter.getValuef() > 0.5);
320 if(should_randomize_anyway || !any_changes_this_run) {
321 randomizePointStates();
322 } else {
323 applyNewStates();
324 }
325
326 if(time_since_last_run >= rateParameter.getValuef()) {
327 time_since_last_run = 0;
328 }
329 }
330
331 public void lightLivePoint(LXPoint p) {
332 float hv = max(0, lx.getBaseHuef() - abs(p.z - zPos.getValuef()));
333 colors[p.index] = lx.hsb(
334 hv,
335 90,
336 80
337 );
338 }
339
340 public void lightDeadPoint(LXPoint p) {
341 colors[p.index] = lx.hsb(
342 lx.getBaseHuef(),
343 0,
344 0
345 );
346 }
347
348 public boolean shouldLightPoint(PointState point_state) {
349 // Respect rate parameter.
350 if(time_since_last_run < rateParameter.getValuef()) {
351 any_changes_this_run = true;
352 return point_state.alive;
353 } else {
354 boolean new_state = cycleOfAutomata(point_state);
355 new_states.add(new_state);
356 return new_state;
357 }
358 }
359
360 public boolean cycleOfAutomata(PointState point_state) {
361 Integer index = point_state.index;
362 Integer alive_neighbor_count = countLiveNeighbors(point_state);
363 boolean before_alive = point_state.alive;
364 boolean after_alive = before_alive;
365
366 if(point_state.alive) {
367 if(alive_neighbor_count == 1) {
368 after_alive = true;
369 } else {
370 after_alive = false;
371 }
372
373 } else {
374 if(alive_neighbor_count == 1) {
375 after_alive = true;
376 } else {
377 after_alive = false;
378 }
379 }
380
381 if(before_alive != after_alive) {
382 any_changes_this_run = true;
383 }
384
385 return after_alive;
386 }
387
388 public int countLiveNeighbors(PointState point_state) {
389 Integer index = point_state.index;
390 PointState before_neighbor;
391 PointState after_neighbor;
392
393 int count = 0;
394 if (index > 0) {
395 before_neighbor = point_states.get(index - 1);
396 if(before_neighbor.alive) {
397 count++;
398 }
399 }
400
401 if (index < (point_states.size() - 1)) {
402 after_neighbor = point_states.get(index + 1);
403 if(after_neighbor.alive) {
404 count++;
405 }
406 }
407
408 return count;
409 }
410
411 private void applyNewStates() {
412 int index = 0;
413 for(boolean new_state: new_states) {
414 PointState point_state = this.point_states.get(index);
415 point_state.alive = new_states.get(index);
416 index++;
417 }
418 }
419
420 private void randomizePointStates() {
421 double prob_range = (1.0 - MIN_ALIVE_PROBABILITY) - (1.0 - MAX_ALIVE_PROBABILITY);
422 double prob = MIN_ALIVE_PROBABILITY + (prob_range * Math.random());
423
424 print("Randomizing points! p = " + prob + "\n");
425
426 for (PointState point_state: this.point_states) {
427 point_state.alive = (Math.random() <= prob);
428 }
429 }
430 }
431
432 class L8onStrips extends SCPattern {
433 // Controls the rate of life algorithm ticks, in milliseconds
434 private BasicParameter rateParameter = new BasicParameter("DELAY", 112.5, 0.0, 1000.0);
435 // Controls if the cubes should be randomized even if something changes. Set above 0.5 to randomize cube aliveness.
436 private BasicParameter randomParameter = new BasicParameter("RAND", 0.0);
437 // Controls the brightness of dead cubes.
438 private BasicParameter deadParameter = new BasicParameter("DEAD", 25.0, 0.0, 100.0);
439 // Controls the saturation.
440 private BasicParameter saturationParameter = new BasicParameter("SAT", 90.0, 0.0, 100.0);
441
442 public final double MIN_ALIVE_PROBABILITY = 0.4;
443 public final double MAX_ALIVE_PROBABILITY = 0.9;
444
445 private final SinLFO xPos = new SinLFO(0, model.xMax, 4500);
446 private final SinLFO zPos = new SinLFO(0, model.zMax, 2500);
447
448 class StripState {
449 // Index of strip in glucose.model.strips
450 public Integer index;
451 // Boolean which describes if strip is alive.
452 public boolean alive;
453 // List of this cubes neighbors
454 public List<Integer> neighbors;
455
456 public StripState(Integer index, boolean alive, List<Integer> neighbors) {
457 this.index = index;
458 this.alive = alive;
459 this.neighbors = neighbors;
460 }
461 }
462
463 // Contains the state of all cubes by index.
464 private List<StripState> strip_states;
465 // Contains the amount of time since the last cycle of life.
466 private int time_since_last_run;
467 // Boolean describing if life changes were made during the current run.
468 private boolean any_changes_this_run;
469 // Hold the new lives
470 private List<Boolean> new_lives;
471
472 public L8onStrips(GLucose glucose) {
473 super(glucose);
474
475 //Print debug info about the strips.
476 //outputStripInfo();
477
478 initStripStates();
479 randomizeStripStates();
480 time_since_last_run = 0;
481 any_changes_this_run = false;
482 new_lives = new ArrayList<Boolean>();
483
484 addParameter(rateParameter);
485 addParameter(randomParameter);
486 addParameter(deadParameter);
487 addParameter(saturationParameter);
488
489 addModulator(xPos).trigger();
490 addModulator(zPos).trigger();
491 }
492
493 public void run(double deltaMs) {
494 Integer i = 0;
495 StripState strip_state;
496
497 any_changes_this_run = false;
498 new_lives.clear();
499 time_since_last_run += deltaMs;
500
501 for (Strip strip : model.strips) {
502 strip_state = this.strip_states.get(i);
503
504 if(shouldLightStrip(strip_state)) {
505 lightLiveStrip(strip);
506 } else {
507 lightDeadStrip(strip);
508 }
509
510 i++;
511 }
512
513 boolean should_randomize_anyway = (randomParameter.getValuef() > 0.5);
514 if(should_randomize_anyway || !any_changes_this_run) {
515 randomizeStripStates();
516 } else {
517 applyNewLives();
518 }
519
520 if(time_since_last_run >= rateParameter.getValuef()) {
521 time_since_last_run = 0;
522 }
523 }
524
525 public void lightLiveStrip(Strip strip) {
526 for (LXPoint p : strip.points) {
527 float hv = max(0, lx.getBaseHuef() - abs(p.z - zPos.getValuef()));
528 colors[p.index] = lx.hsb(
529 hv,
530 saturationParameter.getValuef(),
531 75
532 );
533 }
534 }
535
536 public void lightDeadStrip(Strip strip) {
537 for (LXPoint p : strip.points) {
538 float hv = max(0, lx.getBaseHuef() - abs(p.x - xPos.getValuef()));
539 double dead_bright = deadParameter.getValuef() * Math.random();
540
541 colors[p.index] = lx.hsb(
542 hv,
543 saturationParameter.getValuef(),
544 dead_bright
545 );
546 }
547 }
548
549 public void outputStripInfo() {
550 int i = 0;
551 for (Strip strip : model.strips) {
552 print("Strip " + i + ": " + strip.cx + "," + strip.cy + "," + strip.cz + "\n");
553 ++i;
554 }
555 }
556
557 private void initStripStates() {
558 List<Integer> neighbors;
559 boolean alive = false;
560 StripState strip_state;
561 this.strip_states = new ArrayList<StripState>();
562 Integer i = 0;
563
564 int total_neighbors = 0;
565
566 for (Strip strip : model.strips) {
567 neighbors = findStripNeighbors(strip, i);
568 alive = true;
569 strip_state = new StripState(i, alive, neighbors);
570 this.strip_states.add(strip_state);
571
572 total_neighbors += neighbors.size();
573 ++i;
574 }
575
576 float average_neighbor_count = (float) total_neighbors / (float) model.strips.size();
577 //print("Average neighbor count: " + average_neighbor_count + "\n");
578 }
579
580 private void randomizeStripStates() {
581 double prob_range = (1.0 - MIN_ALIVE_PROBABILITY) - (1.0 - MAX_ALIVE_PROBABILITY);
582 double prob = MIN_ALIVE_PROBABILITY + (prob_range * Math.random());
583
584 //print("Randomizing strips! p = " + prob + "\n");
585
586 for (StripState strip_state : this.strip_states) {
587 strip_state.alive = (Math.random() <= prob);
588 }
589 }
590
591 public List<Integer> findStripNeighbors(Strip strip, Integer index) {
592 List<Integer> neighbors = new LinkedList<Integer>();
593 Integer i = 0;
594 int neighbor_count = 0;
595 double distance = 0.0;
596
597 for (Strip s : model.strips) {
598 if( (int)index != (int)i ) {
599 distance = Math.sqrt( Math.pow((s.cx - strip.cx), 2) + Math.pow((s.cy - strip.cy), 2) + Math.pow((s.cz - strip.cz), 2) );
600
601 if(distance < ( (double) Cube.EDGE_WIDTH) ) {
602 //print("Strip " + i + " is a neighbor of " + index + "\n");
603 neighbors.add(i);
604 }
605 }
606 i++;
607 }
608
609 return neighbors;
610 }
611
612 public boolean shouldLightStrip(StripState strip_state) {
613 // Respect rate parameter.
614 if(time_since_last_run < rateParameter.getValuef()) {
615 any_changes_this_run = true;
616 return strip_state.alive;
617 } else {
618 boolean new_life = cycleOfStripperLife(strip_state);
619 new_lives.add(new_life);
620 return new_life;
621 }
622 }
623
624 public void applyNewLives() {
625 int index = 0;
626 for(boolean liveliness: new_lives) {
627 StripState strip_state = this.strip_states.get(index);
628 strip_state.alive = new_lives.get(index);
629 index++;
630 }
631 }
632
633 public boolean cycleOfStripperLife(StripState strip_state) {
634 Integer index = strip_state.index;
635 Integer alive_neighbor_count = countLiveNeighbors(strip_state);
636 boolean before_alive = strip_state.alive;
637 boolean after_alive = before_alive;
638
639 if(strip_state.alive) {
640 if(alive_neighbor_count < 2 || alive_neighbor_count > 6) {
641 after_alive = false;
642 } else {
643 after_alive = true;
644 }
645
646 } else {
647 if(alive_neighbor_count == 5) {
648 after_alive = true;
649 } else {
650 after_alive = false;
651 }
652 }
653
654 if(before_alive != after_alive) {
655 any_changes_this_run = true;
656 }
657
658 return after_alive;
659 }
660
661 public Integer countLiveNeighbors(StripState strip_state) {
662 Integer count = 0;
663 StripState neighbor_strip_state;
664
665 for(Integer neighbor_index: strip_state.neighbors) {
666 neighbor_strip_state = this.strip_states.get(neighbor_index);
667 if(neighbor_strip_state.alive) {
668 count++;
669 }
670 }
671
672 return count;
673 }
674 }