Conways Game of Life (+ TFT)

Клубника
Ср 20 мая 2015 г., 18:23
Что такое Game of Life?
Ну, вчера работал над этой маленькой игрой.
Его в основном Conways Game of Life на сетке 50x33, в которой банкомат. Должен быть предопределен в эскизе.
Вывод виден на экране ILI9341, но пусть я тоже попробую с OLED.
Это не большой проект, но все же немного смешно :) Собираюсь добавить немного возможности ввода или прикосновения в эти выходные.
Скачать (puush)
Предварительно загружен с помощью планера gospers ^^

Multi для мультипликатора, который масштабирует сетку. Maxy и Maxx обозначают размеры сетки (что также может быть изменено)

Я пытался с 80x80, но это все еще "медленно". 100x100 не сработал, 4000 баллов слишком большие для оперативной памяти (была ошибкой). Одним из способов будет спасение сетки на внешний EEPROM.

~ Солома

Paulrb
Ср 24 июня 2015 г., 22:32
Привет, солома. Игра в жизнь - одна из моих навязчивости. Здесь Является ли моя попытка использовать OLED, отображающий голлер Gosper's Glider на сетке 128x64, работающего на Maple Mini Clone. Это довольно яростно! Около 580 поколений в секунду.

Память не является проблемой, если вы храните свою сетку ячеек, упакованных в биты: Sketch uses 14,788 bytes (13%) of program storage space. Maximum is 110,592 bytes. Global variables use 4,256 bytes of dynamic memory.

Paulrb
Sun 28 июня 2015 г., 17:29
Хорошо, я получил сетку 256x256. Окно 128x64, предоставленное OLED -экраном, можно прокрутить, используя мини -джойстик.

