-
Notifications
You must be signed in to change notification settings - Fork 4
/
game_handler.h
246 lines (195 loc) · 5.34 KB
/
game_handler.h
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
//
// game_handler.h
// GameOfLive
//
// Created by Кирилл on 10.10.17.
// Copyright © 2017 Кирилл. All rights reserved.
//
#ifndef GAME_HANDLER_H
#define GAME_HANDLER_H
#include <cstdint>
#include <map>
#include <ostream>
#include <string>
#include "game_field.h"
class InputResult {
public:
/**
* Event is thrown by timeout.
*/
InputResult() : timedout(true) {}
/**
* Event is thrown by mouse click.
*/
InputResult(size_t posX, size_t posY)
: timedout(false), keyboard(false), posX(posX), posY(posY) {}
/**
* Event is thrown by key pressed.
*/
InputResult(int key) : timedout(false), keyboard(true), key(key) {}
int getKey() const { return isKeyboard() ? key : 0; }
size_t getPosX() const { return isKeyboard() ? 0 : posX; }
size_t getPosY() const { return isKeyboard() ? 0 : posY; }
bool isTimedOut() const { return timedout; }
bool isKeyboard() const { return keyboard && !timedout; }
InputResult& operator=(const InputResult& copy) {
if (© != this) {
posX = copy.posX;
posY = copy.posY;
keyboard = copy.keyboard;
timedout = copy.timedout;
key = copy.key;
}
return (*this);
}
private:
// Mouse click position
size_t posX, posY;
// If this is keyboard event
bool keyboard;
// If this is timeout event
bool timedout;
// Key code
int key;
};
class ViewHandler {
public:
/**
* Draws field and prompts.
*/
virtual void updateField(const GameField& field, size_t stepsCount) = 0;
/**
* Draws keyboard cursor on field.
*/
virtual void updateKeyboardCursor(size_t posX, size_t posY) = 0;
/**
* Draws output from commands.
*/
virtual void updateCommandLine(const std::string& commandOutput) = 0;
/**
* Reads command input from user.
*
* @return User input.
*/
virtual std::string readCommandInput() = 0;
/**
* Waits for the key press/mouse click/timeout expiration.
*
* @param timeout Input timeout in tenths of a second. From 0 to 255.
*
* @return Wait result.
*/
virtual const InputResult waitForInput(uint8_t timeout) = 0;
/**
* Checks whether it is possible to create a field with the given dimensions
* on this terminal.
*/
virtual bool canCrateFieldWithSizes(size_t width, size_t height) = 0;
};
class GameManager {
public:
GameManager(size_t width, size_t height, ViewHandler& viewHandler);
GameManager(const GameField& field, ViewHandler& viewHandler)
: width(field.getWidth()),
height(field.getHeight()),
gameField(field),
previousStep(GameField(0, 0)),
viewHandler(viewHandler) {}
int runGame();
void nextStep();
/**
* If life existed at that position, it dies.
* If there was no life, it borns.
*/
bool setCellAt(int posX, int posY);
/**
* Clears the field, resets the steps counter and creates a field with new
* dimensions.
*/
void reset(size_t width, size_t height);
/**
* Sets new field and resets the steps counter.
*/
void reset(const GameField& field);
void infiniteSteps();
/**
* Cancels last step.
* You can cancel only one step.
*
* @return true, if step succesfully cancelled.
*/
bool stepBack();
/**
* Registers the function of the command handler.
* @param name Command name.
* @param cmd Command handler.
*/
void registerCommand(const std::string& name,
void (*cmd)(const std::vector<std::string>&,
GameManager&,
std::ostream&));
/**
* Checks whether it is possible to create a field with the given dimensions
* on this terminal.
*/
bool canCreateFieldWithSizes(size_t fieldWidth, size_t fieldHeight) const;
const GameField getCurrentField() const;
size_t getWidth() const;
size_t getHeight() const;
ViewHandler& getViewHandler();
private:
size_t width;
size_t height;
std::map<
std::string,
void (*)(const std::vector<std::string>&, GameManager&, std::ostream&)>
commands;
GameField gameField;
GameField previousStep;
ViewHandler& viewHandler;
size_t stepsCounter = 0;
bool hasUndo = false; // Is it possible to cancel at this step
// Keyboard cursor on field position
size_t cursorX = 0;
size_t cursorY = 0;
/**
* Counts the number of living cells around this cell.
*
* @return Number of living cells around
*/
size_t countLifeAround(int posX, int posY) const;
/**
* Forces the update view handler without making any changes to the state of
* the field.
*/
void update();
/**
* Activates the command mode and waits for one command to be entered.
* After the execution of the command goes into normal mode.
*/
void executionInCommandMode();
/**
* Execute command by name.
* @param name Command name.
* @param args Command arguments.
*
* @return true, if command successfully executed.
*/
bool executeCommand(const std::string& name,
const std::vector<std::string>& args,
std::ostream& output);
/**
* Catch mouse clicks.
*/
void onMousePressed(int x, int y);
/**
* Catch key presses.
*/
void onKeyPressed(int key);
/**
* Manages the cursor to set the cells on the field using the arrows on the
* keyboard.
*/
void onKeyboardCursor(int key);
};
#endif /* GAME_HANDLER_H */