Optimized frame repainting. Fixed mouse click processing.
[sixth-3d-demos.git] / src / main / java / eu / svjatoslav / sixth / e3d / examples / life / Matrix.java
1 package eu.svjatoslav.sixth.e3d.examples.life;
2
3 import eu.svjatoslav.sixth.e3d.geometry.Point3D;
4 import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.AbstractCompositeShape;
5 import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.SubShape;
6
7 /**
8  * This is our 2D game of life world. It contains 2D array of {@link Cell}'s.
9  */
10 class Matrix extends AbstractCompositeShape {
11
12     /**
13      * Empty space between cells.
14      */
15     private static final int BORDER = 5;
16
17     /**
18      * Matrix size X and Y. (Amount of cells.)
19      */
20     private static final int SIZE = 30;
21
22     /**
23      * Object marker in 3D scene. Allows to locate all stars from the scene.
24      */
25     private static final String GROUP_STARS = "stars";
26
27     /**
28      * Object marker in 3D scene. Allows to locate surface on the scene.
29      */
30     private static final String GROUP_SURFACE = "surface";
31
32     /**
33      * 2 dimensional matrix of cells
34      */
35     private final Cell[][] cells = new Cell[SIZE][];
36
37     public Matrix(final Point3D location) {
38         super(location);
39
40
41         for (int x = 0; x < SIZE; x++) {
42             cells[x] = new Cell[SIZE];
43
44             // init Y row
45             for (int z = 0; z < SIZE; z++) {
46                 // create cell and register it
47                 final Cell cell = new Cell(getCellLocation(x, z));
48                 cells[x][z] = cell;
49                 addShape(cell);
50             }
51         }
52
53         setGroupForUngrouped(GROUP_SURFACE);
54     }
55
56     /**
57      * Clear matrix.
58      */
59     public void clear() {
60
61         // mark every cell as inactive
62         for (int x = 0; x < SIZE; x++)
63             for (int y = 0; y < SIZE; y++)
64                 cells[x][y].setActive(false);
65
66         // remove history stars
67         removeGroup(GROUP_STARS);
68     }
69
70     /**
71      * Compute survived cells based on the rules of Conway's Game of Life.
72      */
73     private void computeSurvivedCells() {
74
75         for (int y = 0; y < SIZE; y++)
76             for (int x = 0; x < SIZE; x++)
77                 processCell(x, y);
78
79         for (int y = 0; y < SIZE; y++)
80             for (int x = 0; x < SIZE; x++)
81                 cells[x][y].setActive(cells[x][y].survives);
82
83     }
84
85     private void processCell(int x, int y) {
86         int aliveNeighbours = countNeighbours(x, y);
87
88         if (cells[x][y].isActive()) {
89             cells[x][y].survives = ((aliveNeighbours == 2) || (aliveNeighbours == 3));
90         } else {
91             cells[x][y].survives = aliveNeighbours == 3;
92         }
93     }
94
95     private int countNeighbours(int x, int y) {
96         int result = 0;
97         for (int ny = y - 1; ny <= y + 1; ny++)
98             for (int nx = x - 1; nx <= x + 1; nx++)
99                 if (isCellAlive(nx, ny)) result++;
100
101         if (isCellAlive(x, y)) result--;
102
103         return result;
104     }
105
106     private boolean isCellAlive(int x, int y) {
107         if (x < 0) return false;
108         if (x >= SIZE) return false;
109         if (y < 0) return false;
110         if (y >= SIZE) return false;
111         return cells[x][y].isActive();
112     }
113
114     /**
115      * Evolve matrix for one iteration
116      */
117     public void evolve(final boolean preserveHistory) {
118         if (preserveHistory)
119             markActiveCells();
120
121         shiftStarsUp();
122
123         computeSurvivedCells();
124     }
125
126     private Point3D getCellLocation(final int x, final int z) {
127         final int shift = -((SIZE / 2) * (Cell.SIZE + BORDER));
128
129         return new Point3D(
130                 (x * (Cell.SIZE + BORDER)) + shift,
131                 0,
132                 (z * (Cell.SIZE + BORDER)) + shift);
133     }
134
135     /**
136      * Leave trail of active cells as stars above matrix.
137      */
138     private void markActiveCells() {
139         // mark survived cells
140         for (int x = 0; x < SIZE; x++)
141             for (int y = 0; y < SIZE; y++)
142                 if (cells[x][y].isActive())
143                     addShape(new Star(getCellLocation(x, y)));
144
145         setGroupForUngrouped(GROUP_STARS);
146     }
147
148     /**
149      * Find all history tracking stars and shift them up.
150      */
151     private void shiftStarsUp() {
152
153         for (final SubShape subShape : getGroup(GROUP_STARS))
154             ((Star) subShape.getShape()).getLocation().translateY(-10);
155     }
156 }