aboutsummaryrefslogtreecommitdiff
path: root/src/game/game.hpp
blob: d6e2979b6905640f1520a6e4fe2bf1cb0d693844 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#pragma once

#include <chrono>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <list>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>

#include "engine/data/vector2.hpp"
#include "interfaces/RLE_reader.hpp"
#include "interfaces/cell_helper.hpp"
#include "interfaces/cursor.hpp"
#include "interfaces/game.hpp"
#include "interfaces/generation_tracker.hpp"
#include "interfaces/input.hpp"
#include "interfaces/matrix.hpp"
#include "interfaces/scene.hpp"
#include "interfaces/status_manager.hpp"
#include "interfaces/statusline.hpp"

class ICellHelper;
class IGenerationTracker;
class IRLEReader;
class IStatusManager;
class IUserInputObserver;

template <typename ElementType>
class IMatrix;

constexpr auto DEFAULT_GENERATIONS_PER_SECOND = 5L;

constexpr auto MAXIMUM_GENERATIONS_PER_SECOND = 512L;

constexpr auto MILLIS_IN_SECOND = 1000;

constexpr auto CURSOR_FALLBACK_POS_X = 10;
constexpr auto CURSOR_FALLBACK_POS_Y = 10;

constexpr std::string_view ERASE_ENTIRE_LINE = "{esc}[2K";
constexpr std::string_view ERASE_LINE_FROM_CURSOR = "{esc}[0K";

enum Mode
{
	NORMAL,
	COMMAND
};

class CommandInfo
{
public:
	using Options = const std::vector<std::string> &;
	using CommandFunction = std::function<void(Options)>;

	std::size_t option_cnt;
	CommandFunction function;
};

class Game : public IGame
{
public:
	Game(
		IStatusLineFactory statusline_factory,
		std::shared_ptr<IScene> scene,
		std::shared_ptr<ICursorController> cursor_controller,
		std::shared_ptr<IGenerationTracker> generation_tracker,
		std::shared_ptr<IStatusManager> status_manager,
		std::shared_ptr<IUserInputObserver> user_input_observer,
		std::shared_ptr<ICellHelper> cell_helper,
		std::shared_ptr<IRLEReader> rle_reader) noexcept;

	void on_start() override;

	void on_update() noexcept override;

	void on_exit() const noexcept override;

private:
	IStatusLineFactory _statusline_factory;

	std::shared_ptr<IScene> _scene;
	std::shared_ptr<ICursorController> _cursor_controller;
	std::shared_ptr<IGenerationTracker> _generation_tracker;
	std::shared_ptr<IStatusManager> _status_manager;
	std::shared_ptr<IUserInputObserver> _user_input_observer;
	std::shared_ptr<ICellHelper> _cell_helper;
	std::shared_ptr<IRLEReader> _rle_reader;

	Mode _current_mode;

	CursorStyle _normal_mode_cursor_style;
	CursorStyle _command_mode_cursor_style;

	std::int32_t _minimum_cursor_pos_y;

	std::optional<Vector2> _last_pos_before_command_mode;

	std::string _command_mode_input;

	std::unordered_map<std::string, CommandInfo> _commands;

	std::chrono::system_clock::time_point _last_gen_update_time;

	std::int64_t _generations_per_second = DEFAULT_GENERATIONS_PER_SECOND;

	std::vector<Vector2> _living_cell_positions;

	void _on_normal_mode_update() noexcept;

	void _on_command_mode_update() noexcept;

	void _return_to_normal_mode() noexcept;

	void _run_command(const std::string &command) noexcept;

	void _show_command_error(const std::string_view &error_message) noexcept;

	auto _move_cursor(const Vector2 &direction) noexcept -> bool;

	void _set_space(
		const std::shared_ptr<IMatrix<IScene::MatrixElement>> &matrix,
		const Vector2 &position,
		char character) noexcept;

	static void _erase_entire_line() noexcept;

	static void _erase_line_from_cursor() noexcept;

	void _process_next_generation() noexcept;

	void _open_rle_file(CommandInfo::Options options) noexcept;
};