diff --git a/.gitignore b/.gitignore index 259148f..fc96444 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,7 @@ *.exe *.out *.app + +# some locale folders +cmake-build-debug +.idea \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c681a0d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.16) +project(game-of-life) + +set(CMAKE_CXX_STANDARD 14) + +add_executable(game-of-life src/main.cpp src/Message.cpp src/Message.h src/color.h src/GetInput.cpp src/GetInput.h src/GameOfLife.cpp src/GameOfLife.h src/Game.cpp src/Game.h src/Patterns.cpp src/Patterns.h src/Util.cpp src/Util.h) \ No newline at end of file diff --git a/README.md b/README.md index 615eee4..6909450 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,18 @@ -# game-of-life -This is a demonstration in C++ of a game called Game of life created by John Horton Conway in 1970 +# Game of life +This is a demonstration in C++ of a game called [Game of life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) created by John Horton Conway in 1970 + +### The Game Rules +> At each step in time, the following transitions occur: +1. Any live cell with fewer than two live neighbours dies, as if by underpopulation. +2. Any live cell with two or three live neighbours lives on to the next generation. +3. Any live cell with more than three live neighbours dies, as if by overpopulation. +4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. + +### License & Copyright +- Written by [Llewellyn van der Merwe](https://github.com/Llewellynvdm), April 2020 +- Copyright (C) 2020. All Rights Reserved +- License [GNU/GPL Version 2 or later](http://www.gnu.org/licenses/gpl-2.0.html) + +### Thank You! (2020/04) +- Originally Forked [Mario Talevski](https://github.com/MarioTalevski/game-of-life) +- [Champlain College](https://www.champlain.edu/) [SDEV-240-81A](https://classlist.champlain.edu/show/course/number/SDEV_240) \ No newline at end of file diff --git a/patterns/glider.txt b/patterns/glider.txt new file mode 100644 index 0000000..2d772f2 --- /dev/null +++ b/patterns/glider.txt @@ -0,0 +1,5 @@ +2 3 +3 4 +4 2 +4 3 +4 4 \ No newline at end of file diff --git a/patterns/glidergun.txt b/patterns/glidergun.txt new file mode 100644 index 0000000..5137ec0 --- /dev/null +++ b/patterns/glidergun.txt @@ -0,0 +1,36 @@ +-2 26 +-2 25 +-3 26 +-3 25 +7 26 +7 25 +7 24 +8 27 +8 23 +9 28 +9 22 +10 28 +10 22 +11 25 +12 27 +12 23 +13 26 +13 25 +13 24 +14 25 +17 28 +17 27 +17 26 +18 28 +18 27 +18 26 +19 29 +19 25 +21 29 +21 30 +21 25 +21 24 +31 26 +31 27 +32 26 +32 27 \ No newline at end of file diff --git a/patterns/testboard.txt b/patterns/testboard.txt new file mode 100644 index 0000000..cbf076e --- /dev/null +++ b/patterns/testboard.txt @@ -0,0 +1,5 @@ +5 4 +7 4 +5 5 +6 5 +5 6 \ No newline at end of file diff --git a/src/Game.cpp b/src/Game.cpp new file mode 100644 index 0000000..fa8359d --- /dev/null +++ b/src/Game.cpp @@ -0,0 +1,75 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-240-81A + * + * C++ Final Project (first semester) - Coding Component (2020/05/02) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This is a demonstration in C++ of a game called + * Game of life created by John Horton Conway in 1970 + * https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , April 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// internal classes +#include "Game.h" +// libraries +#include + +using namespace std; + +namespace GOL { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * I am trying out namespace just to see how it works :) any input would be great! + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + // check if we are still active + bool Game::isActive() const { + return Game::active; + } + + // set game active state + void Game::setActive(bool active) { + Game::active = active; + } + + // stop the board game + void Game::stop() { + this->setActive(false); + } + + // start the board game + void Game::start() { + this->setActive(true); + } + + // check if player is still playing + bool Game::isStillPlaying() const { + return Game::play; + } + + // stop the whole game + void Game::stopPlaying() { + Game::play = false; + } + + // start the whole game + void Game::startPlaying() { + Game::play = true; + } + + // get the game color + const string &Game::getColor() const { + return Game::color; + } + + void Game::setColor(const string &color) { + Game::color = color; + } +} \ No newline at end of file diff --git a/src/Game.h b/src/Game.h new file mode 100644 index 0000000..5c09125 --- /dev/null +++ b/src/Game.h @@ -0,0 +1,100 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-240-81A + * + * C++ Final Project (first semester) - Coding Component (2020/05/02) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This is a demonstration in C++ of a game called + * Game of life created by John Horton Conway in 1970 + * https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , April 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef GOL_GAME_H +#define GOL_GAME_H + +// internal classes +#include "color.h" +#include "Message.h" +// libraries +#include +#include + +using namespace std; + +namespace GOL { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * I am trying out namespace just to see how it works :) any input would be great! + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + // class to manage game behaviour + class Game { + protected: + // playing status + bool play; + // game color + string color; + // switch to stop board game + bool active; + + // start the whole game + void startPlaying(); + + // set active state + void setActive(bool active); + + public: + // instantiate Message class pointer + Message *message; + + // constructor + Game() { + // start playing + startPlaying(); + // game color + setColor(COLOR_GREEN); + // set the board game to active + setActive(true); + // instantiate the message class on the heap as well + message = new Message; + } + + // destructor + ~Game() { + // remove message from heap memory + delete message; + } + + // set the game color + void setColor(const string &color); + + // get the game color + const string &getColor() const; + + // start the board game + void start(); + + // stop the board game + void stop(); + + // stop the whole game + void stopPlaying(); + + // are we still playing + bool isStillPlaying() const; + + // check if we are still active + bool isActive() const; + + }; +} + + +#endif //GOL_GAME_H diff --git a/src/GameOfLife.cpp b/src/GameOfLife.cpp new file mode 100644 index 0000000..1679abb --- /dev/null +++ b/src/GameOfLife.cpp @@ -0,0 +1,234 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-240-81A + * + * C++ Final Project (first semester) - Coding Component (2020/05/02) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This is a demonstration in C++ of a game called + * Game of life created by John Horton Conway in 1970 + * https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , April 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "GameOfLife.h" + +namespace GOL { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * I am trying out namespace just to see how it works :) any input would be great! + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + // set the active coordinate + void GameOfLife::set(int x, int y) { + GameOfLife::activeState[x + GameOfLife::center][y + GameOfLife::center] = true; + } + + // unset any coordinate + void GameOfLife::unset(int x, int y) { + GameOfLife::activeState[x + GameOfLife::center][y + GameOfLife::center] = false; + } + + // reset the board + void GameOfLife::reset() { + for (int x = 0; x < GameOfLife::size; x++) { + for (int y = 0; y < GameOfLife::size; y++) { + GameOfLife::previousState[x][y] = false; + GameOfLife::activeState[x][y] = false; + } + } + // any moment reset is called we also re-start the game internally + this->start(); + // do some house cleaning resets + this->setActiveInfinity(false); + this->setInfinityCounter(0); + this->setInfinity(false); + } + + // print the board with active coordinates + void GameOfLife::print(int action) { + if (this->isActive()) { + // make sure we stay in same color + cout << this->getColor(); + // stop game if all are dead + if (action == 1) { + this->stop(); + } + // loop over the y axis + for (int y = GameOfLife::boardSize; y > 0; y--) { + // loop over the x axis + for (int x = 1; x < GameOfLife::boardSize; x++) { + if (x == 1) { + // add line numbers + if (action == 3) { + if (y < 10) { + cout << y << " "; + } else { + cout << y; + } + } else { + cout << " "; + } + } + // check if a cell is active/alive + if (GameOfLife::activeState[x + GameOfLife::center][y + GameOfLife::center]) { + cout << " O "; + // check if one cell in view is still active (and not still) + if (!GameOfLife::previousState[x + GameOfLife::center][y + GameOfLife::center] || + this->isActiveInfinity()) { + // if this is infinity + if (this->isActiveInfinity()) { + this->decrementInfinity(); + } + this->start(); + } + } else { + cout << " . "; + } + // print end of line when at the end of line + if (x == GameOfLife::boardSize - 1) { + cout << endl; + } + } + } + // add bottom line of numbers if needed + if (action == 3) { + cout << " "; + for (int x = 1; x < GameOfLife::boardSize; x++) { + if (x < 10) { + cout << " " << x << " "; + } else { + cout << " " << x; + } + } + cout << endl; + } + // if this is infinity + if (action == 1 && this->isActiveInfinity() && this->getInfinityCounter() < 0) { + // when the preset infinity controller switches + // reach its conclusion stop the game + // so the player can choose another pattern + this->stop(); + } + } + } + + // copy the active state to the previous state array + void GameOfLife::copyState() { + // loop over the entire x axis of the board + for (int x = 0; x < GameOfLife::size; x++) { + // loop over the entire y axis of the board + for (int y = 0; y < GameOfLife::size; y++) { + // copy the value over to the previous state + GameOfLife::previousState[x][y] = GameOfLife::activeState[x][y]; + } + } + } + + // set the board active state + void GameOfLife::setState() { + // make sure we have the active state copied + this->copyState(); + // check every cell on the board + // loop over the entire x axis of the board + for (int x = 1; x < GameOfLife::size; x++) { + // loop over the entire y axis of the board + for (int y = 1; y < GameOfLife::size; y++) { + int alive = 0; + // loop to check all eight neighbours + // . . . + // . 0 . + // . . . + // the dots are the neighbours + // zero is the active cell + for (int x2 = -1; x2 < 2; x2++) { // this loop increments the x axis lookup + for (int y2 = -1; y2 < 2; y2++) { // this loop increments the y axis lookup + // when x and y are 0 then + // do not check since it is + // the current active cell + if (!(x2 == 0 && y2 == 0)) { + // check if this neighbour was alive + if (GameOfLife::previousState[x + x2][y + y2]) { + // when alive we increment the alive value + // which we later will use to act upon + ++alive; + } + } + } + } + // now let's act upon the alive status + if (alive < 2) { + // Any live cell with fewer than two live neighbours dies, as if caused by under-population. + // what ever that means... + GameOfLife::activeState[x][y] = false; + } else if (alive == 3) { + // Any live cell with three live neighbours lives on to the next generation. + // what ever that means... + GameOfLife::activeState[x][y] = true; + } else if (alive > 3) { + // Any live cell with more than three live neighbours dies, as if by over-population. + // Which is not true, I have eight children and a very bright future!!! + // We were made to be fruitful Genesis 1:28 (in real Life) + // but in this game... + GameOfLife::activeState[x][y] = false; + } + } + } + } + + // get view board size + int GameOfLife::getViewSize() { + // return string + return GameOfLife::boardSize; + } + + // get view board size + int GameOfLife::getViewArea() { + return GameOfLife::boardSize * GameOfLife::boardSize; + } + + // get settable board area + int GameOfLife::getSettableArea() { + return GameOfLife::boardSize * 3; + } + + // check if infinity is set + bool GameOfLife::isInfinitySet() const { + return GameOfLife::infinitySet; + } + + // set infinity + void GameOfLife::setInfinity(bool infinitySet) { + GameOfLife::infinitySet = infinitySet; + } + + // check if infinity is active + bool GameOfLife::isActiveInfinity() const { + return activeInfinity; + } + + // set the infinity active state + void GameOfLife::setActiveInfinity(bool activeInfinity) { + GameOfLife::activeInfinity = activeInfinity; + } + + // get the infinity counter value + long GameOfLife::getInfinityCounter() const { + return GameOfLife::infinityCounter; + } + + // set the infinity counter value + void GameOfLife::setInfinityCounter(long infinity) { + GameOfLife::infinityCounter = infinity; + } + + // decrement infinity counter value + void GameOfLife::decrementInfinity() { + GameOfLife::infinityCounter--; + } +} \ No newline at end of file diff --git a/src/GameOfLife.h b/src/GameOfLife.h new file mode 100644 index 0000000..a632b86 --- /dev/null +++ b/src/GameOfLife.h @@ -0,0 +1,112 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-240-81A + * + * C++ Final Project (first semester) - Coding Component (2020/05/02) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This is a demonstration in C++ of a game called + * Game of life created by John Horton Conway in 1970 + * https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , April 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef GOL_GAMEOFLIFE_H +#define GOL_GAMEOFLIFE_H + +#include "Game.h" + +namespace GOL { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * I am trying out namespace just to see how it works :) any input would be great! + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + class GameOfLife : public Game { + private: + // the board game size + static const int boardSize = 30; + // hidden size to center the view + static const int center = boardSize * 4; + // hidden size to be able to move gliders and ships out of view + static const int size = boardSize * 9; + // active state arrays + bool activeState[size][size] = {}; + bool previousState[size][size] = {}; + // has infinity been set? + bool infinitySet; + signed long infinityCounter; + // infinity switches + bool activeInfinity; + + // copy the active state to the previous state array + void copyState(); + + public: + + // constructor + GameOfLife() { + // turn off infinity + setActiveInfinity(false); + setInfinity(false); + setInfinityCounter(0); + } + + // destructor + ~GameOfLife() {} + + // set the active coordinates + void set(int x, int y); + + // unset any coordinates + void unset(int x, int y); + + // reset the board + void reset(); + + // print the board with active coordinates + void print(int action = 1); + + // set the board active state + void setState(); + + // get view board size + int getViewSize(); + + // get view board area + int getViewArea(); + + // get settable board area + int getSettableArea(); + + // check if infinity is set + bool isInfinitySet() const; + + // set infinity + void setInfinity(bool infinitySet); + + // check if infinity is active + bool isActiveInfinity() const; + + // set the infinity active state + void setActiveInfinity(bool activeInfinity); + + // get the infinity counter value + long getInfinityCounter() const; + + // set the infinity counter value + void setInfinityCounter(long infinity); + + // decrement infinity counter value + void decrementInfinity(); + }; + +} + + +#endif //GOL_GAMEOFLIFE_H diff --git a/src/GetInput.cpp b/src/GetInput.cpp new file mode 100644 index 0000000..5b0d4a7 --- /dev/null +++ b/src/GetInput.cpp @@ -0,0 +1,32 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-240-81A + * + * C++ Final Project (first semester) - Coding Component (2020/05/02) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This is a demonstration in C++ of a game called + * Game of life created by John Horton Conway in 1970 + * https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , April 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// internal classes +#include "GetInput.h" + +namespace GOL { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * I am trying out namespace just to see how it works :) any input would be great! + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + // get the message string + string GetInput::get() const { + return input; + } +} diff --git a/src/GetInput.h b/src/GetInput.h new file mode 100644 index 0000000..dba38f5 --- /dev/null +++ b/src/GetInput.h @@ -0,0 +1,65 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-240-81A + * + * C++ Final Project (first semester) - Coding Component (2020/05/02) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This is a demonstration in C++ of a game called + * Game of life created by John Horton Conway in 1970 + * https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , April 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef GOL_GETINPUT_H +#define GOL_GETINPUT_H + +// internal classes +#include "Message.h" +// libraries +#include +#include + +using namespace std; + +namespace GOL { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * I am trying out namespace just to see how it works :) any input would be great! + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + class GetInput { + private: + string input; + public: + // constructor + GetInput(string question = "") { + // set message + Message ask(question); + // print question + ask.print(0); + // get the input requested + cin >> input; + } + + GetInput(Message &question) { + // print question + question.print(0); + // get the input requested + cin >> input; + } + + // destructor + ~GetInput() {} + + // get method + string get() const; + }; +} + +#endif //GOL_GETINPUT_H diff --git a/src/Message.cpp b/src/Message.cpp new file mode 100644 index 0000000..fd19e53 --- /dev/null +++ b/src/Message.cpp @@ -0,0 +1,103 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-240-81A + * + * C++ Final Project (first semester) - Coding Component (2020/05/02) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This is a demonstration in C++ of a game called + * Game of life created by John Horton Conway in 1970 + * https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , April 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// internal classes +#include "Message.h" +// libraries +#include +#include + +namespace GOL { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * I am trying out namespace just to see how it works :) any input would be great! + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + // print to terminal the message + void Message::print(int addNewLine) { + // stay in the terminal color + cout << color; + // only print the message + if (addNewLine == 1) { + cout << message << endl; + } else { + cout << message; + } + // empty the message value + message = ""; + } + + // get the message + string Message::get(int addNewLine) { + // get message + string tmp = message; + // empty the message value + message = ""; + // only print the message + if (addNewLine == 1) { + return tmp + "\n"; + } else { + return tmp; + } + } + + // add a line to the message + Message *Message::add(string line, string newline) { + if ("LINE" == line) { + // add a line + line = ""; + message += this->addPadding(line, max_length, spacer_line) + newline; + } else { + // store the string + message += this->prepLine(line, spacer) + newline; + } + return this; + } + + // prepare a string before adding + string Message::prepLine(string &str, string &padding) { + // add padding + return this->addPadding(3, str, padding); + } + + // to model a question for the get input class + string Message::ask(string question) { + // stay in the terminal color + cout << color; + return addPadding(3, question, spacer); + } + + // add padding in front of string + string Message::addPadding(int length, string str, string &padding) { + for (int i = 0; i < length; i++) { + str = padding + str; + } + return str; + } + + // add padding behind string + string Message::addPadding(string str, int length, string &padding) { + // get the string length + int string_length = str.length(); + for (int i = string_length; i < length; i++) { + str += padding; + } + return str; + } +} + diff --git a/src/Message.h b/src/Message.h new file mode 100644 index 0000000..2b9bc94 --- /dev/null +++ b/src/Message.h @@ -0,0 +1,90 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-240-81A + * + * C++ Final Project (first semester) - Coding Component (2020/05/02) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This is a demonstration in C++ of a game called + * Game of life created by John Horton Conway in 1970 + * https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , April 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef GOL_MESSAGE_H +#define GOL_MESSAGE_H + +// internal classes +#include "color.h" +// libraries +#include +#include +#include + +using namespace std; + +namespace GOL { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * I am trying out namespace just to see how it works :) any input would be great! + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + // class to manage all messages + class Message { + private: + // message color + string color = COLOR_GREEN; + string color_reset = COLOR_RESET; + // the message string + string message; + // line max length + int max_length = 95; + // line character + string spacer_line = "-"; + // string ending + string end = "#"; + + // prep string + string prepLine(string &str, string &padding); + + public: + // space character + string spacer = " "; + // string beginning + string begin = "#"; + + // constructor + Message(string lines = "") : message{lines} { + cout << color; + } + + // destructor + ~Message() { + cout << color_reset; + } + + // print method + void print(int addNewLine = 1); + + // get message + string get(int addNewLine = 1); + + // add line method + Message *add(string line, string newline = "\n"); + + // to model a question for the get input class + string ask(string question); + + // add padding around string + string addPadding(string str, int length, string &padding); + + string addPadding(int length, string str, string &padding); + }; +} + +#endif //GOL_MESSAGE_H diff --git a/src/Patterns.cpp b/src/Patterns.cpp new file mode 100644 index 0000000..d17cf7a --- /dev/null +++ b/src/Patterns.cpp @@ -0,0 +1,432 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-240-81A + * + * C++ Final Project (first semester) - Coding Component (2020/05/02) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This is a demonstration in C++ of a game called + * Game of life created by John Horton Conway in 1970 + * https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , April 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// internal classes +#include "Patterns.h" +#include "GameOfLife.h" +// libraries +#include +#include + +using namespace std; + +namespace GOL { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * I am trying out namespace just to see how it works :) any input would be great! + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + // set the preset pattern + bool Patterns::setPreset(int pattern, GameOfLife *game) { + // we have the infinity stuff set + game->setInfinity(true); + // default means pattern does not yet exist + switch (pattern) { + case 1: + return this->testBoard(game); + case 2: + return this->blinker(game); + case 3: + return this->toad(game); + case 4: + return this->beacon(game); + case 5: + return this->pulsar(game); + case 6: + return this->pentaDecathlon(game); + case 7: + return this->gliderGun(game); + case 8: + return this->glidersEaters(game); + case 9: + return this->glider(game); + case 10: + return this->lightWeightSpaceship(game); + case 11: + return this->middleWeightSpaceship(game); + case 12: + return this->heavyWeightSpaceship(game); + default: + game->setInfinity(false); + return false; + } + } + + // set the preset pattern + map Patterns::getPresets() { + map presets; + presets[1] = "Test Board (fun)"; + presets[2] = "Blinker (Oscillator - infinity)"; + presets[3] = "Toad (Oscillator - infinity)"; + presets[4] = "Beacon (Oscillator - infinity)"; + presets[5] = "Pulsar (Oscillator - infinity)"; + presets[6] = "Penta-decathlon (Oscillator - infinity)"; + presets[7] = "Glider Gun (fun)"; + presets[8] = "Gliders Eaters (fun)"; + presets[9] = "Glider (Spaceship)"; + presets[10] = "Light Weight (Spaceship)"; + presets[11] = "Middle Weight (Spaceship)"; + presets[12] = "Heavy Weight (Spaceship)"; + return presets; + } + + // set the test board pattern + bool Patterns::testBoard(GameOfLife *game) { + game->set(11, 12); + game->set(11, 14); + game->set(11, 13); + game->set(12, 13); + game->set(13, 12); + // deal with infinity + game->setActiveInfinity(false); + game->setInfinityCounter(0); + return true; + } + + // set the blinker pattern + bool Patterns::blinker(GameOfLife *game) { + game->set(5, 5); + game->set(5, 6); + game->set(5, 7); + // deal with infinity + game->setActiveInfinity(true); + game->setInfinityCounter(3 * 20); + return true; + } + + // set the toad pattern + bool Patterns::toad(GameOfLife *game) { + game->set(4, 7); + game->set(5, 5); + game->set(5, 8); + game->set(6, 5); + game->set(6, 8); + game->set(7, 6); + // deal with infinity + game->setActiveInfinity(true); + game->setInfinityCounter(6 * 20); + return true; + } + + // set the beacon pattern + bool Patterns::beacon(GameOfLife *game) { + game->set(4, 5); + game->set(4, 6); + game->set(5, 5); + game->set(6, 8); + game->set(7, 8); + game->set(7, 7); + // deal with infinity + game->setActiveInfinity(true); + game->setInfinityCounter(6 * 20); + return true; + } + + // set the pulsar pattern + bool Patterns::pulsar(GameOfLife *game) { + // outer rings + game->set(8, 6); + game->set(9, 6); + game->set(10, 6); + + game->set(14, 6); + game->set(15, 6); + game->set(16, 6); + + game->set(18, 8); + game->set(18, 9); + game->set(18, 10); + + game->set(18, 14); + game->set(18, 15); + game->set(18, 16); + + game->set(6, 8); + game->set(6, 9); + game->set(6, 10); + + game->set(6, 14); + game->set(6, 15); + game->set(6, 16); + + game->set(8, 18); + game->set(9, 18); + game->set(10, 18); + + game->set(14, 18); + game->set(15, 18); + game->set(16, 18); + + // inner rings + game->set(8, 11); + game->set(9, 11); + game->set(10, 11); + + game->set(14, 11); + game->set(15, 11); + game->set(16, 11); + + game->set(13, 8); + game->set(13, 9); + game->set(13, 10); + + game->set(13, 14); + game->set(13, 15); + game->set(13, 16); + + game->set(11, 8); + game->set(11, 9); + game->set(11, 10); + + game->set(11, 14); + game->set(11, 15); + game->set(11, 16); + + game->set(8, 13); + game->set(9, 13); + game->set(10, 13); + + game->set(14, 13); + game->set(15, 13); + game->set(16, 13); + // deal with infinity + game->setActiveInfinity(true); + game->setInfinityCounter(5 * 600); + return true; + } + + // set the Penta-decathlon pattern + bool Patterns::pentaDecathlon(GameOfLife *game) { + // top + game->set(3, 12); + game->set(4, 12); + game->set(5, 12); + game->set(5, 11); + game->set(5, 13); + + // middle + game->set(13, 11); + game->set(13, 13); + game->set(13, 12); + game->set(12, 12); + game->set(11, 12); + game->set(10, 12); + game->set(9, 12); + game->set(8, 12); + game->set(8, 11); + game->set(8, 13); + + // bottom + game->set(18, 12); + game->set(17, 12); + game->set(16, 12); + game->set(16, 11); + game->set(16, 13); + + // deal with infinity + game->setActiveInfinity(true); + game->setInfinityCounter(5 * 350); + return true; + } + + // set the glider pattern + bool Patterns::glider(GameOfLife *game) { + game->set(2, 3); + game->set(3, 4); + game->set(4, 2); + game->set(4, 3); + game->set(4, 4); + // deal with infinity + game->setActiveInfinity(false); + game->setInfinityCounter(0); + return true; + } + + // set the glider gun pattern + bool Patterns::gliderGun(GameOfLife *game) { + // first square + game->set(-2, 26); + game->set(-2, 25); + game->set(-3, 26); + game->set(-3, 25); + + // first after + game->set(7, 26); + game->set(7, 25); + game->set(7, 24); + game->set(8, 27); + game->set(8, 23); + game->set(9, 28); + game->set(9, 22); + game->set(10, 28); + game->set(10, 22); + game->set(11, 25); + game->set(12, 27); + game->set(12, 23); + game->set(13, 26); + game->set(13, 25); + game->set(13, 24); + game->set(14, 25); + + // second after + game->set(17, 28); + game->set(17, 27); + game->set(17, 26); + game->set(18, 28); + game->set(18, 27); + game->set(18, 26); + game->set(19, 29); + game->set(19, 25); + game->set(21, 29); + game->set(21, 30); + game->set(21, 25); + game->set(21, 24); + + // last square + game->set(31, 26); + game->set(31, 27); + game->set(32, 26); + game->set(32, 27); + + // deal with infinity + game->setActiveInfinity(true); + game->setInfinityCounter(5 * 2000); + return true; + } + + // set the light weight spaceship pattern + bool Patterns::lightWeightSpaceship(GameOfLife *game) { + game->set(5, 4); + game->set(5, 5); + game->set(6, 2); + game->set(6, 3); + game->set(6, 5); + game->set(6, 6); + game->set(7, 2); + game->set(7, 3); + game->set(7, 4); + game->set(7, 5); + game->set(8, 3); + game->set(8, 4); + // deal with infinity + game->setActiveInfinity(false); + game->setInfinityCounter(0); + return true; + } + + // set the middle weight spaceship pattern + bool Patterns::middleWeightSpaceship(GameOfLife *game) { + game->set(2, 10); + game->set(2, 12); + game->set(3, 9); + game->set(4, 9); + game->set(4, 13); + game->set(5, 9); + game->set(6, 9); + game->set(6, 12); + game->set(7, 9); + game->set(7, 10); + game->set(7, 11); + // deal with infinity + game->setActiveInfinity(false); + game->setInfinityCounter(0); + return true; + } + + // set the heavy weight spaceship pattern + bool Patterns::heavyWeightSpaceship(GameOfLife *game) { + game->set(2, 10); + game->set(2, 12); + game->set(3, 9); + game->set(4, 9); + game->set(4, 13); + game->set(5, 9); + game->set(5, 13); + game->set(6, 9); + game->set(7, 9); + game->set(7, 12); + game->set(8, 9); + game->set(8, 10); + game->set(8, 11); + // deal with infinity + game->setActiveInfinity(false); + game->setInfinityCounter(0); + return true; + } + + // set the gliders eaters pattern + bool Patterns::glidersEaters(GameOfLife *game) { + // top left + game->set(5, 3); + game->set(5, 4); + game->set(6, 4); + game->set(7, 4); + game->set(8, 5); + game->set(8, 6); + game->set(7, 6); + + // bottom left + game->set(13, 4); + game->set(14, 4); + game->set(15, 4); + game->set(15, 3); + game->set(12, 5); + game->set(12, 6); + game->set(13, 6); + + // top right + game->set(7, 19); + game->set(8, 19); + game->set(8, 20); + game->set(7, 21); + game->set(6, 21); + game->set(5, 21); + game->set(5, 22); + + // bottom right + game->set(13, 19); + game->set(12, 19); + game->set(12, 20); + game->set(13, 21); + game->set(14, 21); + game->set(15, 21); + game->set(15, 22); + + // center top + game->set(9, 10); + game->set(9, 15); + + // center middle + game->set(10, 8); + game->set(10, 9); + game->set(10, 11); + game->set(10, 12); + game->set(10, 13); + game->set(10, 14); + game->set(10, 16); + game->set(10, 17); + + // center bottom + game->set(11, 10); + game->set(11, 15); + // deal with infinity + game->setActiveInfinity(true); + game->setInfinityCounter(5 * 605); + return true; + } +} \ No newline at end of file diff --git a/src/Patterns.h b/src/Patterns.h new file mode 100644 index 0000000..3c9b736 --- /dev/null +++ b/src/Patterns.h @@ -0,0 +1,74 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-240-81A + * + * C++ Final Project (first semester) - Coding Component (2020/05/02) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This is a demonstration in C++ of a game called + * Game of life created by John Horton Conway in 1970 + * https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , April 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef GOL_PATTERNS_H +#define GOL_PATTERNS_H + +// internal classes +#include "GameOfLife.h" +// libraries +#include +#include +#include + +using namespace std; + +namespace GOL { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * I am trying out namespace just to see how it works :) any input would be great! + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + // class to set all board patterns + class Patterns { + private: + // all the patterns + bool testBoard(GameOfLife *game); + + bool blinker(GameOfLife *game); + + bool toad(GameOfLife *game); + + bool beacon(GameOfLife *game); + + bool pulsar(GameOfLife *game); + + bool pentaDecathlon(GameOfLife *game); + + bool gliderGun(GameOfLife *game); + + bool glidersEaters(GameOfLife *game); + + bool glider(GameOfLife *game); + + bool lightWeightSpaceship(GameOfLife *game); + + bool middleWeightSpaceship(GameOfLife *game); + + bool heavyWeightSpaceship(GameOfLife *game); + + public: + // set the preset pattern + bool setPreset(int pattern, GameOfLife *game); + + // get the preset pattern list + static map getPresets(); + }; +} + +#endif //GOL_PATTERNS_H diff --git a/src/Util.cpp b/src/Util.cpp new file mode 100644 index 0000000..8ffec39 --- /dev/null +++ b/src/Util.cpp @@ -0,0 +1,311 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-240-81A + * + * C++ Final Project (first semester) - Coding Component (2020/05/02) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This is a demonstration in C++ of a game called + * Game of life created by John Horton Conway in 1970 + * https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , April 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// internal classes +#include "Util.h" +#include "GameOfLife.h" +#include "Patterns.h" +#include "Message.h" +#include "GetInput.h" +// libraries +#include + +using namespace std; + +namespace GOL { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * I am trying out namespace just to see how it works :) any input would be great! + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + // the introduction message + void Util::introMessage(GameOfLife *game) { + game->message->add("LINE"); + game->message->add("This is a demonstration in C++ of a game called"); + game->message->add("Game of life created by John Horton Conway in 1970"); + game->message->add("https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life"); + game->message->add("LINE"); + game->message->add("Written by Llewellyn van der Merwe"); + game->message->add("LINE"); + game->message->add("The Rules"); + game->message->add("At each step in time, the following transitions occur:"); + game->message->add("1. Any live cell with fewer than two live neighbours dies, as if by underpopulation."); + game->message->add("2. Any live cell with two or three live neighbours lives on to the next generation."); + game->message->add("3. Any live cell with more than three live neighbours dies, as if by overpopulation."); + game->message->add("4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction."); + game->message->add("LINE")->print(0); + } + + // getting the coordinates for the board + void Util::getCoordinates(GameOfLife *game) { + // lets make sure our board is clean + game->reset(); + // instantiate x and y to be integers + int x, y; + // setup the question + game->message->add("This game has the following input options"); + game->message->add("LINE"); + game->message->add("1. Select a pattern from our presets."); + game->message->add("2. Enter a path to a file with the coordinates."); + game->message->add("3. Manually add coordinates to the board."); + game->message->add("or 'q' to quit")->print(0); + // get the user path to action + GetInput action(game->message->ask("Enter your selection: ")); + // clean the screen + Util::clearScreen(); + game->message->add("LINE"); + // file or preset was selected + if (action.get() == "2") { + // clean the screen + Util::clearScreen(); + while (true) { + // give info of the coordinates convention + game->message->add("Coordinates must be given in the following way"); + game->message->add("LINE"); + game->message->add("Each line must have two numbers separated by a space."); + game->message->add("The first number is the x axis value, and the second number is the y axis value."); + game->message->add("So each line represents a coordinate/cell on the board that is active/alive."); + game->message->add("The view area of the board has " + + to_string(game->getViewSize()) + " x " + + to_string(game->getViewSize()) + " = " + + to_string(game->getViewArea()) + " cells. But the board is far larger."); + game->message->add("Meaning you are able to add negative and positive values to a depth of -" + + to_string(game->getSettableArea()) + " and " + + to_string(game->getSettableArea()) + ".")->print(); + // get the file path + GetInput filepath(game->message->ask("Enter file path to read coordinates from, or 'b' to go back: ")); + // check if the player want to go back + if (filepath.get() == "b") { + // go back + getCoordinates(game); + break; + } else { + // read in the file path + ifstream readfile(filepath.get()); + // if we can open the file continue + if (readfile.is_open()) { + // instantiate bucket values + string fileline, x_coordinate, y_coordinate; + // get the lines from the file + while (getline(readfile, fileline)) { + // get the lines from the file + stringstream line_coordinate(fileline); + // get coordinates + getline(line_coordinate, x_coordinate, ' '); + getline(line_coordinate, y_coordinate, ' '); + // convert to number (integer) + x = stoi(x_coordinate); + y = stoi(y_coordinate); + // set the coordinates + game->set(x, y); + } + break; + } else { + game->message->add("No such file, try again.")->print(); + } + } + } + // ask to set infinity + game->setInfinity(false); + } else if (action.get() == "1") { + // clean the screen + Util::clearScreen(); + game->message->add("These are the preset patterns"); + game->message->add("LINE"); + // instantiate Patterns class + Patterns patterns; + // loop over the presets + map::iterator preset; + map presets = patterns.getPresets(); + for (preset = presets.begin(); preset != presets.end(); preset++) { + game->message->add(to_string(preset->first) + ". " + preset->second); + } + // add message to allow player to go back + game->message->add("or 'b' to go back")->print(0); + // get selected preset + GetInput activePreset(game->message->ask("Enter your selection: ")); + // load the preset if the correct number was selected + if ((!activePreset.get().empty() && activePreset.get().find_first_not_of("0123456789") != string::npos) || + !patterns.setPreset(stoi(activePreset.get()), game)) { + game->message->add("No such preset was found, try again.")->print(); + // we try again + getCoordinates(game); + } + } else if (action.get() == "3") { + // clean the screen + Util::clearScreen(); + // give info of the coordinates convention + game->message->add("Coordinates must be given in the following way"); + game->message->add("LINE"); + game->message->add("Each entry must have two numbers separated by a space."); + game->message->add("The first number is the x axis value, and the second number is the y axis value."); + game->message->add("So each entry represents a coordinate/cell on the board that is active/alive."); + game->message->add("The view area of the board has " + + to_string(game->getViewSize()) + " x " + + to_string(game->getViewSize()) + " = " + + to_string(game->getViewArea()) + " cells.")->print(); + // get the coordinates from user manually + while (true) { + cout << game->message->ask( + "Enter the coordinates of an active/alive cell: "); + cin >> x >> y; + // make sure we get numbers + if (cin.fail()) { + // clear to ask the question again + cin.clear(); + cin.ignore(); + // give the warning + game->message->add("Must only be numbers!")->print(); + } else { + // set the coordinates + game->set(x, y); + // check if coordinates are correct + game->message->add("Check your entry")->print(); + // print the set coordinates + game->print(3); + // final check if the above coordinates are correct and if we must continue adding more + game->message->add("To continue you have the following options:"); + game->message->add("1. Add another cell."); + game->message->add("2. Undo that last entry."); + // game->message->add("3. Save coordinates to a file and start game->"); TODO + game->message->add("3. Stop adding cells.")->print(); + GetInput optionInput(game->message->ask("Enter the number: ")); + // ready to start game? + if (optionInput.get() == "2") { + // unset the last coordinates + game->unset(x, y); + } else if (optionInput.get() == "3") { + // stop adding cells + break; + } + } + } + game->setInfinity(false); + } else { + // quit playing the game + game->stopPlaying(); + } + } + + void Util::run(GameOfLife *game) { + // make sure the game is active + if (game->isStillPlaying()) { + // get the coordinates + Util::getCoordinates(game); + // make sure the game is active + if (game->isStillPlaying()) { + // show the board and the selected coordinates + game->message->add("LINE"); + game->message->add("These are the coordinates.")->print(0); + // print the set coordinates + game->print(0); + // give notice of infinity treatment + Util::infinityNote(game); + // final check if the above coordinates are correct + game->message->add("LINE"); + GetInput startGame(game->message->ask("Board setup complete. Start the game ? (y/n) ")); + // ready to start game? + if (startGame.get() == "y" || startGame.get() == "Y") { + while (true) { + // print the board + game->print(); + // update the board state + game->setState(); + // slow down... ;) + usleep(130000); + // clean the screen + if (game->isActive()) { + Util::clearScreen(); + } else { + // show the board and the selected coordinates + Util::getCoordinates(game); + // if the player quit + if (game->isStillPlaying()) { + // show the board and the selected coordinates + game->message->add("LINE"); + game->message->add("These are the new coordinates.")->print(); + // print the set coordinates + game->print(0); + // give notice of infinity treatment + Util::infinityNote(game); + // final check if the above coordinates are correct + game->message->add("LINE"); + GetInput startGameAgain( + game->message->ask("Board setup complete. Start the game again ? (y/n) ")); + if (startGameAgain.get() != "y" && startGameAgain.get() != "Y") { + break; + } + } else { + break; + } + } + } + } + // if we are still active + if (game->isStillPlaying()) { + // restart + Util::run(game); + } + } + } + } + + // give notice of infinity treatment + void Util::infinityNote(GameOfLife *game) { + if (game->isInfinitySet()) { + game->message->add("All infinite loops will automatically exit, sit back and enjoy!"); + game->message->add("LINE")->print(); + } else { + game->message->add("Just a little heads-up, you will need to manually exit the game"); + game->message->add("should it enter an infinite loop (Oscillator)."); + game->message->add("The game will only automatically exit if all visible cells are dead or still."); + game->message->add("LINE")->print(); + } + } + + // method to clear the screen + void Util::clearScreen() { + // Below Code Taken From This Project https://github.com/MarioTalevski/game-of-life + // Tested and working on Ubuntu and Cygwin +#if defined(OS_WIN) + HANDLE hStdOut = GetStdHandle( STD_OUTPUT_HANDLE ); + CONSOLE_SCREEN_BUFFER_INFO csbi; + DWORD count; + DWORD cellCount; + COORD homeCoords = { 0, 0 }; + + if (hStdOut == INVALID_HANDLE_VALUE) return; + + /* Get the number of cells in the current buffer */ + GetConsoleScreenBufferInfo( hStdOut, &csbi ); + cellCount = csbi.dwSize.X *csbi.dwSize.Y; + + /* Fill the entire buffer with spaces */ + FillConsoleOutputCharacter(hStdOut, (TCHAR) ' ', cellCount, homeCoords, &count); + + /* Fill the entire buffer with the current colors and attributes */ + FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count); + + SetConsoleCursorPosition( hStdOut, homeCoords ); + +#elif defined(OS_LINUX) || defined(OS_MAC) + cout << "\033[2J" << "\033[1;1H"; // Clears screen and moves cursor to home pos on POSIX systems +#endif + // Above Code Taken From This Project https://github.com/MarioTalevski/game-of-life + } +} diff --git a/src/Util.h b/src/Util.h new file mode 100644 index 0000000..177ed72 --- /dev/null +++ b/src/Util.h @@ -0,0 +1,64 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-240-81A + * + * C++ Final Project (first semester) - Coding Component (2020/05/02) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This is a demonstration in C++ of a game called + * Game of life created by John Horton Conway in 1970 + * https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , April 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef GOL_UTIL_H +#define GOL_UTIL_H + +// internal classes +#include "Game.h" +#include "GameOfLife.h" +#include "Message.h" +// libraries +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace GOL { + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * I am trying out namespace just to see how it works :) any input would be great! + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + // class combine useful methods + class Util { + public: + // force static use + Util() = delete; + // the introduction message + static void introMessage(GameOfLife *game); + + // the infinity message + static void infinityNote(GameOfLife *game); + + // the main method to run the game + static void run(GameOfLife *game); + + // getting the coordinates for the board + static void getCoordinates(GameOfLife *game); + + // method to clear the screen + static void clearScreen(); + }; +}; + +#endif //GOL_UTIL_H diff --git a/src/color.h b/src/color.h new file mode 100644 index 0000000..ad6464e --- /dev/null +++ b/src/color.h @@ -0,0 +1,35 @@ +// Below Code Taken From This Project https://github.com/MarioTalevski/game-of-life +// Move OS defines up here to be used in different places +#if defined(_WIN32) || defined(WIN32) || defined(__MINGW32__) || defined(__BORLANDC__) +#define OS_WIN +// WINDOWS COLORS +#define COLOR_RED SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED) +#define COLOR_WARNING SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN) + +#define COLOR_BLUE SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_BLUE) + +#define COLOR_RESET SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15) + +#elif defined(linux) || defined(__CYGWIN__) +#define OS_LINUX + +#define COLOR_RED "\033[31m" +#define COLOR_GREEN "\033[32m" +#define COLOR_BLUE "\033[34m" +#define COLOR_RESET "\033[0m" + +#elif (defined(__APPLE__) || defined(__OSX__) || defined(__MACOS__)) && defined(__MACH__) // To ensure that we are running on a mondern version of macOS +#define OS_MAC + +#define COLOR_RED "\033[31m" +#define COLOR_GREEN "\033[32m" +#define COLOR_BLUE "\033[34m" +#define COLOR_RESET "\033[0m" + +#endif + +#if defined(OS_WIN) +#include // Use for windows +#endif + +// Above Code Taken From This Project https://github.com/MarioTalevski/game-of-life \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..05c01a3 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,49 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Champlain College SDEV-240-81A + * + * C++ Final Project (first semester) - Coding Component (2020/05/02) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * This is a demonstration in C++ of a game called + * Game of life created by John Horton Conway in 1970 + * https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Written by Llewellyn van der Merwe , April 2020 + * Copyright (C) 2020. All Rights Reserved + * License GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Originally Forked: Mario Talevski https://github.com/MarioTalevski/game-of-life + * But the code has been massively refactored into classes, + * so much that there is hardly any of the original code left unchanged. + * I have marked the areas that did not change at all, + * since those parts are not part of the above license or copyright. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// internal classes +#include "Util.h" +#include "GameOfLife.h" + +using namespace GOL; + +int main() { + // clean the screen + Util::clearScreen(); + // instantiate the game class on the heap + auto *game = new GameOfLife; + // print the intro message + Util::introMessage(game); + // play the game + Util::run(game); + // game has ended + game->message->add("GAME ENDED"); + game->message->add("LINE")->print(); + // remove game from heap memory + delete game; + return 0; +}