-
Notifications
You must be signed in to change notification settings - Fork 0
/
main_cgol.ino
180 lines (129 loc) · 5.13 KB
/
main_cgol.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include <Wire.h>
#include "ssd1306.h"
#include "intf/ssd1306_interface.h"
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// adapted from https://forum.arduino.cc/t/conways-game-of-life-with-128x64-graphic-lcd-update-also-with-128x64-spi-oled/210637/25
// for I2C
// Conway's Game Of Life 128x64
// PaulRB
// Jun 2014
union MatrixData {
unsigned long long l;
byte b[8];
};
MatrixData Matrix[129]; // Cell data in ram
void setup() {
Serial.begin(9600);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
delay(2000);
Matrix[64].l = B0000010; Matrix[64].l = Matrix[64].l << 32;
Matrix[65].l = B0000111; Matrix[65].l = Matrix[65].l << 32;
Matrix[66].l = B0000100; Matrix[66].l = Matrix[66].l << 32;
ssd1306_128x64_i2c_init();
ssd1306_clearScreen();
//randomiseMatrix();
outputMatrix();
}
void loop() {
unsigned long start = millis();
for (int i=0; i<1000; i++) {
generateMatrix();
outputMatrix();
}
Serial.print(F("Gens/s:"));
Serial.println(1000000/(millis() - start));
}
void outputMatrix() {
uint8_t s_ssd1306_invertByte = 0x00000000;
ssd1306_lcd.set_block(0, 0, 128);
for (uint16_t col = 0; col < 8; col++) {
for (uint16_t row = 0; row <= 127; row++) {
ssd1306_lcd.send_pixels1(s_ssd1306_invertByte ^ Matrix[row].b[col]);
//spi.write(Matrix[row].b[col]);
}
ssd1306_lcd.next_page();
}
ssd1306_intf.stop();
}
void randomiseMatrix() {
//Set up initial cells in matrix
randomSeed(analogRead(0));
for (byte row = 0; row <= 127; row++) {
for (byte col = 0; col <= 8; col++) {
Matrix[row].b[col] = random(0xff);
}
}
}
void injectGlider() {
byte col = random(127);
byte row = random(63);
Matrix[col++].l |= ((unsigned long long) B0000111) << row;
Matrix[col++].l |= ((unsigned long long) B0000001) << row;
Matrix[col++].l |= ((unsigned long long) B0000010) << row;
}
int generateMatrix() {
//Variables holding data on neighbouring cells
unsigned long long NeighbourN, NeighbourNW, NeighbourNE, CurrCells, NeighbourW, NeighbourE, NeighbourS, NeighbourSW, NeighbourSE;
//Variables used in calculating new cells
unsigned long long tot1, carry, tot2, tot4, NewCells;
int changes = 0; // counts the changes in the matrix
static int prevChanges[4]; // counts the changes in the matrix on prev 4 generations
static int staleCount = 0; // counts the consecutive occurrances of the same number of changes in the matrix
//set up N, NW, NE, W & E neighbour data
NeighbourN = Matrix[127].l;
CurrCells = Matrix[0].l;
Matrix[128].l = CurrCells; // copy row 0 to location after last row to remove need for wrap-around code in the loop
NeighbourNW = NeighbourN >> 1 | NeighbourN << 63;
NeighbourNE = NeighbourN << 1 | NeighbourN >> 63;
NeighbourW = CurrCells >> 1 | CurrCells << 63;
NeighbourE = CurrCells << 1 | CurrCells >> 63;
//Process each row of the matrix
for (byte row = 0; row <= 127; row++) {
//Pick up new S, SW & SE neighbours
NeighbourS = Matrix[row + 1].l;
NeighbourSW = NeighbourS >> 1 | NeighbourS << 63;
NeighbourSE = NeighbourS << 1 | NeighbourS >> 63;
//Count the live neighbours (in parallel) for the current row of cells
//However, if total goes over 3, we don't care (see below), so counting stops at 4
tot1 = NeighbourN;
tot2 = tot1 & NeighbourNW; tot1 = tot1 ^ NeighbourNW;
carry = tot1 & NeighbourNE; tot1 = tot1 ^ NeighbourNE; tot4 = tot2 & carry; tot2 = tot2 ^ carry;
carry = tot1 & NeighbourW; tot1 = tot1 ^ NeighbourW; tot4 = tot2 & carry | tot4; tot2 = tot2 ^ carry;
carry = tot1 & NeighbourE; tot1 = tot1 ^ NeighbourE; tot4 = tot2 & carry | tot4; tot2 = tot2 ^ carry;
carry = tot1 & NeighbourS; tot1 = tot1 ^ NeighbourS; tot4 = tot2 & carry | tot4; tot2 = tot2 ^ carry;
carry = tot1 & NeighbourSW; tot1 = tot1 ^ NeighbourSW; tot4 = tot2 & carry | tot4; tot2 = tot2 ^ carry;
carry = tot1 & NeighbourSE; tot1 = tot1 ^ NeighbourSE; tot4 = tot2 & carry | tot4; tot2 = tot2 ^ carry;
//Calculate the updated cells:
// <2 or >3 neighbours, cell dies
// =2 neighbours, cell continues to live
// =3 neighbours, new cell born
NewCells = (CurrCells | tot1) & tot2 & ~ tot4;
//Have any cells changed?
if (NewCells != CurrCells) {
//Count the change for "stale" test
changes++;
Matrix[row].l = NewCells;
}
//Current cells (before update), E , W, SE, SW and S neighbours become
//new N, NW, NE, E, W neighbours and current cells for next loop
NeighbourN = CurrCells;
NeighbourNW = NeighbourW;
NeighbourNE = NeighbourE;
NeighbourE = NeighbourSE;
NeighbourW = NeighbourSW;
CurrCells = NeighbourS;
}
if (changes != prevChanges[0] && changes != prevChanges[1] && changes != prevChanges[2] && changes != prevChanges[3]) {
staleCount = 0;
}
else {
staleCount++; //Detect "stale" matrix
}
if (staleCount > 64) injectGlider(); //Inject a glider
//SerialUSB.println(changes);
for (int i=3; i>0; i--) {
prevChanges[i] = prevChanges[i-1];
}
prevChanges[0] = changes;
}