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);
25 // Controls the number of neighbors needed to birth a new life.
26 private BasicParameter fertilityParameter = new BasicParameter("FERT", 2.0, 1.0, 5.0);
29 public final double MIN_ALIVE_PROBABILITY = 0.2;
30 public final double MAX_ALIVE_PROBABILITY = 0.9;
32 private final SinLFO xPos = new SinLFO(0, model.xMax, 4500);
34 // Contains the state of all cubes by index.
35 private List<CubeState> cube_states;
36 // Contains the amount of time since the last cycle of life.
37 private int time_since_last_run;
38 // Boolean describing if life changes were made during the current run.
39 private boolean any_changes_this_run;
41 private List<Boolean> new_lives;
43 public L8onLife(GLucose glucose) {
46 //Print debug info about the cubes.
50 time_since_last_run = 0;
51 any_changes_this_run = false;
52 new_lives = new ArrayList<Boolean>();
54 addParameter(rateParameter);
55 addParameter(randomParameter);
56 addParameter(deadParameter);
57 addParameter(saturationParameter);
58 addParameter(fertilityParameter);
59 addModulator(xPos).trigger();
62 public void run(double deltaMs) {
66 any_changes_this_run = false;
68 time_since_last_run += deltaMs;
70 for (Cube cube : model.cubes) {
71 cube_state = this.cube_states.get(i);
73 if(shouldLightCube(cube_state)) {
82 boolean should_randomize_anyway = (randomParameter.getValuef() > 0.5);
83 if(should_randomize_anyway || !any_changes_this_run) {
84 randomizeCubeStates();
89 if(time_since_last_run >= rateParameter.getValuef()) {
90 time_since_last_run = 0;
94 public void lightLiveCube(Cube cube) {
95 for (LXPoint p : cube.points) {
96 float hv = max(0, lx.getBaseHuef() - abs(p.x - xPos.getValuef()));
97 colors[p.index] = lx.hsb(
99 saturationParameter.getValuef(),
105 public void lightDeadCube(Cube cube) {
106 for (LXPoint p : cube.points) {
107 float hv = max(0, lx.getBaseHuef() - abs(p.x - xPos.getValuef()));
108 double dead_bright = deadParameter.getValuef() * Math.random();
110 colors[p.index] = lx.hsb(
112 saturationParameter.getValuef(),
118 public void outputCubeInfo() {
120 for (Cube c : model.cubes) {
121 print("Cube " + i + ": " + c.x + "," + c.y + "," + c.z + "\n");
124 print("Edgeheight: " + Cube.EDGE_HEIGHT + "\n");
125 print("Edgewidth: " + Cube.EDGE_WIDTH + "\n");
126 print("Channelwidth: " + Cube.CHANNEL_WIDTH + "\n");
129 private void initCubeStates() {
130 List<Integer> neighbors;
131 boolean alive = false;
132 CubeState cube_state;
133 this.cube_states = new LinkedList<CubeState>();
136 for (Cube c : model.cubes) {
137 neighbors = findCubeNeighbors(c, i);
139 cube_state = new CubeState(i, alive, neighbors);
140 this.cube_states.add(cube_state);
145 private void randomizeCubeStates() {
146 double prob_range = (1.0 - MIN_ALIVE_PROBABILITY) - (1.0 - MAX_ALIVE_PROBABILITY);
147 double prob = MIN_ALIVE_PROBABILITY + (prob_range * Math.random());
149 //print("Randomizing cubes! p = " + prob + "\n");
151 for (CubeState cube_state: this.cube_states) {
152 cube_state.alive = (Math.random() <= prob);
156 public List<Integer> findCubeNeighbors(Cube cube, Integer index) {
157 List<Integer> neighbors = new LinkedList<Integer>();
160 for (Cube c : model.cubes) {
162 if(abs(c.x - cube.x) < (Cube.EDGE_WIDTH * 2) && abs(c.y - cube.y) < (Cube.EDGE_HEIGHT * 2)) {
163 //print("Cube " + i + " is a neighbor of " + index + "\n");
174 public boolean shouldLightCube(CubeState cube_state) {
175 // Respect rate parameter.
176 if(time_since_last_run < rateParameter.getValuef()) {
177 any_changes_this_run = true;
178 return cube_state.alive;
180 boolean new_life = cycleOfLife(cube_state);
181 new_lives.add(new_life);
186 public void applyNewLives() {
188 for(boolean liveliness: new_lives) {
189 CubeState cube_state = this.cube_states.get(index);
190 cube_state.alive = new_lives.get(index);
195 public boolean cycleOfLife(CubeState cube_state) {
196 Integer index = cube_state.index;
197 Integer alive_neighbor_count = countLiveNeighbors(cube_state);
198 boolean before_alive = cube_state.alive;
199 boolean after_alive = before_alive;
200 int fetility_count = (int) fertilityParameter.getValuef();
202 if(cube_state.alive) {
203 if(alive_neighbor_count < 2 || alive_neighbor_count > 3) {
210 if(alive_neighbor_count == fetility_count) {
217 if(before_alive != after_alive) {
218 any_changes_this_run = true;
224 public Integer countLiveNeighbors(CubeState cube_state) {
226 CubeState neighbor_cube_state;
228 for(Integer neighbor_index: cube_state.neighbors) {
229 neighbor_cube_state = this.cube_states.get(neighbor_index);
230 if(neighbor_cube_state.alive) {