Видео
// Conway's Game Of Life 256x256 // PaulRB // Jun 2015 #include //Pins controlling SSD1306 Graphic OLED #define OLED_DC 1 #define OLED_CS 0 #define OLED_RESET 2 #define OLED_COLS 128 #define OLED_ROWS 8 #define MATRIX_COLS 256 #define MATRIX_ROWS 32 union MatrixData { unsigned long long l[MATRIX_ROWS/8]; byte b[MATRIX_ROWS]; }; #define SW_U 17 #define SW_D 20 #define SW_L 18 #define SW_R 16 #define SW_C 19 int scrollHorz = 0; int scrollVert = 0; MatrixData Matrix[MATRIX_COLS+1]; // Cell data in ram void setup() { pinMode(OLED_DC, OUTPUT); pinMode(OLED_CS, OUTPUT); pinMode(OLED_RESET, OUTPUT); SPI.begin(); SPI.setBitOrder(MSBFIRST); // Set the SPI bit order SPI.setDataMode(SPI_MODE0); //Set the SPI data mode 0 SPI.setClockDivider(SPI_CLOCK_DIV2); // 2.25 MHz digitalWrite(OLED_RESET, HIGH); delay(1); digitalWrite(OLED_RESET, LOW); delay(10); digitalWrite(OLED_RESET, HIGH); digitalWrite(OLED_DC, LOW); digitalWrite(OLED_CS, LOW); SPI.transfer(0xAE); // Display off SPI.transfer(0xD5); // Set display clock divider SPI.transfer(0x80); SPI.transfer(0xA8); // Set multiplex SPI.transfer(0x3F); SPI.transfer(0xD3); // Set display offset SPI.transfer(0x00); SPI.transfer(0x40); // Set start line to zero SPI.transfer(0x8D); // Set charge pump SPI.transfer(0x14); SPI.transfer(0x20); // Set memory mode SPI.transfer(0x00); SPI.transfer(0xA0 | 0x1); // Set segment remapping SPI.transfer(0xC8); // Set command Scan decode SPI.transfer(0xDA); // Set Comm pins SPI.transfer(0x12); SPI.transfer(0x81); // Set contrast SPI.transfer(0xCF); SPI.transfer(0xd9); // Set precharge SPI.transfer(0xF1); SPI.transfer(0xDB); // Set Vcom detect SPI.transfer(0x40); SPI.transfer(0xA4); // Allow display resume SPI.transfer(0xA6); // Set normal display SPI.transfer(0xAF); // Display On digitalWrite(OLED_CS, HIGH); //R-pentomino //Matrix[64].l[4] = 0b0000010; //Matrix[65].l[4] = 0b0000111; //Matrix[66].l[4] = 0b0000100; //Gosper's Glider Gun //Matrix[64].l[4] = 0b00000000000000000000000000010000000000000000000000; //Matrix[65].l[4] = 0b00000000000000000000000001010000000000000000000000; //Matrix[66].l[4] = 0b00000000000000011000000110000000000001100000000000; //Matrix[67].l[4] = 0b00000000000000100010000110000000000001100000000000; //Matrix[68].l[4] = 0b00011000000001000001000110000000000000000000000000; //Matrix[69].l[4] = 0b00011000000001000101100001010000000000000000000000; //Matrix[70].l[4] = 0b00000000000001000001000000010000000000000000000000; //Matrix[71].l[4] = 0b00000000000000100010000000000000000000000000000000; //Matrix[72].l[4] = 0b00000000000000011000000000000000000000000000000000; randomiseMatrix(); outputMatrix(); Serial.begin(115200); pinMode(SW_U, INPUT_PULLUP); pinMode(SW_D, INPUT_PULLUP); pinMode(SW_L, INPUT_PULLUP); pinMode(SW_R, INPUT_PULLUP); pinMode(SW_C, INPUT_PULLUP); } void loop() { unsigned long start = millis(); for (int i=0; i<1000; i++) { generateMatrix(); outputMatrix(); } //Serial.print("Gens/s:"); Serial.println(1000000UL/(millis() - start)); } void outputMatrix() { digitalWrite(OLED_DC, LOW); //Command mode digitalWrite(OLED_CS, LOW); //Enable display on SPI bus SPI.transfer(0x21); // Set column address SPI.transfer(0); SPI.transfer(OLED_COLS-1); SPI.transfer(0x22); // Set page address SPI.transfer(0); SPI.transfer(OLED_ROWS-1); digitalWrite(OLED_CS, HIGH); //Disable display on SPI bus digitalWrite(OLED_DC, HIGH); // Data mode digitalWrite(OLED_CS, LOW); //Enable display on SPI bus if (digitalRead(SW_L) == LOW && scrollHorz < (MATRIX_COLS - OLED_COLS)) scrollHorz++; if (digitalRead(SW_R) == LOW && scrollHorz > 0) scrollHorz--; if (digitalRead(SW_U) == LOW && scrollVert < ((MATRIX_ROWS - OLED_ROWS)<<3)) scrollVert++; if (digitalRead(SW_D) == LOW && scrollVert > 0) scrollVert--; //Send matrix data for display on OLED for (int col = 0; col < OLED_ROWS; col++) { int colScrolled = col + (scrollVert>>3); for (int row = 0; row < OLED_COLS; row++) { SPI.transfer(Matrix[row+scrollHorz].b[colScrolled]); } } digitalWrite(OLED_CS, HIGH); } void randomiseMatrix() { //Set up initial cells in matrix randomSeed(analogRead(0)); for (int row = 0; row < MATRIX_COLS; row++) { for (int col = 0; col < MATRIX_ROWS; col++) { Matrix[row].b[col] = random(0xff); } } } void injectGlider() { int col = random(MATRIX_COLS); int row = random(MATRIX_ROWS); Matrix[col++].b[row] |= 0b0000111; Matrix[col++].b[row] |= 0b0000001; Matrix[col++].b[row] |= 0b0000010; } void rotateLeft(unsigned long long x[]) { unsigned long long c = 0; for (int i=0; i<4; i++) { unsigned long long c2 = x[i] >> 63; x[i] = x[i] << 1 | c; c = c2; } x[0] |= c; } void rotateRight(unsigned long long x[]) { unsigned long long c = 0; for (int i=3; i>=0; i--) { unsigned long long c2 = x[i] << 63; x[i] = x[i] >> 1 | c; c = c2; } x[3] |= c; } int generateMatrix() { //Variables holding data on neighbouring cells MatrixData 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[MATRIX_COLS-1]; CurrCells = Matrix[0]; Matrix[MATRIX_COLS] = CurrCells; // copy row 0 to location after last row to remove need for wrap-around code in the loop NeighbourNW = NeighbourN; rotateLeft(NeighbourNW.l); NeighbourNE = NeighbourN; rotateRight(NeighbourNE.l); NeighbourW = CurrCells; rotateLeft(NeighbourW.l); NeighbourE = CurrCells; rotateRight(NeighbourE.l); //Process each row of the matrix for (int row = 0; row < MATRIX_COLS; row++) { //Pick up new S, SW & SE neighbours NeighbourS = Matrix[row + 1]; NeighbourSW = NeighbourS; rotateLeft(NeighbourSW.l); NeighbourSE = NeighbourS; rotateRight(NeighbourSE.l); for (int i=0; i3 neighbours, cell dies // =2 neighbours, cell continues to live // =3 neighbours, new cell born NewCells = (CurrCells.l[i] | tot1) & tot2 & ~ tot4; //Have any cells changed? if (NewCells != CurrCells.l[i]) { //Count the change for "stale" test changes++; Matrix[row].l[i] = 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 //Serial.println(changes); for (int i=3; i>0; i--) { prevChanges[i] = prevChanges[i-1]; } prevChanges[0] = changes; }

