diff options
| -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_  | 
