Conway's Game of Life
Design a simple command line based version of Conway's Game of Life. See rules here: https://www.wikiwand.com/en/Conway%27s_Game_of_Life
#include <iostream>
#include <vector>
#include <math.h>
#include <chrono>
#include <thread>
#include <conio.h>
using namespace std;
class State {
public:
State(int y, int x, bool state) {
x_pos = x;
y_pos = y;
alive = state;
}
int x_pos;
int y_pos;
bool alive;
private:
};
inline void print2d(vector<vector<char>> &nums)
{
for (int i = 0; i < nums.size(); i++) {
for (int j = 0; j < nums.at(i).size(); j++) {
cout << nums.at(i).at(j) << ' ';
}
cout << endl;
}
}
vector<vector<char>> createField(int length, int height) {
vector<vector<char>> field;
vector<char> temp;
for (int i = 0; i < length; i++) {
for (int j = 0; j < height; j++) {
temp.push_back(' ');
}
field.push_back(temp);
temp.clear();
}
return field;
}
inline int countNumberOfLiveCells(vector<vector<char>> ¤tState, int y, int x) {
// 8 possible neighbors
int count = 0;
if (currentState.at(y + 1).at(x) == 'O') count++;
if (currentState.at(y + 1).at(x + 1) == 'O') count++;
if (currentState.at(y).at(x + 1) == 'O') count++;
if (currentState.at(y - 1).at(x + 1) == 'O') count++;
if (currentState.at(y - 1).at(x) == 'O') count++;
if (currentState.at(y - 1).at(x - 1) == 'O') count++;
if (currentState.at(y).at(x - 1) == 'O') count++;
if (currentState.at(y + 1).at(x - 1) == 'O') count++;
return count;
}
void getNextState(vector<vector<char>> *currentState) {
vector<State> updateCells;
for (int i = 1; i < (*currentState).size() - 1; i++) {
for (int j = 1; j < (*currentState).at(i).size() - 1; j++) {
int liveCells = countNumberOfLiveCells((*currentState), i, j);
// Analyze 4 cases per cell - deaths and births occur simultaneously
// 1) Any live cell with fewer than two live neighbours dies, as if caused by under-population.
// 3) Any live cell with more than three live neighbours dies, as if by over-population.
// 2) Any live cell with two or three live neighbours lives on to the next generation. (inverse of statement 1)
if ((*currentState).at(i).at(j) == 'O') {
if (liveCells < 2 || liveCells > 3) {
updateCells.emplace_back(i, j, false);
}
//(*currentState).at(i).at(j) = ' ';
}
// 4) Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
else {
if (liveCells == 3)
updateCells.emplace_back(i, j, true);
//(*currentState).at(i).at(j) = 'O';
}
}
}
// update new generation
for (int i = 0; i < updateCells.size(); i++) {
int y_pos = (updateCells.at(i)).y_pos;
int x_pos = (updateCells.at(i)).x_pos;
if (updateCells.at(i).alive == true) {
(*currentState).at(y_pos).at(x_pos) = 'O';
}
else (*currentState).at(y_pos).at(x_pos) = ' ';
}
}
inline void runGame(vector<vector<char>> &field, int sleep) {
while (true) {
// 1) Display / print the updated field
print2d(field);
// 2) Wait a set amount of time
std::this_thread::sleep_for(std::chrono::milliseconds(sleep));
// 3) Get the updated field by modifying the current field in mem
getNextState(&field);
// 4) Clear the window
system("cls");
}
}
void loopInitializer(vector<vector<char>> &enviroment, vector < pair<int, int>> thingToCreate, pair<int, int> &origin) {
for (int i = 0; i < thingToCreate.size(); i++) {
enviroment.at(origin.first + thingToCreate.at(i).first).at(origin.second + thingToCreate.at(i).second) = 'O';
}
}
void initialize(int length, int height, int choice, int sleep) {
vector<vector<char>> enviroment = createField(length, height);
pair<int, int> origin(length / 2, height / 2);
switch (choice) {
/*
think cartisian cord system, with the y (origin.first) sign flipped
y,x not x,y
*/
case 1:
{
vector < pair<int, int>> glider =
{ { 0,0 },{ 1,1 },{ 1,2 },{ 0,2 },{ -1,2 } };
loopInitializer(enviroment, glider, origin);
break;
}
case 2:
{
vector < pair<int, int>> blinker =
{ { -1,0 },{ 0,0 },{ 1,0 } };
loopInitializer(enviroment, blinker, origin);
break;
}
case 3:
{
vector < pair<int, int>> toad =
{ { 0,1 },{ -1,1 },{ -1,0 },{ 0,0 },{ 0,2 },{ -1,-1 } };
loopInitializer(enviroment, toad, origin);
break;
}
case 4:
{
vector < pair<int, int>> beacon =
{ {0,0},{ 0,1 },{ 1,0 },{ 2,3 },{ 3,3 },{ 3,2 } };
loopInitializer(enviroment, beacon, origin);
break;
}
case 5:
{
vector < pair<int, int>> pulsar =
{ {-1,2},{ -1,3 },{ -1,4 },{ -2,1 },{ -3,1 },{ -4,1 },
{ -6,2 },{ -6,3 },{ -6,4 },{ -2,6 },{ -3,6 },{ -4,6 },
{ -1, -2 },{ -1,-3 },{ -1,-4 },{ -2,-1 },{ -3,-1 },{ -4,-1 },
{ -6,-2 },{ -6,-3 },{ -6,-4 },{ -2,-6 },{ -3,-6 },{ -4,-6 },
{ 1,-2 },{ 1,-3 },{ 1,-4 },{ 2,-1 },{ 3,-1 },{ 4,-1 },
{ 6,-2 },{ 6,-3 },{ 6,-4 },{ 2,-6 },{ 3,-6 },{ 4,-6 },
{ 1,2 },{ 1,3 },{ 1,4 },{ 2,1 },{ 3,1 },{ 4,1 },
{ 6,2 },{ 6,3 },{ 6,4 },{ 2,6 },{ 3,6 },{ 4,6 } };
loopInitializer(enviroment, pulsar, origin);
break;
}
case 6:
{
vector < pair<int, int>> beacon =
{ { 0,0 },{ 0,1 },{ 0,2 },{ -1,0 },{ -1,1 },{ -1,2 },
{ 1,0 },{ 1,1 },{ 1,2 },{ 2,0 },{ 2,1 },{ 2,2 },
{ -2,0 },{ -2,2 },{ -3,0 },{ -3,1 },{ -3,2 },
{ 3,0 },{ 3,2 },{ 4,0 },{ 4,1 },{ 4,2 },
};
loopInitializer(enviroment, beacon, origin);
break;
}
case 7:
{
vector < pair<int, int>> spaceShip =
{ { 0,0 },{ 0,3 },{ 2,0 },{ 1,4 },{ 2,4 },{ 3,1 },
{ 3,2 },{ 3,3 },{ 3,4 }
};
loopInitializer(enviroment, spaceShip, origin);
break;
}
default:
cout << "Invalid Choice" << endl;
}
runGame(enviroment, sleep);
}
// https://www.wikiwand.com/en/Conway's_Game_of_Life
int main()
{
cout << " Welcome to Conways Game of Life" << endl;
cout << " For best result, expand your console window size" << endl;
cout << "Please select one of the following classic fields" << endl;
int choice;
cout << "\n Conway Menu\n"
<< "1. Glider\n"
<< "2. Blinker\n"
<< "3. Toad\n"
<< "4. Beacon\n"
<< "5. Pulsar\n"
<< "6. Pentadecathlon \n"
<< "7. Lightweight spaceship \n"
<< " Your choice >> ";
cin >> choice;
int gottaGoFast;
cout << "How fast do you want each frame? (in milliseconds) - recommended 125" << endl;
cin >> gottaGoFast;
switch (choice)
{
case 1:
initialize(35, 60, 1, gottaGoFast);
break;
case 2:
initialize(35, 60, 2, gottaGoFast);
break;
case 3:
initialize(35, 60, 3, gottaGoFast);
break;
case 4:
initialize(35, 60, 4, gottaGoFast);
break;
case 5:
initialize(35, 60, 5, gottaGoFast);
break;
case 6:
initialize(35, 60, 6, gottaGoFast);
break;
case 7:
initialize(35, 60, 7, gottaGoFast);
break;
default:
cout << "Invalid Choice" << endl;
}
}
Last updated