Paulrb
Сб, 04 июля 2015 г., 18:33
И теперь мини -джойстик удаляется, и вид автоматически панонент вокруг сетки, чтобы показать часть, где происходит что -то интересное.

Видео

Код: // Conway's Game Of Life 256x256 // PaulRB // Jun 2015 #include //Pins controlling SSD1306 Graphic OLED #define OLED_DC 1 #define OLED_CS 0 #define OLED_RESET 2 #define OLED_COLS 128 #define OLED_ROWS 8 #define MATRIX_COLS 256 #define MATRIX_ROWS 32 union MatrixData { unsigned long long l[MATRIX_ROWS/8]; byte b[MATRIX_ROWS]; }; MatrixData Matrix[MATRIX_COLS+1]; // Cell data in ram int leftChanges, rightChanges, topChanges, bottomChanges; void setup() { byte startupCodes[] = { 0xAE, // Display off 0xD5, // Set display clock divider 0x80, 0xA8, // Set multiplex 0x3F, 0xD3, // Set display offset 0x00, 0x40, // Set start line to zero 0x8D, // Set charge pump 0x14, 0x20, // Set memory mode 0x00, 0xA1, // Set segment remapping 0xC8, // Set command Scan decode 0xDA, // Set Comm pins 0x12, 0x81, // Set contrast 0xCF, 0xd9, // Set precharge 0xF1, 0xDB, // Set Vcom detect 0x40, 0xA4, // Allow display resume 0xA6, // Set normal display 0xAF // Display On }; pinMode(OLED_DC, OUTPUT); pinMode(OLED_CS, OUTPUT); pinMode(OLED_RESET, OUTPUT); SPI.begin(); SPI.setBitOrder(MSBFIRST); // Set the SPI bit order SPI.setDataMode(SPI_MODE0); //Set the SPI data mode 0 SPI.setClockDivider(SPI_CLOCK_DIV2); // 2.25 MHz digitalWrite(OLED_RESET, HIGH); delay(1); digitalWrite(OLED_RESET, LOW); delay(10); digitalWrite(OLED_RESET, HIGH); digitalWrite(OLED_DC, LOW); digitalWrite(OLED_CS, LOW); for (int i = 0; i < sizeof(startupCodes); i++) SPI.transfer(startupCodes[i]); digitalWrite(OLED_CS, HIGH); //R-pentomino //Matrix[64].l[4] = 0b0000010; //Matrix[65].l[4] = 0b0000111; //Matrix[66].l[4] = 0b0000100; //injectGlider(); //Gosper's Glider Gun //Matrix[64].l[4] = 0b00000000000000000000000000010000000000000000000000; //Matrix[65].l[4] = 0b00000000000000000000000001010000000000000000000000; //Matrix[66].l[4] = 0b00000000000000011000000110000000000001100000000000; //Matrix[67].l[4] = 0b00000000000000100010000110000000000001100000000000; //Matrix[68].l[4] = 0b00011000000001000001000110000000000000000000000000; //Matrix[69].l[4] = 0b00011000000001000101100001010000000000000000000000; //Matrix[70].l[4] = 0b00000000000001000001000000010000000000000000000000; //Matrix[71].l[4] = 0b00000000000000100010000000000000000000000000000000; //Matrix[72].l[4] = 0b00000000000000011000000000000000000000000000000000; randomiseMatrix(); outputMatrix(); //Serial.begin(115200); //pinMode(SW_U, INPUT_PULLUP); //pinMode(SW_D, INPUT_PULLUP); //pinMode(SW_L, INPUT_PULLUP); //pinMode(SW_R, INPUT_PULLUP); //pinMode(SW_C, INPUT_PULLUP); } void loop() { unsigned long start = millis(); for (int i=0; i<1000; i++) { generateMatrix(); if (leftChanges - rightChanges > 16) scrollRight(); if (rightChanges - leftChanges > 16) scrollLeft(); if (bottomChanges - topChanges > 16) scrollDown(); if (topChanges - bottomChanges > 16) scrollUp(); outputMatrix(); } //Serial.print("Gens/s:"); Serial.println(1000000UL/(millis() - start)); } void outputMatrix() { digitalWrite(OLED_DC, LOW); //Command mode digitalWrite(OLED_CS, LOW); //Enable display on SPI bus SPI.transfer(0x21); // Set column address SPI.transfer(0); SPI.transfer(OLED_COLS-1); SPI.transfer(0x22); // Set page address SPI.transfer(0); SPI.transfer(OLED_ROWS-1); digitalWrite(OLED_CS, HIGH); //Disable display on SPI bus digitalWrite(OLED_DC, HIGH); // Data mode digitalWrite(OLED_CS, LOW); //Enable display on SPI bus //Send matrix data for display on OLED for (int col = MATRIX_ROWS/2 - OLED_ROWS/2; col < MATRIX_ROWS/2 + OLED_ROWS/2; col++) { for (int row = MATRIX_COLS/2 - OLED_COLS/2; row < MATRIX_COLS/2 + OLED_COLS/2; row++) { SPI.transfer(Matrix[row].b[col]); } } digitalWrite(OLED_CS, HIGH); } void randomiseMatrix() { //Set up initial cells in matrix randomSeed(analogRead(0)); for (int row = 0; row < MATRIX_COLS; row++) { for (int col = 0; col < MATRIX_ROWS; col++) { Matrix[row].b[col] = random(0xff); } } } void injectGlider() { int col = random(MATRIX_COLS); int row = random(MATRIX_ROWS); Matrix[col++].b[row] |= 0b0000111; Matrix[col++].b[row] |= 0b0000001; Matrix[col++].b[row] |= 0b0000010; } void rotateLeft(unsigned long long x[]) { unsigned long long carryIn = 0, carryOut; for (int i=0; i<4; i++) { carryOut = x[i] >> 63; x[i] = x[i] << 1 | carryIn; carryIn = carryOut; } x[0] |= carryOut; } void rotateRight(unsigned long long x[]) { unsigned long long carryIn = 0, carryOut; for (int i=3; i>=0; i--) { carryOut = x[i] << 63; x[i] = x[i] >> 1 | carryIn; carryIn = carryOut; } x[3] |= carryOut; } void scrollLeft() { Matrix[MATRIX_COLS] = Matrix[0]; for (int row = 0; row < MATRIX_COLS+1; row++) Matrix[row] = Matrix[row+1]; } void scrollRight() { for (int row = MATRIX_COLS; row > 0; row--) Matrix[row] = Matrix[row-1]; Matrix[0] = Matrix[MATRIX_COLS]; } void scrollUp() { for (int row = 0; row < MATRIX_COLS; row++) rotateLeft(Matrix[row].l); } void scrollDown() { for (int row = 0; row < MATRIX_COLS; row++) rotateRight(Matrix[row].l); } int generateMatrix() { //Variables holding data on neighbouring cells MatrixData 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 leftChanges = rightChanges = topChanges = bottomChanges = 0; //set up N, NW, NE, W & E neighbour data NeighbourN = Matrix[MATRIX_COLS-1]; CurrCells = Matrix[0]; Matrix[MATRIX_COLS] = CurrCells; // copy row 0 to location after last row to remove need for wrap-around code in the loop NeighbourNW = NeighbourN; rotateLeft(NeighbourNW.l); NeighbourNE = NeighbourN; rotateRight(NeighbourNE.l); NeighbourW = CurrCells; rotateLeft(NeighbourW.l); NeighbourE = CurrCells; rotateRight(NeighbourE.l); //Process each row of the matrix for (int row = 0; row < MATRIX_COLS; row++) { //Pick up new S, SW & SE neighbours NeighbourS = Matrix[row + 1]; NeighbourSW = NeighbourS; rotateLeft(NeighbourSW.l); NeighbourSE = NeighbourS; rotateRight(NeighbourSE.l); for (int i=0; i3 neighbours, cell dies // =2 neighbours, cell continues to live // =3 neighbours, new cell born NewCells = (CurrCells.l[i] | tot1) & tot2 & ~ tot4; //Have any cells changed? if (NewCells != CurrCells.l[i]) { //Count the change for "stale" test changes++; if (row >= MATRIX_COLS/2) rightChanges++; else leftChanges++; if (i >= MATRIX_ROWS/16) bottomChanges++; else topChanges++; Matrix[row].l[i] = 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 for (int i=3; i>0; i--) { prevChanges[i] = prevChanges[i-1]; } prevChanges[0] = changes; }

