-
Notifications
You must be signed in to change notification settings - Fork 0
/
game.h
234 lines (193 loc) · 5.07 KB
/
game.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
//
// Created by alcicer on 5/30/2022.
//
#ifndef TETRIS_GAME_H
#define TETRIS_GAME_H
#include <map>
#include <algorithm>
#include <stdexcept>
#include "blocks.h"
enum class movement_status : unsigned {
MOVEMENT_SUCCESS,
MOVEMENT_FAILED,
ROTATE_SUCCESS,
ROTATE_FAILED
};
enum class merge_status : unsigned {
MERGED,
GAME_OVER
};
enum class command : unsigned {
ROTATE_CLOCKWISE,
ROTATE_COUNTER_CLOCKWISE,
MOVE_LEFT,
MOVE_RIGHT,
MOVE_DOWN
};
class board {
public:
/**
*
* @param r number of rows
* @param c number of columns
*/
board(unsigned r, unsigned c) : rows(r), columns(c), m(r, std::vector<int>(c, -1)) {
next = blockQueue.generate_block();
};
movement_status moveDown();
movement_status moveLeft();
movement_status moveRight();
[[nodiscard]] movement_status rotateClockWise() const;
[[nodiscard]] movement_status rotateCounterClockWise() const;
/**
* The board will go one step further, to do this
* it will try to move the current block down one square.
* @return -1 if game over, 0 if block landed, 1 if the block has moved down one square
*/
int doTick();
/**
* initialize the board, sets the blocks
*/
void init();
/**
* clears the rows which all squares filled with minions
* @return cleared row indexes
*/
[[nodiscard]] std::vector<int> clearLines();
[[nodiscard]] const block *getCurrent() const {
return current.get();
}
[[nodiscard]] const block *getNext() const {
return next.get();
}
/**
*
* @param x row index
* @param y column index
* @return -1 if not filled, else filled value which determines also minion type
*/
[[nodiscard]] int getValue(unsigned x, unsigned y) const {
return m[x][y];
}
/**
*
* @return current block`s top x position
*/
[[nodiscard]] int getCurrentPosX() const {
return currentPosX;
};
/**
*
* @return current block`s top y position
*/
[[nodiscard]] int getCurrentPosY() const {
return currentPosY;
};
private:
/**
*
* @param moveX move on X axis
* @param moveY move on Y axis
* @return true if position suitable
*/
[[nodiscard]] bool checkNextPosition(int moveX, int moveY) const;
/**
* try to merge current block with board
* @return MERGED if success, GAME_OVER if not possible
*/
merge_status land();
block_queue blockQueue;
std::unique_ptr<block> current;
bool landed = false;
std::unique_ptr<block> next;
static const int CURRENT_X_DEFAULT = -4;
static const int CURRENT_Y_DEFAULT = 3;
int currentPosX{CURRENT_X_DEFAULT};
int currentPosY{CURRENT_Y_DEFAULT};
const unsigned rows;
const unsigned columns;
/** board matrix rows X columns */
std::vector<std::vector<int>> m;
};
class game {
public:
/**
* create game with default 20X10 and level 0
*/
game() : game(20, 10) {
}
/**
* create game with default 20X10 and starting level
* @param level starting level
*/
explicit game(unsigned level) : game(20, 10, level) {
}
/**
*
* @param r number of rows
* @param c number of columns
*/
game(unsigned r, unsigned c, unsigned level = 0);
/**
*
* @param lvl level
* @return original tetris frame value
*/
[[nodiscard]] unsigned getFrame(unsigned lvl) const;
/**
*
* @param lvl level
* @return number of lines needed for increase the level
*/
[[nodiscard]] unsigned getLvlIncrease(unsigned lvl) const;
/**
* increase +1 stat for block type
* @param bt block type
*/
void increaseStat(block_type bt);
[[nodiscard]] unsigned getStat(block_type bt) const;
[[nodiscard]] unsigned int getScore() const {
return score;
}
[[nodiscard]] unsigned int getLines() const {
return lines;
}
[[nodiscard]] unsigned int getLevel() const {
return level;
}
[[nodiscard]] double getSpeed() const {
return speed;
}
/**
* The game will go one step further, to do this
* it will call doTick for board and calculate level, speed, statistics, etc...
* @return -1 if game over, 0 if block landed, 1 if the block has moved down one square
*/
int doTick(std::vector<int> &lineIndexes);
/**
*
* @param cmd user input
* @return movement status
*/
movement_status processCommand(command cmd);
/**
* start the game
*/
void start();
[[nodiscard]] const board &getBrd() const;
// TODO
// select start level
// maybe wrappers for SDL functions, and native c++ game mechanism
private:
bool started = false;
std::map<unsigned, unsigned> lvl_frames;
unsigned score{0};
std::map<unsigned, unsigned> lvl_increase;
unsigned lines{0};
std::map<block_type, unsigned> statistics;
unsigned level{0};
double gravity = 60.0988;
double speed;
board brd;
};
#endif //TETRIS_GAME_H