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.2;
27 public final double MAX_ALIVE_PROBABILITY = 0.9;
29 private final SinLFO xPos = new SinLFO(0, model.xMax, 4500);
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 private List<Boolean> new_lives;
40 public L8onLife(GLucose glucose) {
43 //Print debug info about the cubes.
47 time_since_last_run = 0;
48 any_changes_this_run = false;
49 new_lives = new ArrayList<Boolean>();
51 addParameter(rateParameter);
52 addParameter(randomParameter);
53 addParameter(deadParameter);
54 addParameter(saturationParameter);
55 addModulator(xPos).trigger();
58 public void run(double deltaMs) {
62 any_changes_this_run = false;
64 time_since_last_run += deltaMs;
66 for (Cube cube : model.cubes) {
67 cube_state = this.cube_states.get(i);
69 if(shouldLightCube(cube_state)) {
78 boolean should_randomize_anyway = (randomParameter.getValuef() > 0.5);
79 if(should_randomize_anyway || !any_changes_this_run) {
80 randomizeCubeStates();
85 if(time_since_last_run >= rateParameter.getValuef()) {
86 time_since_last_run = 0;
90 public void lightLiveCube(Cube cube) {
91 for (LXPoint p : cube.points) {
92 float hv = max(0, lx.getBaseHuef() - abs(p.x - xPos.getValuef()));
93 colors[p.index] = lx.hsb(
95 saturationParameter.getValuef(),
101 public void lightDeadCube(Cube cube) {
102 for (LXPoint p : cube.points) {
103 float hv = max(0, lx.getBaseHuef() - abs(p.x - xPos.getValuef()));
104 double dead_bright = deadParameter.getValuef() * Math.random();
106 colors[p.index] = lx.hsb(
108 saturationParameter.getValuef(),
114 public void outputCubeInfo() {
116 for (Cube c : model.cubes) {
117 print("Cube " + i + ": " + c.x + "," + c.y + "," + c.z + "\n");
120 print("Edgeheight: " + Cube.EDGE_HEIGHT + "\n");
121 print("Edgewidth: " + Cube.EDGE_WIDTH + "\n");
122 print("Channelwidth: " + Cube.CHANNEL_WIDTH + "\n");
125 private void initCubeStates() {
126 List<Integer> neighbors;
127 boolean alive = false;
128 CubeState cube_state;
129 this.cube_states = new LinkedList<CubeState>();
132 for (Cube c : model.cubes) {
133 neighbors = findCubeNeighbors(c, i);
135 cube_state = new CubeState(i, alive, neighbors);
136 this.cube_states.add(cube_state);
141 private void randomizeCubeStates() {
142 double prob_range = (1.0 - MIN_ALIVE_PROBABILITY) - (1.0 - MAX_ALIVE_PROBABILITY);
143 double prob = MIN_ALIVE_PROBABILITY + (prob_range * Math.random());
145 //print("Randomizing cubes! p = " + prob + "\n");
147 for (CubeState cube_state: this.cube_states) {
148 cube_state.alive = (Math.random() <= prob);
152 public List<Integer> findCubeNeighbors(Cube cube, Integer index) {
153 List<Integer> neighbors = new LinkedList<Integer>();
156 for (Cube c : model.cubes) {
158 if(abs(c.x - cube.x) < (Cube.EDGE_WIDTH * 2) && abs(c.y - cube.y) < (Cube.EDGE_HEIGHT * 2)) {
159 //print("Cube " + i + " is a neighbor of " + index + "\n");
170 public boolean shouldLightCube(CubeState cube_state) {
171 // Respect rate parameter.
172 if(time_since_last_run < rateParameter.getValuef()) {
173 any_changes_this_run = true;
174 return cube_state.alive;
176 boolean new_life = cycleOfLife(cube_state);
177 new_lives.add(new_life);
182 public void applyNewLives() {
184 for(boolean liveliness: new_lives) {
185 CubeState cube_state = this.cube_states.get(index);
186 cube_state.alive = new_lives.get(index);
191 public boolean cycleOfLife(CubeState cube_state) {
192 Integer index = cube_state.index;
193 Integer alive_neighbor_count = countLiveNeighbors(cube_state);
194 boolean before_alive = cube_state.alive;
195 boolean after_alive = before_alive;
197 if(cube_state.alive) {
198 if(alive_neighbor_count < 2 || alive_neighbor_count > 3) {
205 if(alive_neighbor_count == 3) {
212 if(before_alive != after_alive) {
213 any_changes_this_run = true;
219 public Integer countLiveNeighbors(CubeState cube_state) {
221 CubeState neighbor_cube_state;
223 for(Integer neighbor_index: cube_state.neighbors) {
224 neighbor_cube_state = this.cube_states.get(neighbor_index);
225 if(neighbor_cube_state.alive) {