Rogerclark
Сб, 04 июля 2015 г., 21:42
Пол

Выглядит очень круто.

Вы поняли свою ошибку с аварией?


Кроме того, в ваших комментариях YourTube,
Можете ли вы ссылаться на мои видео на YouTube о том, как вы устанавливаете, а также на репо и этот форум?

Вы можете попробовать один из этих цветных дисплеев на основе SPI, например, ILI9341 (хотя это может быть немного медленнее, если вы не можете использовать DMA для выполнения передач)

Paulrb
Солнце 5 июля 2015 г., 16:25
Привет, Роджер, ссылки добавлены на видео на YouTube.

Не знаю, есть ли у меня проблема с пульсированием/аварией, оставив эскиз за несколько часов и посмотрит, что произойдет. Может быть, даже небольшие изменения могут вызвать/избежать проблемы.

Спасибо, что все это произошло на Arduino Ide, кстати, кстати!

Rogerclark
Солнце 5 июля 2015 г. 9:06 вечера
Привет, Пол

Если у вас все еще есть проблема с синим пульсированием, дайте мне знать, и я посмотрю, смогу ли я воспроизвести его, а затем попробуйте бежать с адаптером Stlink и GDB, бегающим, чтобы увидеть, сможет ли он пролить свет на то, почему его сбой

