John Conway's Game of Life - Playdate C API


Controls

Up/DownIncrease/Decrease cell size
AReset
BPause
CrankIncrease/Decrease probability of a cell being alive on init

Source Code - C

#include <stdbool.h>
#include "pd_api.h"

static int CELL_SIZE = 8;
static int CELL_COLS; // set at runtime
static int CELL_ROWS;

static PlaydateAPI* pd = NULL;

static bool** fg = NULL;
static bool** bg = NULL;

static bool isPaused = false;
static int newCellProbability = 50;

static bool isAlive(int x, int y) {
    return fg[(x + CELL_COLS) % CELL_COLS][(y + CELL_ROWS) % CELL_ROWS];
}

// any live cell with fewer than 2 live neighbors dies, as if caused by underpopulation.
// any live cell with more than 3 live neighbors dies, as if by overcrowding.
// any live cell with two or 3 live neighbors lives on to the next generation.
// any dead cell with exactly 3 live neighbors becomes a live cell.
static bool nextState(int x, int y) {
    int neighbors = 0;
    for (int dx = -1; dx <= 1; dx++) {
        for (int dy = -1; dy <= 1; dy++) {
            if (dx == 0 && dy == 0) continue;
            if (isAlive(x + dx, y + dy)) neighbors++;
        }
    }

    if (isAlive(x, y)) {
        return neighbors == 2 || neighbors == 3;
    } else {
        return neighbors == 3;
    }
    return false;
}

static void step(void) {
    for (int y = 0; y < CELL_ROWS; y++) {
        for (int x = 0; x < CELL_COLS; x++) {
            bg[x][y] = nextState(x, y);
        }
    }

    bool** temp = fg;
    fg = bg;
    bg = temp;
}

static void randomizeGrid(void) {
    for (int y = 0; y < CELL_ROWS; y++) {
        for (int x = 0; x < CELL_COLS; x++) {
            fg[x][y] = (rand() % 100 < newCellProbability);
        }
    }
}

static void initGrid(void) {
    CELL_COLS = LCD_COLUMNS / CELL_SIZE;
    CELL_ROWS = LCD_ROWS / CELL_SIZE;
    fg = (bool**)malloc(sizeof(bool*) * CELL_COLS);
    bg = (bool**)malloc(sizeof(bool*) * CELL_COLS);
    for (int i = 0; i < CELL_COLS; i++) {
        fg[i] = (bool*)malloc(sizeof(bool) * CELL_ROWS);
        bg[i] = (bool*)malloc(sizeof(bool) * CELL_ROWS);
    }
    randomizeGrid();
}

static void freeGrid(void) {
    for (int i = 0; i < CELL_COLS; i++) {
        free(bg[i]);
        free(fg[i]);
    }
    free(bg);
    free(fg);
    bg = NULL;
    fg = NULL;
}

static void resizeCell(int newCellSize) {
    freeGrid();
    CELL_SIZE = newCellSize;
    initGrid();
}

static void drawGrid(void) {
    pd->graphics->clear(kColorWhite);
    for (int y = 0; y < CELL_ROWS; y++) {
        for (int x = 0; x < CELL_COLS; x++) {
            if (fg[x][y]) {
                int px = x * CELL_SIZE;
                int py = y * CELL_SIZE;
                pd->graphics->fillRect(px, py, CELL_SIZE, CELL_SIZE, kColorBlack);
            }
        }
    }
}

static int update(void* ud) {
    PDButtons current, pushed, released;
    pd->system->getButtonState(&current, &pushed, &released);

    if (pushed & kButtonA) {
        randomizeGrid();
    }
    if (pushed & kButtonB) {
        isPaused = !isPaused;
    }

    if (pushed & kButtonUp) {
        resizeCell(CELL_SIZE + 1);
    } else if (pushed & kButtonDown && CELL_SIZE > 1) {
        resizeCell(CELL_SIZE - 1);
    }

    float crankChange = pd->system->getCrankChange();
    if (crankChange > 0) { // clockwise
        newCellProbability += 1;
        if (newCellProbability > 100) newCellProbability = 100;
        randomizeGrid();
    } else if (crankChange < 0) { // counter-clockwise
        newCellProbability -= 1;
        if (newCellProbability < 1) newCellProbability = 1;
        randomizeGrid();
    }

    if (!isPaused) {
        step();
    }
    drawGrid();
//    pd->system->drawFPS(0, 0);

    return 1;
}

int eventHandler(PlaydateAPI* playdate, PDSystemEvent event, uint32_t arg) {
    if (event == kEventInit) {
        pd = playdate;
        initGrid();
        pd->display->setRefreshRate(8);
        pd->system->setUpdateCallback(update, NULL);
    }
    return 0;
}

Build & Run

make clean && make && make run
~/Developer/PlaydateSDK/bin/Playdate\ Simulator.app/Contents/MacOS/Playdate\ Simulator build/GameOfLife.pdx

Download

GameOfLife.pdx.zip

Source Code

The source code can be found on GitHub.



Projects

Site

Tags