
// main.cpp
#include "ofMain.h"
#include "ofApp.h"
//The Rules
//For a space that is 'populated':
//Each cell with one or no neighbors dies, as if by solitude.
//Each cell with four or more neighbors dies, as if by overpopulation.
//Each cell with two or three neighbors survives.
//For a space that is 'empty' or 'unpopulated'
//Each cell with three neighbors becomes populated.
//========================================================================
int main( ){
// Set up the GL context
ofSetupOpenGL(1024, 768, OF_WINDOW); // <-------- setup the GL context
// this kicks off the running of my app
// can be OF_WINDOW or OF_FULLSCREEN
// pass in width and height too:
ofRunApp(new ofApp());
}
// ofApp.h
#pragma once
#include "ofMain.h"
#include "ofxGui.h"
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void mousePressed(int x, int y, int button);
// Grid properties
vector<vector<int>> grid;
int cols, rows;
int cellSize;
// Image for starting pattern
ofImage startImage;
// GUI elements
ofxPanel gui;
ofxIntSlider frameRateSlider;
ofxIntSlider cellSizeSlider;
// Helper functions
void initializeGrid();
void initializeGridFromImage();
int countNeighbors(int x, int y);
void updateGrid();
};
// ofApp.cpp
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup() {
// Print the rules
cout << "GAME OF LIFE" << endl;
cout << "THE RULES: " << endl;
cout << "FOR A SPACE THAT IS 'POPULATED':" << endl;
cout << "* EACH CELL WITH ONE OR NO NEIGHBORS DIES, AS IF BY SOLITUDE." << endl;
cout << "* EACH CELL WITH FOUR OR NO NEIGHBORS DIES, AS IF BY OVERPOPULATION." << endl;
cout << "* EACH CELL WITH TWO OR THREE NEIGHBORS SURVIVES." << endl;
cout << "FOR A SPACE THAT IS 'EMPTY' OR 'UNPOPULATED':" << endl;
cout << "* EACH CELL WITH THREE NEIGHBORS BECOMES POPULATED." << endl;
cout << endl;
cout << "INSTRUCTIONS: " << endl;
cout << "PRESS SPACE TO RESET" << endl;
cout << "CLICK A CELL TO TOGGLE STATE" << endl;
// Set the frame rate
ofSetFrameRate(5);
// Load the starting image
startImage.load("startPattern.jpg");
// Resize the image to fit the grid
int imageWidth = startImage.getWidth();
int imageHeight = startImage.getHeight();
// Set the window size based on the image dimensions
ofSetWindowShape(imageWidth, imageHeight);
// Initialize grid properties
cellSize = 2;
cols = ofGetWidth() / cellSize;
rows = ofGetHeight() / cellSize;
// Resize the image to fit the grid
startImage.resize(cols, rows);
initializeGridFromImage();
// Setup GUI
gui.setup();
gui.add(frameRateSlider.setup("Frame Rate", 10, 1, 60));
//gui.add(cellSizeSlider.setup("Cell Size", 5, 1, 20));
}
//--------------------------------------------------------------
void ofApp::update() {
ofSetFrameRate(frameRateSlider);
//// Check if cell size has changed
//if (cellSize != cellSizeSlider) {
// cellSize = cellSizeSlider;
// cols = ofGetWidth() / cellSize;
// rows = ofGetHeight() / cellSize;
// startImage.resize(cols, rows);
// initializeGridFromImage();
//}
updateGrid();
}
//--------------------------------------------------------------
void ofApp::draw() {
ofBackground(255);
for (int W = 0; W < cols; W++) {
for (int H = 0; H < rows; H++) {
if (grid[W][H] == 1) {
ofSetColor(255); // White for live cells
}
else {
ofSetColor(0); // Black for dead cells
}
ofDrawRectangle(W * cellSize, H * cellSize, cellSize, cellSize);
}
}
// Draw GUI
gui.draw();
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key) {
if (key == ' ') {
// Spacebar to reset the grid
initializeGridFromImage();
}
}
//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button) {
// Toggle cell state on mouse click
int W = x / cellSize;
int H = y / cellSize;
grid[W][H] = 1 - grid[W][H];
}
//--------------------------------------------------------------
void ofApp::initializeGrid() {
grid.resize(cols, vector<int>(rows, 0));
// Randomly initialize the grid
for (int W = 0; W < cols; W++) {
for (int H = 0; H < rows; H++) {
grid[W][H] = ofRandom(2); // 0 or 1
}
}
}
//--------------------------------------------------------------
void ofApp::initializeGridFromImage() {
grid.resize(cols, vector<int>(rows, 0));
ofPixels &pixels = startImage.getPixels();
for (int W = 0; W < cols; W++) {
for (int H = 0; H < rows; H++) {
ofColor color = pixels.getColor(W, H);
grid[W][H] = (color.getBrightness() > 50) ? 0 : 1; // Threshold to determine live or dead cell
}
}
}
//--------------------------------------------------------------
int ofApp::countNeighbors(int x, int y) {
int count = 0;
for (int W = -1; W <= 1; W++) {
for (int H = -1; H <= 1; H++) {
int col = (x + W + cols) % cols;
int row = (y + H + rows) % rows;
count += grid[col][row];
}
}
count -= grid[x][y]; // Subtract the cell itself
return count;
}
//--------------------------------------------------------------
void ofApp::updateGrid() {
vector<vector<int>> next(cols, vector<int>(rows, 0));
for (int W = 0; W < cols; W++) {
for (int H = 0; H < rows; H++) {
int neighbors = countNeighbors(W, H);
int state = grid[W][H];
if (state == 0 && neighbors == 3) {
next[W][H] = 1; // Reproduction
}
else if (state == 1 && (neighbors < 2 || neighbors > 3)) {
next[W][H] = 0; // Death
}
else {
next[W][H] = state; // Stasis
}
}
}
grid = next; // Update the grid
}