Mrburnette
Солнце 5 июля 2015 г., 22:28
Paulrb написал:И теперь мини -джойстик удаляется, и вид автоматически панонент вокруг сетки, чтобы показать часть, где происходит что -то интересное.

Видео

Paulrb
Пн, 6 июля 2015 г. 5:57 утра
Спасибо, Рэй. Ты помнишь мои ранние попытки на Пикакс? Около 10 кадров в секунду на сетке 16 x16...

Роджер, вчера непрерывно запускал код более 3 часов без сбоя/синего пульсации. Понятия не имею, что я сделал, чтобы исправить это, к сожалению. Если он запустится снова, попытаюсь изолировать то, что я изменил, что вызывает это, хотя, если это происходит только через несколько часов, я, вероятно, пропустит это.

Rogerclark
Пн, 6 июля 2015 г., 6:23
Пол

Интересно, может ли свободное соединение с дисплеем (не совсем уверен, как)

В любом случае. Там нет способа отладить его, если мы не сможем воспроизвести ошибку

Где я слышал это раньше..... ;-)

Mrburnette
Пн, 6 июля 2015 12:12
Paulrb написал:Спасибо, Рэй. Ты помнишь мои ранние попытки на Пикакс? Около 10 кадров в секунду на сетке 16 x16...

WWVB Timecode от синей таблетки