diff options
author | Adrian Kummerlaender | 2016-12-09 23:28:46 +0100 |
---|---|---|
committer | Adrian Kummerlaender | 2016-12-09 23:28:46 +0100 |
commit | b72dcd74717366f145b029d89ae11a085a5f5997 (patch) | |
tree | c90959183927ee1e9adc3dc08c631e2ae17f79ef | |
download | termlife-b72dcd74717366f145b029d89ae11a085a5f5997.tar termlife-b72dcd74717366f145b029d89ae11a085a5f5997.tar.gz termlife-b72dcd74717366f145b029d89ae11a085a5f5997.tar.bz2 termlife-b72dcd74717366f145b029d89ae11a085a5f5997.tar.lz termlife-b72dcd74717366f145b029d89ae11a085a5f5997.tar.xz termlife-b72dcd74717366f145b029d89ae11a085a5f5997.tar.zst termlife-b72dcd74717366f145b029d89ae11a085a5f5997.zip |
Initial working version
...of a plain Game Of Life displayed using `Termbox`.
-rw-r--r-- | CMakeLists.txt | 21 | ||||
-rw-r--r-- | life.cc | 46 | ||||
-rw-r--r-- | src/world.h | 146 |
3 files changed, 213 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d517ca3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.8) +project(life) + +set( + CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} -std=c++14 -W -Wall -Wextra -Winline -pedantic" +) + +include_directories( + src/ +) + +add_executable( + life + life.cc +) + +target_link_libraries( + life + termbox +) @@ -0,0 +1,46 @@ +#include <termbox.h> + +#include "world.h" + +int main(int, char*[]) { + tb_init(); + + tb_select_input_mode(TB_INPUT_ESC | TB_INPUT_MOUSE); + + life::World<20,20> world; + + while ( true ) { + struct tb_event ev; + int t = tb_poll_event(&ev); + + if ( t == -1 ) { + tb_shutdown(); + return -1; + } + + switch (t) { + case TB_EVENT_KEY: + switch ( ev.key ) { + case TB_KEY_ESC: + tb_shutdown(); + return 0; + case TB_KEY_SPACE: + world.tick(); + break; + } + break; + case TB_EVENT_MOUSE: + if (ev.key == TB_KEY_MOUSE_LEFT) { + world.summonLifeAt(ev.x, ev.y); + } + + break; + case TB_EVENT_RESIZE: + break; + } + + world.draw(); + } + + return 0; +} diff --git a/src/world.h b/src/world.h new file mode 100644 index 0000000..297d0c5 --- /dev/null +++ b/src/world.h @@ -0,0 +1,146 @@ +#ifndef LIFE_SRC_WORLD_H_ +#define LIFE_SRC_WORLD_H_ + +#include <array> +#include <stack> +#include <tuple> +#include <cstdint> + +#include <termbox.h> + +namespace life { + +template< + std::size_t WIDTH, + std::size_t HEIGHT +> +class World { + public: + World() { + for ( std::size_t j = 0; j < HEIGHT; j++ ) { + for ( std::size_t i = 0; i < WIDTH; i++ ) { + this->matrix_[j][i] = false; + } + } + } + + void summonLifeAt(std::size_t x, std::size_t y) { + this->matrix_[y][x] = true; + } + + void extinguishLifeAt(std::size_t x, std::size_t y) { + this->matrix_[y][x] = false; + } + + bool isLifeAt(std::ptrdiff_t x, std::ptrdiff_t y) { + if ( x >= 0 && + x < WIDTH && + y >= 0 && + y < HEIGHT ) { + return this->matrix_[y][x]; + } else { + return false; // end of world is dead + } + } + + std::uint8_t lifeDensityAt(std::size_t x, std::size_t y) { + std::uint8_t counter = 0; + + if ( this->isLifeAt(x - 1, y) ) { + counter++; + } + if ( this->isLifeAt(x + 1, y) ) { + counter++; + } + if ( this->isLifeAt(x, y - 1) ) { + counter++; + } + if ( this->isLifeAt(x, y + 1) ) { + counter++; + } + if ( this->isLifeAt(x - 1, y + 1) ) { + counter++; + } + if ( this->isLifeAt(x - 1, y - 1) ) { + counter++; + } + if ( this->isLifeAt(x + 1, y + 1) ) { + counter++; + } + if ( this->isLifeAt(x + 1, y - 1) ) { + counter++; + } + + return counter; + } + + void tick() { + this->age_++; + + std::stack<std::tuple<std::size_t, std::size_t, bool>> updates; + + for ( std::size_t j = 0; j < HEIGHT; j++ ) { + for ( std::size_t i = 0; i < WIDTH; i++ ) { + const std::uint8_t d = this->lifeDensityAt(i, j); + + if ( this->matrix_[j][i] ) { + if ( d < 2 ) { + updates.push(std::make_tuple(i, j, false)); + } else if ( d == 2 || d == 3 ) { + updates.push(std::make_tuple(i, j, true)); + } else if ( d > 3 ) { + updates.push(std::make_tuple(i, j, false)); + } + } else { + if ( d == 3 ) { + updates.push(std::make_tuple(i, j, true)); + } + } + } + } + + while ( !updates.empty() ) { + const auto& update = updates.top(); + + if ( std::get<2>(update) ) { + this->summonLifeAt( + std::get<0>(update), + std::get<1>(update) + ); + } else { + this->extinguishLifeAt( + std::get<0>(update), + std::get<1>(update) + ); + } + + updates.pop(); + } + } + + void draw() { + tb_clear(); + + for ( std::size_t j = 0; j < HEIGHT; j++ ) { + for ( std::size_t i = 0; i < WIDTH; i++ ) { + if ( this->matrix_[j][i] ) { + tb_change_cell(i, j, 0x2588, TB_BLACK, TB_GREEN); + } else { + tb_change_cell(i, j, 0x2591, TB_BLACK, TB_BLUE); + } + } + } + + tb_present(); + } + + private: + std::size_t age_ = 0; + + std::array<std::array<bool, WIDTH>, HEIGHT> matrix_; + +}; + +} + +#endif // LIFE_SRC_WORLD_H_ |