-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathAddTileCommand.cpp
More file actions
288 lines (251 loc) · 9.45 KB
/
Copy pathAddTileCommand.cpp
File metadata and controls
288 lines (251 loc) · 9.45 KB
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
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
//------------------------------------------------------------------------------
// AddTileCommand.cpp
//
// Group: Group 11591, study assistant Thomas Neff
//
// Authors: Benjamin Franz Herbert Rauch
// Peter Lorenz
// Rene Hasenburger
//------------------------------------------------------------------------------
//
#include "AddTileCommand.h"
#include "Position.h"
#include "Game.h"
#include "Tile.h"
#include "Exceptions.h"
#include "iostream"
//------------------------------------------------------------------------------
// Compares two colors and returns the to integer converted value it if they are
// equal, otherwise it's 0
// @param col1 color 1 to be compared
// @param col2 color 2 to be compared
// @return Integer 0 if not equal, otherwise the converted value.
int compCol(Color col1, Color col2)
{
if (col1 == col2)
return static_cast<int>(col1);
return 0;
}
//------------------------------------------------------------------------------
unsigned int AddTileCommand::getParamCnt()
{
return 2;
}
//------------------------------------------------------------------------------
int AddTileCommand::execute(Game &board, std::vector<std::string> ¶ms)
{
Position pos;
//check number of parameters and (if available) evaluate first parameter
if (params.size() != 2 || !pos.parse(params.at(0)))
{
throw TraxException(TraxException::INVALID_PARAMS);
}
//preserve old data in case of screw up
std::vector<std::vector<Tile *> > game_board = board.getBoard();
std::pair<Position, Position> min_max_save(
Position(board.getMinX(), board.getMinY()),
Position(board.getMaxX(), board.getMaxY()));
std::vector<Position> buffer;
buffer.push_back(pos);
//evaluate second parameter
Tile::Type tile_type;
std::string tile_type_str = params.at(1);
if (tile_type_str == "+")
tile_type = Tile::TYPE_CROSS;
else if (tile_type_str == "/")
tile_type = Tile::TYPE_CURVE_1;
else if (tile_type_str == "\\")
tile_type = Tile::TYPE_CURVE_2;
else
{
throw TraxException(TraxException::INVALID_PARAMS);
}
bool first_tile = board.getStartTile() == nullptr;
//first tile must be at (0,0)
if (first_tile && (pos.getX() != 0 || pos.getY() != 0))
{
throw TraxException(TraxException::POSITION_MUST_BE_ZERO);
}
//check if space is taken
if (board.getTileAtPosition(pos) != nullptr)
{
throw TraxException(TraxException::FIELD_NOT_FREE);
}
Tile *tile_pointer;
//handle first tile because further calculations are not related to it
if (first_tile)
{
tile_pointer = new Tile(tile_type, Color::COLOR_RED);
board.setStartTile(tile_pointer);
board.setTileAtPosition(pos, tile_pointer);
board.togglePlayer();
return 1;
}
//get neighboring tiles
Tile *above = board.getTileAtPosition(pos.getX(), pos.getY() - 1);
Tile *right = board.getTileAtPosition(pos.getX() + 1, pos.getY());
Tile *below = board.getTileAtPosition(pos.getX(), pos.getY() + 1);
Tile *left = board.getTileAtPosition(pos.getX() - 1, pos.getY());
//if there are none, error
if (above == nullptr && right == nullptr &&
below == nullptr && left == nullptr)
{
throw TraxException(TraxException::FIELD_NOT_CONNECTED);
}
//get the colors that point to the tile to place
Tile::ColorsOnTile colors_for_tile;
if (above != nullptr)
colors_for_tile.setTop(above->getColors().getBottom());
if (right != nullptr)
colors_for_tile.setRight(right->getColors().getLeft());
if (below != nullptr)
colors_for_tile.setBottom(below->getColors().getTop());
if (left != nullptr)
colors_for_tile.setLeft(left->getColors().getRight());
//calculate top color
int top_color_integer;
switch (tile_type)
{
case Tile::TYPE_CROSS:
top_color_integer = colors_for_tile.getTop() |
Game::getInvertedColor(colors_for_tile.getRight()) |
colors_for_tile.getBottom() |
Game::getInvertedColor(colors_for_tile.getLeft());
break;
case Tile::TYPE_CURVE_1:
top_color_integer = colors_for_tile.getTop() |
Game::getInvertedColor(colors_for_tile.getRight()) |
Game::getInvertedColor(colors_for_tile.getBottom()) |
colors_for_tile.getLeft();
break;
case Tile::TYPE_CURVE_2:
top_color_integer = colors_for_tile.getTop() |
colors_for_tile.getRight() |
Game::getInvertedColor(colors_for_tile.getBottom()) |
Game::getInvertedColor(colors_for_tile.getLeft());
break;
}
//if top color is red AND white...
if (top_color_integer == COLOR_MISMATCH)
{
throw TraxException(TraxException::CONNECTED_LINES_MISMATCH);
}
//should't happen at this point but if no top color found...
else if (top_color_integer == COLOR_NOT_DEFINED)
{
throw TraxException(TraxException::FIELD_NOT_CONNECTED);
}
tile_pointer = new Tile(tile_type, static_cast<Color>(top_color_integer));
board.setTileAtPosition(pos, tile_pointer);
try
{
int pt = 1; //placed tiles
pt += checkAdditionalTiles(board, pos.getX(), pos.getY() - 1, buffer);
pt += checkAdditionalTiles(board, pos.getX() + 1, pos.getY(), buffer);
pt += checkAdditionalTiles(board, pos.getX(), pos.getY() + 1, buffer);
pt += checkAdditionalTiles(board, pos.getX() - 1, pos.getY(), buffer);
for (Position &pos_buffered : buffer)
{
if (board.checkForWin(pos_buffered))
break;
}
board.checkForDraw();
board.togglePlayer();
return pt;
}
catch (TraxException &ex)
{
//run out of tiles or mismatch.
if (ex.getErrorType() == TraxException::NOT_ENOUGH_TILES_LEFT ||
ex.getErrorType() == TraxException::CONNECTED_LINES_MISMATCH)
{
//reset board.
for (Position &pos : buffer)
delete board.getTileAtPosition(pos);
board.overwriteBoard(game_board);
board.forceMinMax(min_max_save.first, min_max_save.second);
}
//pass exception on
throw ex;
}
}
//------------------------------------------------------------------------------
int AddTileCommand::checkAdditionalTiles(Game &board, int x, int y,
std::vector<Position> &buffer)
{
//field to check already taken.
if (board.getTileAtPosition(x, y) != nullptr)
return 0;
//get neighboring tiles
Tile *above = board.getTileAtPosition(x, y - 1);
Tile *right = board.getTileAtPosition(x + 1, y);
Tile *below = board.getTileAtPosition(x, y + 1);
Tile *left = board.getTileAtPosition(x - 1, y);
//get the colors that point to the tile to place
Tile::ColorsOnTile col_for_t;
if (above != nullptr)
col_for_t.setTop(above->getColors().getBottom());
if (right != nullptr)
col_for_t.setRight(right->getColors().getLeft());
if (below != nullptr)
col_for_t.setBottom(below->getColors().getTop());
if (left != nullptr)
col_for_t.setLeft(left->getColors().getRight());
int combined;
//if top and bottom are the same = cross
if ((combined = compCol(col_for_t.getTop(), col_for_t.getBottom())))
board.setTileAtPosition(Position(x, y),
new Tile(Tile::TYPE_CROSS, static_cast<Color>(combined)));
//if top and bottom are the same = cross (but result color inverted)
else if ((combined = compCol(col_for_t.getRight(), col_for_t.getLeft())))
board.setTileAtPosition(Position(x, y),
new Tile(Tile::TYPE_CROSS, static_cast<Color>(combined ^ 3)));
//if top and left are the same = curve_1
else if ((combined = compCol(col_for_t.getTop(), col_for_t.getLeft())))
board.setTileAtPosition(Position(x, y),
new Tile(Tile::TYPE_CURVE_1, static_cast<Color>(combined)));
//if right and bottom are the same = curve_1 (but result color inverted)
else if ((combined = compCol(col_for_t.getRight(), col_for_t.getBottom())))
board.setTileAtPosition(Position(x, y),
new Tile(Tile::TYPE_CURVE_1, static_cast<Color>(combined ^ 3)));
//if top and right are the same = curve_2
else if ((combined = compCol(col_for_t.getTop(), col_for_t.getRight())))
board.setTileAtPosition(Position(x, y),
new Tile(Tile::TYPE_CURVE_2, static_cast<Color>(combined)));
//if left and bottom are the same = curve_2 (but result color inverted)
else if ((combined = compCol(col_for_t.getLeft(), col_for_t.getBottom())))
board.setTileAtPosition(Position(x, y),
new Tile(Tile::TYPE_CURVE_2, static_cast<Color>(combined ^ 3)));
//not clearly defined
else
return 0;
//col_for_t = color of the paths that are leading to the tile
//col_for_s = color of the paths of the tile itself.
Tile::ColorsOnTile col_for_s = board.getTileAtPosition(x, y)->getColors();
if (col_for_s.getTop() + col_for_t.getTop() == COLOR_MISMATCH ||
col_for_s.getLeft() + col_for_t.getLeft() == COLOR_MISMATCH ||
col_for_s.getRight() + col_for_t.getRight() == COLOR_MISMATCH ||
col_for_s.getBottom() + col_for_t.getBottom() == COLOR_MISMATCH)
{
throw TraxException(TraxException::CONNECTED_LINES_MISMATCH);
}
if (board.getRemainingTiles() < 0)
{
throw TraxException(TraxException::NOT_ENOUGH_TILES_LEFT);
}
//one tile added, now check neighbor again
int placed_tiles = 1;
placed_tiles += checkAdditionalTiles(board, x, y - 1, buffer);
placed_tiles += checkAdditionalTiles(board, x + 1, y, buffer);
placed_tiles += checkAdditionalTiles(board, x, y + 1, buffer);
placed_tiles += checkAdditionalTiles(board, x - 1, y, buffer);
return placed_tiles;
}
//------------------------------------------------------------------------------
AddTileCommand::AddTileCommand() : Command("addtile")
{
}
//------------------------------------------------------------------------------
AddTileCommand::~AddTileCommand()
{
}