another algorithm for conway
This commit is contained in:
parent
0bab9368ba
commit
df782208e2
|
@ -1,8 +1,8 @@
|
|||
project(conway)
|
||||
|
||||
add_executable(${PROJECT_NAME}.elf
|
||||
src/main.cpp
|
||||
src/ConwayScene.cpp src/ConwayScene.h src/bg.h src/ConwaySeeder.cpp src/ConwaySeeder.h)
|
||||
src/main.cpp src/ConwayScene.cpp src/ConwayScene.h
|
||||
src/NaiveConwayScene.cpp src/NaiveConwayScene.h src/bg.h src/ConwaySeeder.cpp src/ConwaySeeder.h src/ActiveTrackingConwayScene.cpp src/ActiveTrackingConwayScene.h)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}.elf gba-sprite-engine)
|
||||
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 30/11/18.
|
||||
//
|
||||
|
||||
#include <libgba-sprite-engine/background/text_stream.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_core.h>
|
||||
#include "ActiveTrackingConwayScene.h"
|
||||
|
||||
ActiveTrackingConwayScene::ActiveTrackingConwayScene(const std::shared_ptr<GBAEngine> &engine, u8 percentageSeed)
|
||||
: ConwayScene(engine, percentageSeed) {}
|
||||
|
||||
void ActiveTrackingConwayScene::tick(u16 keys) {
|
||||
generation++;
|
||||
int totalAmountAlive = 0;
|
||||
dma3_cpy(buffer, map, sizeof(buffer));
|
||||
|
||||
// when starting slow (100 active), this totals to 100 * 9 = +900 instructions VS +30k in the naive impl
|
||||
// when starting high, this will too slow down, worst case slightly slower than naive (SIZE * 9 instead of * 8)
|
||||
// 1. loop through all "active" cells.
|
||||
for(int i = 0; i < MAP_SIZE; i++) {
|
||||
auto cell = activeCellIndex[i];
|
||||
if(!cell.taken) {
|
||||
break;
|
||||
}
|
||||
int x = cell.x, y = cell.y;
|
||||
|
||||
// 2. process those _AND_ the neighbours (could be dead ones becoming alive)
|
||||
for(int x_i = x - 1; x_i <= x + 1; x_i++) {
|
||||
for(int y_j = y - 1; y_j <= y + 1; y_j++) {
|
||||
int toCheckPos = y_j * MAP_WIDTH + x_i;
|
||||
if(toCheckPos >= 0 && toCheckPos < MAP_SIZE - 1) {
|
||||
u16 state = getNextState(x_i, y_j);
|
||||
if(state == ALIVE) {
|
||||
// 3. Save the cell metadata if active for the next generation
|
||||
activeCellIndexBuffer[totalAmountAlive].taken = true;
|
||||
activeCellIndexBuffer[totalAmountAlive].x = x_i;
|
||||
activeCellIndexBuffer[totalAmountAlive].y = y_j;
|
||||
totalAmountAlive++;
|
||||
}
|
||||
buffer[toCheckPos] = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
activeCellIndexBuffer[totalAmountAlive].taken = false;
|
||||
|
||||
TextStream::instance().setText(std::string("amount alive: ") + std::to_string(totalAmountAlive) + std::string(" of ") + std::to_string(MAP_SIZE), 1, 1);
|
||||
TextStream::instance().setText(std::string("generation: ") + std::to_string(generation), 2, 1);
|
||||
dma3_cpy(activeCellIndex, activeCellIndexBuffer, sizeof(activeCellIndex));
|
||||
|
||||
dma3_cpy(map, buffer, sizeof(map));
|
||||
bg.get()->updateMap(map);
|
||||
}
|
||||
|
||||
|
||||
void ActiveTrackingConwayScene::postload() {
|
||||
int i = 0;
|
||||
for(int w = 0; w < MAP_WIDTH; w++) {
|
||||
for(int h = 0; h < MAP_HEIGHT; h++) {
|
||||
u8 index = h * MAP_WIDTH + w;
|
||||
if(map[index] == ALIVE) {
|
||||
activeCellIndex[i].taken = true;
|
||||
activeCellIndex[i].x = w;
|
||||
activeCellIndex[i].y = h;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 30/11/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_PROJECT_ACTIVETRACKINGCONWAYSCENE_H
|
||||
#define GBA_SPRITE_ENGINE_PROJECT_ACTIVETRACKINGCONWAYSCENE_H
|
||||
|
||||
|
||||
#include "ConwayScene.h"
|
||||
|
||||
struct cell {
|
||||
bool taken;
|
||||
int x, y;
|
||||
};
|
||||
|
||||
class ActiveTrackingConwayScene : public ConwayScene {
|
||||
private:
|
||||
cell activeCellIndex[MAP_SIZE] = {0}, activeCellIndexBuffer[MAP_SIZE] = {0};
|
||||
|
||||
public:
|
||||
ActiveTrackingConwayScene(const std::shared_ptr<GBAEngine> &engine, u8 percentageSeed);
|
||||
|
||||
void tick(u16 keys) override;
|
||||
|
||||
void postload() override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_PROJECT_ACTIVETRACKINGCONWAYSCENE_H
|
|
@ -2,19 +2,18 @@
|
|||
// Created by Wouter Groeneveld on 30/11/18.
|
||||
//
|
||||
|
||||
#include "ConwayScene.h"
|
||||
#include "bg.h"
|
||||
|
||||
#include <libgba-sprite-engine/gba_engine.h>
|
||||
#include <libgba-sprite-engine/sprites/sprite_builder.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_core.h>
|
||||
#include <libgba-sprite-engine/background/text_stream.h>
|
||||
#include "ConwayScene.h"
|
||||
#include "bg.h"
|
||||
|
||||
|
||||
// See http://www.coranac.com/tonc/text/gfx.htm#cd-qran
|
||||
int __qran_seed= 42; // Seed / rnd holder
|
||||
|
||||
ConwayScene::ConwayScene(const std::shared_ptr<GBAEngine> &engine, u8 percentageSeed) : Scene(engine), percentageSeed(percentageSeed) {
|
||||
}
|
||||
|
||||
std::vector<Sprite *> ConwayScene::sprites() {
|
||||
return {};
|
||||
}
|
||||
|
@ -23,25 +22,9 @@ std::vector<Background *> ConwayScene::backgrounds() {
|
|||
return { bg.get() };
|
||||
}
|
||||
|
||||
int ConwayScene::countAmountOfNeighbouringCellsAlive(int x, int y) {
|
||||
int amountOfNeightbouringCellsAlive = 0;
|
||||
int pos = y * MAP_WIDTH + x;
|
||||
|
||||
for(int x_i = x - 1; x_i <= x + 1; x_i++) {
|
||||
for(int y_j = y - 1; y_j <= y + 1; y_j++) {
|
||||
int toCheckPos = y_j * MAP_WIDTH + x_i;
|
||||
if(toCheckPos >= 0 && toCheckPos < MAP_SIZE - 1 && pos != toCheckPos && map[toCheckPos] == ALIVE) {
|
||||
amountOfNeightbouringCellsAlive++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return amountOfNeightbouringCellsAlive;
|
||||
}
|
||||
|
||||
u16 ConwayScene::getNextState(int x, int y) {
|
||||
int pos = y * MAP_WIDTH + x;
|
||||
int amountAlive = countAmountOfNeighbouringCellsAlive(x, y);
|
||||
int amountAlive = countAmountOfNeighbouringCellsAlive(pos, x, y);
|
||||
|
||||
int currentState = map[pos];
|
||||
|
||||
|
@ -58,6 +41,32 @@ u16 ConwayScene::getNextState(int x, int y) {
|
|||
}
|
||||
}
|
||||
|
||||
int ConwayScene::countAmountOfNeighbouringCellsAlive(int pos, int x, int y) {
|
||||
int amountOfNeightbouringCellsAlive = 0;
|
||||
|
||||
for(int x_i = x - 1; x_i <= x + 1; x_i++) {
|
||||
for(int y_j = y - 1; y_j <= y + 1; y_j++) {
|
||||
int toCheckPos = y_j * MAP_WIDTH + x_i;
|
||||
if(toCheckPos >= 0 && toCheckPos < MAP_SIZE - 1 && pos != toCheckPos && map[toCheckPos] == ALIVE) {
|
||||
amountOfNeightbouringCellsAlive++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return amountOfNeightbouringCellsAlive;
|
||||
}
|
||||
|
||||
void ConwayScene::load() {
|
||||
backgroundPalette = std::unique_ptr<BackgroundPaletteManager>(new BackgroundPaletteManager(conway_palette, sizeof(conway_palette)));
|
||||
|
||||
seedRandomMap(((MAP_WIDTH * MAP_HEIGHT) / 100) * percentageSeed);
|
||||
|
||||
bg = std::unique_ptr<Background>(new Background(1, conway_data, sizeof(conway_data), map, sizeof(map)));
|
||||
bg.get()->useMapScreenBlock(16);
|
||||
|
||||
postload();
|
||||
}
|
||||
|
||||
void ConwayScene::seedRandomMap(int seedcount) {
|
||||
for(int i = 0; i < MAP_SIZE; i++) {
|
||||
map[i] = DEAD;
|
||||
|
@ -70,30 +79,3 @@ void ConwayScene::seedRandomMap(int seedcount) {
|
|||
}
|
||||
}
|
||||
|
||||
void ConwayScene::load() {
|
||||
backgroundPalette = std::unique_ptr<BackgroundPaletteManager>(new BackgroundPaletteManager(conway_palette, sizeof(conway_palette)));
|
||||
|
||||
seedRandomMap(((MAP_WIDTH * MAP_HEIGHT) / 100) * percentageSeed);
|
||||
|
||||
bg = std::unique_ptr<Background>(new Background(1, conway_data, sizeof(conway_data), map, sizeof(map)));
|
||||
bg.get()->useMapScreenBlock(16);
|
||||
}
|
||||
|
||||
void ConwayScene::tick(u16 keys) {
|
||||
generation++;
|
||||
int totalAmountAlive = 0;
|
||||
dma3_cpy(buffer, map, sizeof(buffer));
|
||||
|
||||
for(int w = 0; w < MAP_WIDTH; w++) {
|
||||
for(int h = 0; h < MAP_HEIGHT; h++) {
|
||||
u16 state = getNextState(w, h);
|
||||
if(state == ALIVE) totalAmountAlive++;
|
||||
buffer[h * MAP_WIDTH + w] = state;
|
||||
}
|
||||
}
|
||||
|
||||
TextStream::instance().setText(std::string("amount alive: ") + std::to_string(totalAmountAlive) + std::string(" of ") + std::to_string(MAP_SIZE), 1, 1);
|
||||
TextStream::instance().setText(std::string("generation: ") + std::to_string(generation), 2, 1);
|
||||
dma3_cpy(map, buffer, sizeof(map));
|
||||
bg.get()->updateMap(buffer);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#ifndef GBA_SPRITE_ENGINE_PROJECT_CONWAYSCENE_H
|
||||
#define GBA_SPRITE_ENGINE_PROJECT_CONWAYSCENE_H
|
||||
|
||||
|
||||
#define MAP_WIDTH 64
|
||||
#define MAP_HEIGHT 64
|
||||
#define MAP_SIZE 64 * 64
|
||||
|
@ -14,19 +15,20 @@
|
|||
|
||||
#include <libgba-sprite-engine/scene.h>
|
||||
|
||||
|
||||
class ConwayScene : public Scene {
|
||||
private:
|
||||
protected:
|
||||
u8 percentageSeed;
|
||||
u16 generation;
|
||||
std::unique_ptr<Background> bg;
|
||||
u16 map[MAP_SIZE], buffer[MAP_SIZE];
|
||||
|
||||
int countAmountOfNeighbouringCellsAlive(int x, int y);
|
||||
void seedRandomMap(int seedcount);
|
||||
int countAmountOfNeighbouringCellsAlive(int pos, int x, int y);
|
||||
u16 getNextState(int x, int y);
|
||||
|
||||
public:
|
||||
ConwayScene(const std::shared_ptr<GBAEngine> &engine, u8 percentageSeed);
|
||||
ConwayScene(const std::shared_ptr<GBAEngine> &engine, u8 percentageSeed) : Scene(engine), percentageSeed(percentageSeed) {}
|
||||
|
||||
std::vector<Sprite *> sprites() override;
|
||||
|
||||
|
@ -34,7 +36,9 @@ public:
|
|||
|
||||
void load() override;
|
||||
|
||||
void tick(u16 keys) override;
|
||||
virtual void postload() = 0;
|
||||
|
||||
virtual void tick(u16 keys) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
#include <libgba-sprite-engine/gba_engine.h>
|
||||
#include "ConwaySeeder.h"
|
||||
#include "bg.h"
|
||||
#include "ConwayScene.h"
|
||||
#include "NaiveConwayScene.h"
|
||||
#include "ActiveTrackingConwayScene.h"
|
||||
|
||||
ConwaySeeder::ConwaySeeder(const std::shared_ptr<GBAEngine> &engine) : Scene(engine), percentage(30), delta(0) {}
|
||||
ConwaySeeder::ConwaySeeder(const std::shared_ptr<GBAEngine> &engine) : Scene(engine), percentage(30), delta(0), impl(1) {}
|
||||
|
||||
std::vector<Background *> ConwaySeeder::backgrounds() {
|
||||
return {};
|
||||
|
@ -33,15 +34,27 @@ void ConwaySeeder::load() {
|
|||
.buildPtr();
|
||||
|
||||
TextStream::instance().setText(std::string("Conways Game of Life"), 1, 1);
|
||||
TextStream::instance().setText(std::string("Up/Down to adjust"), 10, 1);
|
||||
TextStream::instance().setText(std::string("Start to render"), 11, 1);
|
||||
TextStream::instance().setText(std::string("Up/Down to adjust seed"), 10, 1);
|
||||
TextStream::instance().setText(std::string("A/B to adjust impl"), 11, 1);
|
||||
TextStream::instance().setText(std::string("Start to render"), 12, 1);
|
||||
}
|
||||
|
||||
void ConwaySeeder::tick(u16 keys) {
|
||||
TextStream::instance().setText(std::string("Seed percentage: ") + std::to_string(percentage), 5, 1);
|
||||
TextStream::instance().setText(std::string("Seed impl: ") + (impl == 1 ? std::string("naive") : std::string("fast")), 6, 1);
|
||||
|
||||
if(keys & KEY_A) {
|
||||
impl = 1;
|
||||
} else if(keys & KEY_B) {
|
||||
impl = 2;
|
||||
}
|
||||
|
||||
if(keys & KEY_START) {
|
||||
engine.get()->setScene(new ConwayScene(engine, percentage));
|
||||
if(impl == 1) {
|
||||
engine.get()->setScene(new NaiveConwayScene(engine, percentage));
|
||||
} else {
|
||||
engine.get()->setScene(new ActiveTrackingConwayScene(engine, percentage));
|
||||
}
|
||||
} else if(keys & KEY_UP && percentage < 90) {
|
||||
delta = 1;
|
||||
} else if(keys & KEY_DOWN && percentage > 10) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
class ConwaySeeder : public Scene {
|
||||
private:
|
||||
int delta;
|
||||
int impl;
|
||||
int percentage;
|
||||
std::unique_ptr<Sprite> conwaySprite;
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 30/11/18.
|
||||
//
|
||||
|
||||
#include <libgba-sprite-engine/gba_engine.h>
|
||||
#include <libgba-sprite-engine/sprites/sprite_builder.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_core.h>
|
||||
#include <libgba-sprite-engine/background/text_stream.h>
|
||||
|
||||
#include "NaiveConwayScene.h"
|
||||
#include "ConwayScene.h"
|
||||
|
||||
|
||||
void NaiveConwayScene::tick(u16 keys) {
|
||||
generation++;
|
||||
int totalAmountAlive = 0;
|
||||
dma3_cpy(buffer, map, sizeof(buffer));
|
||||
|
||||
// Naïve implementation:
|
||||
// 1. O(n^2) loop
|
||||
// 2. for each element, check x-1, x, x+y, y-1, y,y+1
|
||||
// totals to min. 4096 * 8 = +32.768 instructions, each update(), at only 16.8 MHz!
|
||||
for(int w = 0; w < MAP_WIDTH; w++) {
|
||||
for(int h = 0; h < MAP_HEIGHT; h++) {
|
||||
u16 state = getNextState(w, h);
|
||||
if(state == ALIVE) totalAmountAlive++;
|
||||
buffer[h * MAP_WIDTH + w] = state;
|
||||
}
|
||||
}
|
||||
|
||||
TextStream::instance().setText(std::string("amount alive: ") + std::to_string(totalAmountAlive) + std::string(" of ") + std::to_string(MAP_SIZE), 1, 1);
|
||||
TextStream::instance().setText(std::string("generation: ") + std::to_string(generation), 2, 1);
|
||||
|
||||
dma3_cpy(map, buffer, sizeof(map));
|
||||
bg.get()->updateMap(map);
|
||||
}
|
||||
|
||||
void NaiveConwayScene::postload() {
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 30/11/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_PROJECT_NAIVE_CONWAYSCENE_H
|
||||
#define GBA_SPRITE_ENGINE_PROJECT_NAIVE_CONWAYSCENE_H
|
||||
|
||||
|
||||
#include "ConwayScene.h"
|
||||
|
||||
class NaiveConwayScene : public ConwayScene {
|
||||
private:
|
||||
|
||||
int countAmountOfNeighbouringCellsAlive(int pos, int x, int y);
|
||||
|
||||
public:
|
||||
NaiveConwayScene(const std::shared_ptr<GBAEngine> &engine, u8 percentageSeed) : ConwayScene(engine, percentageSeed) {}
|
||||
|
||||
void tick(u16 keys) override;
|
||||
|
||||
void postload() override;
|
||||
};
|
||||
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_PROJECT_CONWAYSCENE_H
|
Loading…
Reference in New Issue