I found Conway's game of life. I had heard of it, of course, but didn't think it would be so easy and fun to implement. Anyway, here's my code which I know needs a lot of polish:
#include <iostream>
#include <vector>
#include <windows.h>
#define SIZE 10
using std::vector;
struct Pos {
int x;
int y;
Pos(int ix, int iy) : x(ix), y(iy) {}
};
void printGrid();
int getNeighborCount(Pos cellPos);
void next(int (&universe)[SIZE][SIZE]);
void killOrBirthCells(int (&universe)[SIZE][SIZE], vector<Pos> &toKill, vector<Pos> &toBirth);
void cellFate(int &cell, Pos cellPos, int neighborCount, vector<Pos> &toKill, vector<Pos> &toBirth);
void printUniverse(int (&universe)[SIZE][SIZE]);
int main() {
int universe[SIZE][SIZE] = {0};
// glider
universe[0][2] = 1;
universe[1][2] = 1;
universe[2][2] = 1;
universe[2][1] = 1;
universe[1][0] = 1;
while (1) {
system("cls");
next(universe);
printUniverse(universe);
Sleep(500);
}
return 0;
}
int getNeighborCount(int (&universe)[SIZE][SIZE], Pos cellPos) {
int count = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int x = cellPos.x - 1 + j;
int y = cellPos.y - 1 + i;
// handle cells on the edge
if (x >= 0 && y >= 0 && x < SIZE && y < SIZE
&& universe[cellPos.y - 1 + i][cellPos.x - 1 + j] == 1) {
count++;
}
}
}
// exclude itself
if (universe[cellPos.y][cellPos.x]) {
return count - 1;
}
return count;
}
void next(int (&universe)[SIZE][SIZE]) {
std::vector<Pos> toKill;
std::vector<Pos> toBirth;
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
Pos cellPos{j, i};
int neighborCount = getNeighborCount(universe, cellPos);
cellFate(universe[i][j], cellPos, neighborCount, toKill, toBirth);
}
}
killOrBirthCells(universe, toKill, toBirth);
}
// populate toKill and toBirth vectors
void cellFate(int &cell, Pos cellPos, int neighborCount, vector<Pos> &toKill, vector<Pos> &toBirth) {
if (cell == 1) {
// lonely
if (neighborCount == 0 || neighborCount == 1) {
toKill.push_back(cellPos);
// overcrowded
} else if (neighborCount >= 4 && neighborCount <= 8) {
toKill.push_back(cellPos);
}
} else {
if (neighborCount == 3) {
toBirth.push_back(cellPos);
}
}
}
void killOrBirthCells(int (&universe)[SIZE][SIZE], vector<Pos> &toKill, vector<Pos> &toBirth) {
for (Pos cellPos : toKill) {
universe[cellPos.y][cellPos.x] = 0;
}
for (Pos cellPos : toBirth) {
universe[cellPos.y][cellPos.x] = 1;
}
toKill.clear();
toBirth.clear();
}
void printUniverse(int (&universe)[SIZE][SIZE]) {
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
if (universe[i][j] == 1) {
std::cout << 'x';
} else {
std::cout << '.';
}
}
std::cout << '\n';
}
}