1 package org.woehlke.computer.kurzweil.tabs.cca;
2
3 import lombok.Getter;
4 import lombok.extern.log4j.Log4j2;
5 import org.woehlke.computer.kurzweil.commons.model.LatticeNeighbourhoodType;
6 import org.woehlke.computer.kurzweil.commons.model.LatticePointNeighbourhoodPosition;
7 import org.woehlke.computer.kurzweil.commons.tabs.TabModel;
8 import org.woehlke.computer.kurzweil.tabs.cca.canvas.CyclicCellularAutomatonColorScheme;
9
10 import java.util.Random;
11 import java.util.concurrent.ForkJoinTask;
12
13 import static org.woehlke.computer.kurzweil.commons.model.LatticeNeighbourhoodType.*;
14
15 @Log4j2
16 @Getter
17 public class CyclicCellularAutomatonModel extends ForkJoinTask<Void> implements TabModel {
18
19 private final CyclicCellularAutomatonContext tabCtx;
20
21 private volatile int[][][] lattice;
22 private volatile int source;
23 private volatile int target;
24 private volatile LatticeNeighbourhoodType neighbourhoodType;
25 private Boolean running;
26
27 private final CyclicCellularAutomatonColorScheme colorScheme;
28 private final int versions;
29 private final static int startX = 0;
30 private final static int startY = 0;
31 private final int worldX;
32 private final int worldY;
33
34 public CyclicCellularAutomatonModel(CyclicCellularAutomatonContext tabCtx) {
35 this.tabCtx = tabCtx;
36 this.worldX = this.tabCtx.getCtx().getWorldDimensions().getX();
37 this.worldY = this.tabCtx.getCtx().getWorldDimensions().getY();
38 this.colorScheme = new CyclicCellularAutomatonColorScheme();
39 this.versions = 2;
40 this.startWithNeighbourhoodVonNeumann();
41 this.resetLattice();
42 this.running = Boolean.FALSE;
43 }
44
45 @Override
46 protected boolean exec() {
47 boolean doIt = false;
48 synchronized (running) {
49 doIt = running.booleanValue();
50 }
51 if(doIt){
52
53 int maxState = colorScheme.getMaxState();
54 int xx;
55 int yy;
56 int nextState;
57 int y;
58 int x;
59 int i;
60 for (y = 0; y < worldY; y++) {
61 for (x = 0; x < worldX; x++) {
62 lattice[target][x][y] = lattice[source][x][y];
63 nextState = (lattice[source][x][y] + 1) % maxState;
64 LatticePointNeighbourhoodPosition[] pos = LatticePointNeighbourhoodPosition.getNeighbourhoodFor(neighbourhoodType);
65 for (i = 0; i < pos.length; i++) {
66 xx = ((x + pos[i].getX() + worldX) % worldX);
67 yy = ((y + pos[i].getY() + worldY) % worldY);
68 if (nextState == lattice[source][xx][yy]) {
69 lattice[target][x][y] = nextState;
70 i = pos.length;
71 }
72 }
73 }
74 }
75 this.source = (this.source + 1) % 2;
76 this.target = (this.target + 1) % 2;
77
78 }
79 return true;
80 }
81
82
83 private void initCreateLattice(){
84 log.info("initCreateLattice start: "+neighbourhoodType.name());
85 lattice = new int[versions][worldX][worldY];
86 source = 0;
87 target = 1;
88 log.info("initCreateLattice finished: "+neighbourhoodType.name());
89 }
90
91 private void initFillLattice(){
92 log.info("initCreateLattice start: "+neighbourhoodType.name());
93 Random random = this.tabCtx.getCtx().getRandom();
94 int maxState = this.colorScheme.getMaxState();
95 int y;
96 int x;
97 for (y = 0; y < worldY; y++) {
98 for (x = 0; x < worldX; x++) {
99 lattice[source][x][y] = random.nextInt(maxState);
100 }
101 }
102 log.info("initCreateLattice finished: "+neighbourhoodType.name());
103 }
104
105 public void resetLattice(){
106 initCreateLattice();
107 initFillLattice();
108 }
109
110 public void startWithNeighbourhoodVonNeumann() {
111 if( this.neighbourhoodType == null) {
112 log.info("startWithNeighbourhoodVonNeumann");
113 } else {
114 log.info("startWithNeighbourhoodVonNeumann: " + neighbourhoodType.name());
115 }
116 this.neighbourhoodType=VON_NEUMANN_NEIGHBORHOOD;
117 resetLattice();
118 log.info("startWithNeighbourhoodVonNeumann started: "+neighbourhoodType.name());
119 }
120
121 public void startWithNeighbourhoodMoore() {
122 log.info("startWithNeighbourhoodVonNeumann: "+neighbourhoodType.name());
123 this.neighbourhoodType=MOORE_NEIGHBORHOOD;
124 resetLattice();
125 log.info("startWithNeighbourhoodVonNeumann started: "+neighbourhoodType.name());
126 }
127
128 public void startWithNeighbourhoodWoehlke() {
129
130 this.neighbourhoodType=WOEHLKE_NEIGHBORHOOD;
131 resetLattice();
132 log.info("startWithNeighbourhoodVonNeumann started: "+neighbourhoodType.name());
133 }
134
135
136 @Override
137 public Void getRawResult() {
138 return null;
139 }
140
141 @Override
142 protected void setRawResult(Void value) {}
143
144
145 public void start() {
146 log.info("start");
147 synchronized (running) {
148 running = Boolean.TRUE;
149 }
150 log.info("started "+this.toString());
151 }
152
153 public void stop() {
154 log.info("stop");
155 synchronized (running) {
156 running = Boolean.FALSE;
157 }
158 log.info("stopped "+this.toString());
159 }
160
161 public int getState(int x, int y) {
162 return lattice[source][x][y];
163 }
164 }