2 // Index of cube in glucose.model.cubes
4 // Boolean which describes if cube is alive.
6 // List of this cubes neighbors
7 public List<Integer> neighbors;
9 public CubeState(Integer index, boolean alive, List<Integer> neighbors) {
12 this.neighbors = neighbors;
16 class L8onLife extends SCPattern {
17 // Controls the rate of life algorithm ticks, in milliseconds
18 private BasicParameter rateParameter = new BasicParameter("RATE", 122.5, 0.0, 2000.0);
19 // Controls if the cubes should be randomized even if something changes. Set above 0.5 to randomize cube aliveness.
20 private BasicParameter randomParameter = new BasicParameter("RAND", 0.0);
21 // Controls the brightness of dead cubes.
22 private BasicParameter deadParameter = new BasicParameter("DEAD", 25.0, 0.0, 100.0);
23 // Controls the saturation.
24 private BasicParameter saturationParameter = new BasicParameter("SAT", 90.0, 0.0, 100.0);
26 public final double MIN_ALIVE_PROBABILITY = 0.1;
27 public final double MAX_ALIVE_PROBABILITY = 0.8;
29 private final SinLFO xPos = new SinLFO(0, model.xMax, 3500);
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;
38 public L8onLife(GLucose glucose) {
41 //Print debug info about the cubes.
45 time_since_last_run = 0;
46 any_changes_this_run = false;
48 addParameter(rateParameter);
49 addParameter(randomParameter);
50 addParameter(deadParameter);
51 addParameter(saturationParameter);
52 addModulator(xPos).trigger();
55 public void run(double deltaMs) {
59 any_changes_this_run = false;
60 time_since_last_run += deltaMs;
62 for (Cube cube : model.cubes) {
63 cube_state = this.cube_states.get(i);
65 if(shouldLightCube(cube_state)) {
74 boolean should_randomize_anyway = (randomParameter.getValuef() > 0.5);
75 if(should_randomize_anyway || !any_changes_this_run) {
76 randomizeCubeStates();
79 if(time_since_last_run >= rateParameter.getValuef()) {
80 time_since_last_run = 0;
84 public void lightLiveCube(Cube cube) {
85 for (LXPoint p : cube.points) {
86 float hv = max(0, lx.getBaseHuef() - abs(p.x - xPos.getValuef()));
87 colors[p.index] = lx.hsb(
89 saturationParameter.getValuef(),
95 public void lightDeadCube(Cube cube) {
96 for (LXPoint p : cube.points) {
97 float hv = max(0, lx.getBaseHuef() - abs(p.x - xPos.getValuef()));
98 double dead_bright = deadParameter.getValuef() * Math.random();
100 colors[p.index] = lx.hsb(
102 saturationParameter.getValuef(),
108 public void outputCubeInfo() {
110 for (Cube c : model.cubes) {
111 print("Cube " + i + ": " + c.x + "," + c.y + "," + c.z + "\n");
114 print("Edgeheight: " + Cube.EDGE_HEIGHT + "\n");
115 print("Edgewidth: " + Cube.EDGE_WIDTH + "\n");
116 print("Channelwidth: " + Cube.CHANNEL_WIDTH + "\n");
119 private void initCubeStates() {
120 List<Integer> neighbors;
121 boolean alive = false;
122 CubeState cube_state;
123 this.cube_states = new LinkedList<CubeState>();
126 for (Cube c : model.cubes) {
127 neighbors = findCubeNeighbors(c, i);
129 cube_state = new CubeState(i, alive, neighbors);
130 this.cube_states.add(cube_state);
135 private void randomizeCubeStates() {
136 double prob_range = (1.0 - MIN_ALIVE_PROBABILITY) - (1.0 - MAX_ALIVE_PROBABILITY);
137 double prob = MIN_ALIVE_PROBABILITY + (prob_range * Math.random());
139 //print("Randomizing cubes! p = " + prob + "\n");
141 for (CubeState cube_state: this.cube_states) {
142 cube_state.alive = (Math.random() <= prob);
146 public List<Integer> findCubeNeighbors(Cube cube, Integer index) {
147 List<Integer> neighbors = new LinkedList<Integer>();
150 for (Cube c : model.cubes) {
152 if(abs(c.x - cube.x) < (Cube.EDGE_WIDTH * 2) && abs(c.y - cube.y) < (Cube.EDGE_HEIGHT * 2)) {
153 //print("Cube " + i + " is a neighbor of " + index + "\n");
164 public boolean shouldLightCube(CubeState cube_state) {
165 // Respect rate parameter.
166 if(time_since_last_run < rateParameter.getValuef()) {
167 any_changes_this_run = true;
168 return cube_state.alive;
170 return cycleOfLife(cube_state);
174 public boolean cycleOfLife(CubeState cube_state) {
175 Integer index = cube_state.index;
176 Integer alive_neighbor_count = countLiveNeighbors(cube_state);
177 boolean before_alive = cube_state.alive;
179 if(cube_state.alive) {
180 if(alive_neighbor_count < 2 || alive_neighbor_count > 3) {
181 cube_state.alive = false;
183 cube_state.alive = true;
187 if(alive_neighbor_count == 3) {
188 cube_state.alive = true;
190 cube_state.alive = false;
194 this.cube_states.set(index, cube_state);
196 if(before_alive != cube_state.alive) {
197 any_changes_this_run = true;
200 return cube_state.alive;
203 public Integer countLiveNeighbors(CubeState cube_state) {
205 CubeState neighbor_cube_state;
207 for(Integer neighbor_index: cube_state.neighbors) {
208 neighbor_cube_state = this.cube_states.get(neighbor_index);
209 if(neighbor_cube_state.alive) {