-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathWorldBoard.cpp
317 lines (273 loc) · 12.2 KB
/
WorldBoard.cpp
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
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
#pragma once
#include "WorldBoard.h"
#include <iostream>
#include <random>
#include "Directions.h"
#include "UniformRandom.h"
#include "DocoFactory.h"
// --- Initialize Directions for the World
Directions dirs = Directions();
// --- Initialize Random Number Generator
UniformRandom* uniRand = UniformRandom::getInstance();
// ========= WORLD BOARD CONSTRUCTOR / DESTRUCTOR ==============================
WorldBoard::WorldBoard()
{
char inFile[] = "DOCOData02.xml";
this->readFile(inFile);
}
WorldBoard::WorldBoard(char* inFile)
{
this->readFile(inFile);
}
WorldBoard::~WorldBoard()
{
}
// ========= FILE READ with PARSER =============================================
void WorldBoard::readFile(char* inFile)
{
// --- Create the Parser Object
this->myParser = DataParser::getInstance(inFile);
// --- Parse World Size
this->width = this->myParser->getDOCOWorldWidth();
this->height = this->myParser->getDOCOWorldHeight();
// --- Create the CellGrid given World Size
this->worldCellGrid = new CellGrid(width, height);
// --- Initialize the Char Matrix
this->worldCellGrid->initCharMatrix(this->width, this->height);
// --- Get number of DOCOs to Spawn from Parser
int doco_count = this->myParser->getDOCOCount();
std::cout << "\n\nDOCO Count: " << doco_count << "\n";
// --- Get Obstacle count from Parser
int obstacle_count = this->myParser->getObstacleCount();
std::cout << "\n\nObstacle Count: " << doco_count << "\n";
// --- Parser Paremeters
char* ptr_direction = new char;
char* ptr_strategy = new char; //Doco movement strategy
int* ptr_x_pos = new int;
int* ptr_y_pos = new int;
// --- Parse all DOCO information in provided file and create DOCOs from it
// --- Create the factory
DocoFactory* myDocoFactory = DocoFactory::getInstance();
while (this->myParser->getDOCOData(ptr_strategy, ptr_x_pos, ptr_y_pos)) //PA2 No Direction Given
{
std::pair<std::string, std::pair<int, int> > dir_pair;
std::string dir;
// --- Spawn DOCOs at provided X, Y positions with provided movement strategy and direction if avaiable,
// --- otherwise they are given random movement stategy and direction.
// --- Cases for each posible movement being passed in. None of these will activate for PA-1
// Uses first char of strategy
switch (ptr_strategy[0]) {
case 'H':
dir_pair = dirs.getRandomHorizontalDirectionPair();
dir = dir_pair.first;
this->doco_vect.push_back(*myDocoFactory->createDocoHorizontal(*ptr_x_pos, *ptr_y_pos, dir));
this->worldCellGrid->cell_matrix[*ptr_y_pos][*ptr_x_pos].setStrategy("Horizontal");
break;
case 'V':
dir_pair = dirs.getRandomVerticalDirectionPair();
dir = dir_pair.first;
this->doco_vect.push_back(*myDocoFactory->createDocoVertical(*ptr_x_pos, *ptr_y_pos, dir));
this->worldCellGrid->cell_matrix[*ptr_y_pos][*ptr_x_pos].setStrategy("Vertical");
break;
case 'D':
dir_pair = dirs.getRandomDiagonalDirectionPair();
dir = dir_pair.first;
this->doco_vect.push_back(*myDocoFactory->createDocoDiagonal(*ptr_x_pos, *ptr_y_pos, dir));
this->worldCellGrid->cell_matrix[*ptr_y_pos][*ptr_x_pos].setStrategy("Diagonal");
break;
case 'P':
dir_pair = dirs.getRandomPerpDirectionPair();
dir = dir_pair.first;
this->doco_vect.push_back(*myDocoFactory->createDocoPerp(*ptr_x_pos, *ptr_y_pos, dir));
this->worldCellGrid->cell_matrix[*ptr_y_pos][*ptr_x_pos].setStrategy("Perp");
break;
case 'R':
dir_pair = dirs.getRandomDirectionPair();
dir = dir_pair.first;
this->doco_vect.push_back(*myDocoFactory->createDocoDefault(*ptr_x_pos, *ptr_y_pos, dir));
this->worldCellGrid->cell_matrix[*ptr_y_pos][*ptr_x_pos].setStrategy("Random");
break;
default:
// --- Generate a random direction. Provides pair like so: ("N", (0,1))
// strcpy(ptr_strategy,'r');
dir_pair = dirs.getRandomDirectionPair();
dir = dir_pair.first;
this->doco_vect.push_back(*myDocoFactory->createDocoDefault(*ptr_x_pos, *ptr_y_pos, dir));
this->worldCellGrid->cell_matrix[*ptr_y_pos][*ptr_x_pos].setStrategy("Random");
}
// --- Set Matrix to occupied in this xy pos
WorldBoard::updateCellWithADoco(*ptr_x_pos, *ptr_y_pos); // set the cell for doco
}
// --- Parser Memory Management
this->doco_vect.shrink_to_fit();
std::cout << "\n\nDOCO's created: " << this->doco_vect.size() << "\n";
// --- Spawn Obstacles
int* ptr_xpos = new int;
int* ptr_ypos = new int;
std::pair<int, int> pos_pair;
while (this->myParser->getObstacleData(ptr_xpos, ptr_ypos))
{
pos_pair = std::make_pair(*ptr_xpos, *ptr_ypos);
this->obstacle_positions.push_back(pos_pair);
this->setCellWithObstacle(*ptr_xpos, *ptr_ypos);
}
this->obstacle_positions.shrink_to_fit();
std::cout << "\n\nObstacles created: " << this->obstacle_positions.size() << "\n";
// --- Create the Initial Food Locations, Given starting Food_Count
int food_count = this->myParser->getFoodCount();
this->generateFoodLocations(this->width, this->height, food_count);
// --- Update the choosen new food cells with the food and change symbol for that cell position.
this->updateCellsWithNewFood();
}
// ========= FOOD SPAWNER ======================================================
void WorldBoard::generateFoodLocations(int w, int h, int foodCount)
{
// generate spawn locations
int x_pos = 0;
int y_pos = 0;
for (int i = 0; i < foodCount; ++i)
{
x_pos = uniRand->generateRandomNum(0, w-1);
y_pos = uniRand->generateRandomNum(0, h-1);
while ((this->worldCellGrid->cell_matrix[y_pos][x_pos].getFoodCount() > 3) // Food count > 3, generate new x and y position.
|| (this->worldCellGrid->cell_matrix[y_pos][x_pos].getObstacle()) // Don't spawn food in obstacles cells
|| (this->worldCellGrid->cell_matrix[y_pos][x_pos].getOccupied()) ) // Don't spawn food in occupied cells
{
x_pos = uniRand->generateRandomNum(0, w-1);
y_pos = uniRand->generateRandomNum(0, h-1);
}
auto location = std::make_pair(x_pos, y_pos);
this->food_positions.push_back(location);
}
this->food_positions.shrink_to_fit();
}
void WorldBoard::setCellWithNewFood(int x, int y)
{
this->worldCellGrid->cell_matrix[y][x].addFood(1);
this->worldCellGrid->cell_matrix[y][x].setFoodPresent();
this->worldCellGrid->cell_matrix[y][x].setSymbol();
}
void WorldBoard::updateCellsWithNewFood()
{
for (auto food : this->food_positions) {
this->setCellWithNewFood(food.first, food.second);
}
food_positions.clear(); // all new food positions have been processed.
}
// ========= OBSTACLES ======================================================
void WorldBoard::setCellWithObstacle(int x, int y)
{
this->worldCellGrid->cell_matrix[y][x].setObsPresent();
this->worldCellGrid->cell_matrix[y][x].setSymbol();
}
// ========= DOCO ACTIONs ======================================================
int WorldBoard::setCellWithNoFood(int x, int y)
{
int count = this->worldCellGrid->cell_matrix[y][x].getFoodCount();
this->worldCellGrid->cell_matrix[y][x].removeAllFood();
return count;
}
// Helper Function for updateDocos - Makes a Cell on the grid have a DOCO Present
int WorldBoard::updateCellWithADoco(int x, int y)
{
this->worldCellGrid->cell_matrix[y][x].setOccupied(true);
int food_count = this->setCellWithNoFood(x, y);
this->worldCellGrid->cell_matrix[y][x].setFoodPresent();
this->worldCellGrid->cell_matrix[y][x].setSymbol();
return food_count;
}
void WorldBoard::updateDocos(void)
{
// --- Remove dead DOCOs from the list
auto size = this->doco_vect.size();
while (size > 0) // Go through doco_vect, delete item if it's dead
{
if (!this->doco_vect[size-1].getAlive()) {
this->worldCellGrid->cell_matrix[this->doco_vect[size-1].getYPos()][this->doco_vect[size-1].getXPos()].setOccupied(false);
this->worldCellGrid->cell_matrix[this->doco_vect[size-1].getYPos()][this->doco_vect[size-1].getXPos()].setSymbol();
this->doco_vect.erase(this->doco_vect.begin() + size - 1);
}
size -= 1;
}
// --- Split Docos if (energy_level > 750)
int i = 0;
int currentEnergy = 0;
int newEnergy = 0;
for (i = 0; i < int(this->doco_vect.size()); ++i) // Go through doco_vect, split them if high energy
{
// --- When energy too high, split doco into 2 on cell and head in opposite dirs.
if ((currentEnergy = this->doco_vect[i].getEnergy()) > 750) {
// --- Split original's energy
newEnergy = int(currentEnergy / 2);
this->doco_vect[i].setEnergy(newEnergy);
// --- Save direction of original.
auto oldDir = this->doco_vect[i].getDirection();
this->doco_vect[i].setAlive(true);
// --- Copy Constructor
// Doco docoCopy = this->doco_vect[i];
auto* docoCopy = new Doco(this->doco_vect[i]);
// --- Reverse direction of the new Doco
auto oppositeDir = dirs.getOppositeDirectionPair(oldDir);
docoCopy->setDirection(oppositeDir.first);
docoCopy->setAlive(true);
// --- Push back the copy
doco_vect.push_back(*docoCopy);
}
}
// --- Vars for the upcoming DOCO update loop
int food_eaten;
int x = 0;
int y = 0;
// --- Update the current cells with DOCO actions that were decided the previous turn / round.
for (i = 0; i < int(this->doco_vect.size()); i++)
{
// --- Current X any Y Pos
x = this->doco_vect[i].getXPos();
y = this->doco_vect[i].getYPos();
// ------------------
// --- Tell the DOCO what it's surrounding are, so it knows its options.
this->doco_vect[i].adjoined_cells = this->worldCellGrid->findAdjoinedCells(x, y); //Non Border Cells
this->doco_vect[i].adjoined_occupied_cells = this->worldCellGrid->findAdjoinedOccupiedCells();
this->doco_vect[i].adjoined_obstacle_cells = this->worldCellGrid->findAdjoinedObstacleCells();
this->doco_vect[i].adjoined_open_cells = this->worldCellGrid->findAdjoinedOpenCells();
this->doco_vect[i].adjoined_food_cells = this->worldCellGrid->findAdjoinedCellsFood();
this->doco_vect[i].adjoined_open_cells_with_food = this->worldCellGrid->findAdjoinedOpenCellsWithFood();
// --- Find NEW Cell to move to from available options. Chooses desirable X_Y position and assingns the DOCO with that new X_Y position
auto moved_to = this->doco_vect[i].move(this->width, this->height); // all doco's in list make new move decision one at a time
// ------------------
// --- Update it's previous cell with data on being non-occupied now.
this->worldCellGrid->cell_matrix[y][x].setOccupied(false);
this->worldCellGrid->cell_matrix[y][x].setFoodPresent();
this->worldCellGrid->cell_matrix[y][x].setSymbol();
// --- Update cell properties of new cell DOCO is at
// --- Eat Food for Current Cell. Gain Energy.
food_eaten = this->updateCellWithADoco(this->doco_vect[i].getXPos(), this->doco_vect[i].getYPos());
this->doco_vect[i].eat(food_eaten, "default");
this->worldCellGrid->cell_matrix[this->doco_vect[i].getYPos()][this->doco_vect[i].getXPos()].setOccupied(true); // set the cell as populated
this->worldCellGrid->cell_matrix[this->doco_vect[i].getYPos()][this->doco_vect[i].getXPos()].setStrategy(this->worldCellGrid->cell_matrix[y][x].getStrategy()); //set strategy from previous cell
this->worldCellGrid->cell_matrix[this->doco_vect[i].getYPos()][this->doco_vect[i].getXPos()].setFoodPresent();
this->worldCellGrid->cell_matrix[this->doco_vect[i].getYPos()][this->doco_vect[i].getXPos()].setSymbol();
}
}
// --- Perform a SINGLE update of the WorldBoard
void WorldBoard::updateWorldState()
{
// --- Reinitialize the Char Matrix each turn.
this->worldCellGrid->initCharMatrix(this->width, this->height);
// --- Find new positions to place food on the board that are not already at max capacity
this->generateFoodLocations(this->width, this->height, uniRand->generateRandomNum(1, 10));
// --- Update the choosen new food cells with the food and change symbol for that cell position.
this->updateCellsWithNewFood();
// --- Update every DOCO on the board.
this->updateDocos();
// --- Run through the character status of each cell and set the matrix for it.
this->worldCellGrid->setCharMatrix();
}
void WorldBoard::printWorld()
{
this->worldCellGrid->printCharMatrix();
std::cout << "DOCOs on Board: " << this->worldCellGrid->getDocoCharCount() << "\n";
std::cout << "DOCOs Actually Present: " << this->doco_vect.size() << "\n";
std::cout << "Unique Food Spots: " << this->worldCellGrid->getFoodCharCount() << "\n";
std::cout << "Obstacles on Board: " << this->worldCellGrid->getObstacleCount() << "\n";
}