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