@jutge.org/toolkit 4.2.24 → 4.2.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,107 +2,117 @@
|
|
|
2
2
|
|
|
3
3
|
#include "Board.hh"
|
|
4
4
|
#include "Action.hh"
|
|
5
|
-
|
|
6
5
|
|
|
7
|
-
Board::Board
|
|
6
|
+
Board::Board(istream &is, int seed)
|
|
7
|
+
{
|
|
8
8
|
set_random_seed(seed);
|
|
9
|
-
*static_cast<Settings*>(this) = Settings::read_settings(is);
|
|
9
|
+
*static_cast<Settings *>(this) = Settings::read_settings(is);
|
|
10
10
|
|
|
11
11
|
player2alive_units = vector<set<int>>(num_players());
|
|
12
|
-
player2dead_units
|
|
13
|
-
zombies_
|
|
14
|
-
|
|
15
|
-
names
|
|
16
|
-
scr
|
|
17
|
-
scr_accumulated
|
|
18
|
-
nb_cells
|
|
19
|
-
overall_strength = vector<int>
|
|
20
|
-
|
|
21
|
-
stats
|
|
12
|
+
player2dead_units = vector<set<int>>(num_players());
|
|
13
|
+
zombies_ = set<int>();
|
|
14
|
+
|
|
15
|
+
names = vector<string>(num_players());
|
|
16
|
+
scr = vector<int>(num_players(), 0);
|
|
17
|
+
scr_accumulated = vector<int>(num_players(), 0);
|
|
18
|
+
nb_cells = vector<int>(num_players(), 0); // Is computed in read grid
|
|
19
|
+
overall_strength = vector<int>(num_players(), clan_ini_strength());
|
|
20
|
+
|
|
21
|
+
stats = vector<double>(num_players(), 0);
|
|
22
22
|
|
|
23
23
|
rnd = 0;
|
|
24
24
|
|
|
25
25
|
fresh_id = 0;
|
|
26
26
|
read_generator_and_grid(is);
|
|
27
27
|
|
|
28
|
-
for (auto&
|
|
28
|
+
for (auto &p : units)
|
|
29
|
+
fresh_id = max(fresh_id, p.first);
|
|
29
30
|
++fresh_id;
|
|
30
|
-
|
|
31
|
+
|
|
31
32
|
_my_assert(ok(), "Invariants are not satisfied.");
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
void Board::check_is_good_initial_fixed_board
|
|
35
|
-
|
|
35
|
+
void Board::check_is_good_initial_fixed_board() const
|
|
36
|
+
{
|
|
37
|
+
vector<int> num_units(num_players(), 0);
|
|
36
38
|
int num_zombies = 0;
|
|
37
39
|
int num_food = 0;
|
|
38
40
|
|
|
39
41
|
_my_assert(int(grid.size()) == board_rows(), "Fixed board has wrong number of rows.");
|
|
40
42
|
_my_assert(int(grid[0].size()) == board_cols(), "Fixed board has wrong number of cols.");
|
|
41
|
-
|
|
43
|
+
|
|
42
44
|
for (int i = 0; i < board_rows(); ++i)
|
|
43
|
-
for (int j = 0; j < board_cols(); ++j)
|
|
45
|
+
for (int j = 0; j < board_cols(); ++j)
|
|
46
|
+
{
|
|
44
47
|
Cell c = grid[i][j];
|
|
45
|
-
if (c.food)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
48
|
+
if (c.food)
|
|
49
|
+
++num_food;
|
|
50
|
+
if (c.id != -1)
|
|
51
|
+
{
|
|
52
|
+
int id = c.id;
|
|
53
|
+
_my_assert(units.count(id) != 0, "Unit places in grid does noe appear in units");
|
|
54
|
+
const Unit &u = units.find(id)->second;
|
|
55
|
+
_my_assert(u.type != Dead, "Initial unit already dead");
|
|
56
|
+
if (u.type == Alive)
|
|
57
|
+
{
|
|
58
|
+
_my_assert(player_ok(u.player), "Player not ok in check_is_good_initial_fixed_board");
|
|
59
|
+
_my_assert(c.owner == u.player, "Unit placed in a cell but player does not own it");
|
|
60
|
+
_my_assert(u.pos == Pos(i, j), "Live unit does not have right position");
|
|
61
|
+
_my_assert(player2alive_units[u.player].count(id) != 0, "Live unit not in player2alive_units");
|
|
62
|
+
++num_units[u.player];
|
|
63
|
+
}
|
|
64
|
+
else
|
|
65
|
+
{ // We know it is a zombie
|
|
66
|
+
++num_zombies;
|
|
67
|
+
_my_assert(u.player == -1, "Zombies should have player -1");
|
|
68
|
+
_my_assert(u.pos == Pos(i, j), "Zombie does not have right position");
|
|
69
|
+
_my_assert(zombies_.count(id) != 0, "Live unit not in zombies_");
|
|
70
|
+
}
|
|
64
71
|
}
|
|
65
72
|
}
|
|
66
|
-
|
|
67
|
-
_my_assert(num_food == num_ini_food(),"Fixed board has wrong number of initial food.");
|
|
68
|
-
_my_assert(num_zombies == num_ini_zombies(),"Fixed board has wrong number of initial zombies.");
|
|
73
|
+
|
|
74
|
+
_my_assert(num_food == num_ini_food(), "Fixed board has wrong number of initial food.");
|
|
75
|
+
_my_assert(num_zombies == num_ini_zombies(), "Fixed board has wrong number of initial zombies.");
|
|
69
76
|
for (int p = 0; p < num_players(); ++p)
|
|
70
77
|
_my_assert(int(player2alive_units[p].size()) == num_units[p], "Fixed board has wrong number of initial live units.");
|
|
71
78
|
}
|
|
72
79
|
|
|
73
|
-
void Board::print_settings
|
|
80
|
+
void Board::print_settings(ostream &os) const
|
|
81
|
+
{
|
|
74
82
|
|
|
75
|
-
os <<
|
|
76
|
-
os
|
|
77
|
-
os <<
|
|
78
|
-
os <<
|
|
79
|
-
os <<
|
|
80
|
-
os <<
|
|
81
|
-
os <<
|
|
82
|
-
os <<
|
|
83
|
-
os <<
|
|
84
|
-
os <<
|
|
85
|
-
os <<
|
|
86
|
-
os <<
|
|
87
|
-
os <<
|
|
88
|
-
os <<
|
|
89
|
-
os <<
|
|
83
|
+
os << version() << endl;
|
|
84
|
+
os << endl;
|
|
85
|
+
os << "NUM_PLAYERS" << "\t\t\t" << num_players() << endl;
|
|
86
|
+
os << "NUM_ROUNDS" << "\t\t\t" << num_rounds() << endl;
|
|
87
|
+
os << "BOARD_ROWS" << "\t\t\t" << board_rows() << endl;
|
|
88
|
+
os << "BOARD_COLS" << "\t\t\t" << board_cols() << endl;
|
|
89
|
+
os << "NUM_INI_UNITS_PER_CLAN" << "\t\t" << num_ini_units_per_clan() << endl;
|
|
90
|
+
os << "NUM_INI_ZOMBIES" << "\t\t\t" << num_ini_zombies() << endl;
|
|
91
|
+
os << "NUM_INI_FOOD" << "\t\t\t" << num_ini_food() << endl;
|
|
92
|
+
os << "CLAN_INI_STRENGTH" << "\t\t" << clan_ini_strength() << endl;
|
|
93
|
+
os << "POINTS_FOR_KILLING_PERSON" << "\t" << points_for_killing_person() << endl;
|
|
94
|
+
os << "POINTS_FOR_KILLING_ZOMBIE" << "\t" << points_for_killing_zombie() << endl;
|
|
95
|
+
os << "POINTS_PER_OWNED_CELL" << "\t\t" << points_per_owned_cell() << endl;
|
|
96
|
+
os << "FOOD_STRENGTH" << "\t\t\t" << food_strength() << endl;
|
|
97
|
+
os << "ROUNDS_BEFORE_BECOMING_ZOMBIE" << "\t" << rounds_before_becoming_zombie() << endl;
|
|
90
98
|
}
|
|
91
99
|
|
|
92
|
-
|
|
93
|
-
|
|
100
|
+
void Board::print_names(ostream &os) const
|
|
101
|
+
{
|
|
94
102
|
os << "names ";
|
|
95
|
-
for (int pl = 0; pl < num_players(); ++pl)
|
|
103
|
+
for (int pl = 0; pl < num_players(); ++pl)
|
|
104
|
+
os << ' ' << name(pl);
|
|
96
105
|
os << endl;
|
|
97
106
|
}
|
|
98
107
|
|
|
99
|
-
|
|
100
|
-
|
|
108
|
+
void Board::print_state(ostream &os)
|
|
109
|
+
{
|
|
101
110
|
|
|
102
111
|
// Should start with the same format of Info::read_grid.
|
|
103
112
|
// Then other data describing the state.
|
|
104
113
|
|
|
105
|
-
os << endl
|
|
114
|
+
os << endl
|
|
115
|
+
<< endl;
|
|
106
116
|
|
|
107
117
|
os << " ";
|
|
108
118
|
for (int j = 0; j < board_cols(); ++j)
|
|
@@ -114,24 +124,34 @@ void Board::print_state (ostream& os) {
|
|
|
114
124
|
os << j % 10;
|
|
115
125
|
os << endl;
|
|
116
126
|
|
|
117
|
-
for (int i = 0; i < board_rows(); ++i)
|
|
127
|
+
for (int i = 0; i < board_rows(); ++i)
|
|
128
|
+
{
|
|
118
129
|
os << i / 10 << i % 10 << " ";
|
|
119
|
-
for (int j = 0; j < board_cols(); ++j)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
else if (c.owner ==
|
|
125
|
-
|
|
126
|
-
else
|
|
130
|
+
for (int j = 0; j < board_cols(); ++j)
|
|
131
|
+
{
|
|
132
|
+
const Cell &c = grid[i][j];
|
|
133
|
+
if (c.type == Waste)
|
|
134
|
+
os << 'W';
|
|
135
|
+
else if (c.owner == 0)
|
|
136
|
+
os << '0';
|
|
137
|
+
else if (c.owner == 1)
|
|
138
|
+
os << '1';
|
|
139
|
+
else if (c.owner == 2)
|
|
140
|
+
os << '2';
|
|
141
|
+
else if (c.owner == 3)
|
|
142
|
+
os << '3';
|
|
143
|
+
else
|
|
144
|
+
os << '.';
|
|
127
145
|
}
|
|
128
146
|
os << endl;
|
|
129
147
|
}
|
|
130
148
|
|
|
131
|
-
os << endl
|
|
149
|
+
os << endl
|
|
150
|
+
<< "units" << endl;
|
|
132
151
|
os << units.size() << endl;
|
|
133
152
|
os << "type\tid\tplayer\trow\tcolumn\trounds" << endl;
|
|
134
|
-
for (const auto&
|
|
153
|
+
for (const auto &ci : units)
|
|
154
|
+
{
|
|
135
155
|
os << UnitType2char(ci.second.type) << "\t";
|
|
136
156
|
os << ci.second.id << "\t";
|
|
137
157
|
os << ci.second.player << "\t";
|
|
@@ -140,15 +160,18 @@ void Board::print_state (ostream& os) {
|
|
|
140
160
|
os << ci.second.rounds_for_zombie << endl;
|
|
141
161
|
}
|
|
142
162
|
|
|
143
|
-
os << endl
|
|
163
|
+
os << endl
|
|
164
|
+
<< "food" << endl;
|
|
144
165
|
// Collect them
|
|
145
166
|
vector<Pos> food;
|
|
146
167
|
for (int i = 0; i < board_rows(); ++i)
|
|
147
168
|
for (int j = 0; j < board_cols(); ++j)
|
|
148
|
-
if (grid[i][j].food)
|
|
169
|
+
if (grid[i][j].food)
|
|
170
|
+
food.push_back(Pos(i, j));
|
|
149
171
|
os << food.size() << endl;
|
|
150
172
|
os << "row\tcolumn" << endl;
|
|
151
|
-
for (const auto&
|
|
173
|
+
for (const auto &p : food)
|
|
174
|
+
{
|
|
152
175
|
os << p.i << "\t";
|
|
153
176
|
os << p.j << endl;
|
|
154
177
|
}
|
|
@@ -159,178 +182,210 @@ void Board::print_state (ostream& os) {
|
|
|
159
182
|
os << endl;
|
|
160
183
|
|
|
161
184
|
os << "score";
|
|
162
|
-
for (auto s : scr)
|
|
185
|
+
for (auto s : scr)
|
|
186
|
+
os << "\t" << s;
|
|
163
187
|
os << endl;
|
|
164
188
|
os << endl;
|
|
165
189
|
|
|
166
190
|
os << "scr_acc";
|
|
167
|
-
for (auto s : scr_accumulated)
|
|
191
|
+
for (auto s : scr_accumulated)
|
|
192
|
+
os << "\t" << s;
|
|
168
193
|
os << endl;
|
|
169
194
|
os << endl;
|
|
170
195
|
|
|
171
196
|
os << "strength";
|
|
172
|
-
for (auto s : overall_strength)
|
|
197
|
+
for (auto s : overall_strength)
|
|
198
|
+
os << "\t" << s;
|
|
173
199
|
os << endl;
|
|
174
200
|
os << endl;
|
|
175
201
|
|
|
176
202
|
os << "status";
|
|
177
|
-
for (auto s : stats)
|
|
203
|
+
for (auto s : stats)
|
|
204
|
+
os << "\t" << s;
|
|
178
205
|
os << endl;
|
|
179
206
|
os << endl;
|
|
180
207
|
}
|
|
181
208
|
|
|
182
|
-
|
|
183
|
-
|
|
209
|
+
void Board::print_results() const
|
|
210
|
+
{
|
|
184
211
|
int max_score = 0;
|
|
185
212
|
vector<int> v;
|
|
186
|
-
for (int pl = 0; pl < num_players(); ++pl)
|
|
213
|
+
for (int pl = 0; pl < num_players(); ++pl)
|
|
214
|
+
{
|
|
187
215
|
|
|
188
|
-
cerr << "info: player " <<
|
|
189
|
-
<< " got score "
|
|
216
|
+
cerr << "info: player " << name(pl)
|
|
217
|
+
<< " got score " << score(pl) << endl;
|
|
190
218
|
|
|
191
|
-
if
|
|
192
|
-
|
|
219
|
+
if (score(pl) == max_score)
|
|
220
|
+
v.push_back(pl);
|
|
221
|
+
else if (score(pl) > max_score)
|
|
222
|
+
{
|
|
193
223
|
max_score = score(pl);
|
|
194
224
|
v = vector<int>(1, pl);
|
|
195
225
|
}
|
|
196
226
|
}
|
|
197
227
|
|
|
198
228
|
cerr << "info: player(s)";
|
|
199
|
-
for (int pl : v)
|
|
229
|
+
for (int pl : v)
|
|
230
|
+
cerr << " " << name(pl);
|
|
200
231
|
cerr << " got top score" << endl;
|
|
201
232
|
}
|
|
202
233
|
|
|
203
234
|
// Returns whether c1 wins
|
|
204
|
-
bool Board::first_unit_wins_attack
|
|
235
|
+
bool Board::first_unit_wins_attack(const Unit &u1, const Unit &u2)
|
|
236
|
+
{
|
|
205
237
|
int S = 30; // 30% vegades attack is a surprise and u1 wins
|
|
206
|
-
if (random(0,100) < S)
|
|
238
|
+
if (random(0, 100) < S)
|
|
239
|
+
return true;
|
|
207
240
|
|
|
208
241
|
// Otherwise, it depend on the strength
|
|
209
242
|
int u1_strength = strength(u1.player);
|
|
210
243
|
int u2_strength = strength(u2.player);
|
|
211
244
|
|
|
212
|
-
if (u1_strength + u2_strength == 0)
|
|
245
|
+
if (u1_strength + u2_strength == 0)
|
|
246
|
+
return random(0, 1) == 0; // If both no strength --> 50-50
|
|
213
247
|
int M = 1000;
|
|
214
|
-
int num = random(0,M);
|
|
215
|
-
double threshold = double(u1_strength)/(u1_strength + u2_strength)*M;
|
|
248
|
+
int num = random(0, M);
|
|
249
|
+
double threshold = double(u1_strength) / (u1_strength + u2_strength) * M;
|
|
216
250
|
return num < threshold;
|
|
217
251
|
}
|
|
218
252
|
|
|
219
|
-
void Board::perform_attack
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
Unit&
|
|
253
|
+
void Board::perform_attack(Unit &orig_u, Unit &dest_u, vector<vector<int>> &alive_to_dead)
|
|
254
|
+
{
|
|
255
|
+
bool first_wins = first_unit_wins_attack(orig_u, dest_u);
|
|
256
|
+
Unit &winner = (first_wins ? orig_u : dest_u);
|
|
257
|
+
Unit &loser = (first_wins ? dest_u : orig_u);
|
|
223
258
|
|
|
224
259
|
alive_to_dead[loser.player].push_back(loser.id);
|
|
225
260
|
loser.type = Dead;
|
|
226
261
|
loser.rounds_for_zombie = rounds_before_becoming_zombie();
|
|
227
|
-
scr_accumulated[winner.player] += points_for_killing_person();
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
bool Board::execute (const Command& m,
|
|
231
|
-
vector<int>& food_to_regenerate,
|
|
232
|
-
vector<vector<int>>& zombie_to_unit,
|
|
233
|
-
vector<vector<int>>& alive_to_dead
|
|
234
|
-
) {
|
|
235
|
-
int id = m.id;
|
|
236
|
-
Dir dir = Dir(m.dir);
|
|
237
|
-
CommandType c_type = CommandType(m.c_type);
|
|
262
|
+
scr_accumulated[winner.player] += points_for_killing_person();
|
|
263
|
+
}
|
|
238
264
|
|
|
265
|
+
bool Board::execute(const Command &m,
|
|
266
|
+
vector<int> &food_to_regenerate,
|
|
267
|
+
vector<vector<int>> &zombie_to_unit,
|
|
268
|
+
vector<vector<int>> &alive_to_dead)
|
|
269
|
+
{
|
|
270
|
+
int id = m.id;
|
|
271
|
+
Dir dir = Dir(m.dir);
|
|
272
|
+
CommandType c_type = CommandType(m.c_type);
|
|
239
273
|
|
|
240
|
-
if (not command_type_ok(c_type))
|
|
274
|
+
if (not command_type_ok(c_type))
|
|
275
|
+
{
|
|
241
276
|
cerr << "warning: invalid command type in command: " << c_type << endl;
|
|
242
277
|
return false;
|
|
243
278
|
}
|
|
244
279
|
|
|
245
|
-
if (not dir_ok(dir))
|
|
280
|
+
if (not dir_ok(dir))
|
|
281
|
+
{
|
|
246
282
|
cerr << "warning: invalid dir in command: " << dir << endl;
|
|
247
283
|
return false;
|
|
248
284
|
}
|
|
249
285
|
|
|
250
|
-
Unit&
|
|
251
|
-
UnitType type = un.type;
|
|
252
|
-
int
|
|
253
|
-
Pos
|
|
254
|
-
Cell&
|
|
286
|
+
Unit &un = units[id];
|
|
287
|
+
UnitType type = un.type;
|
|
288
|
+
int pl = un.player;
|
|
289
|
+
Pos op = un.pos;
|
|
290
|
+
Cell &oc = grid[op.i][op.j];
|
|
255
291
|
|
|
256
|
-
if (type == Alive and (dir == DR or dir == RU or dir == UL or dir == LD))
|
|
257
|
-
|
|
258
|
-
|
|
292
|
+
if (type == Alive and (dir == DR or dir == RU or dir == UL or dir == LD))
|
|
293
|
+
return false; // Alive not diagonal
|
|
294
|
+
|
|
295
|
+
if (type == Dead)
|
|
296
|
+
return false; // Unit is dead (maybe has been dead in this round)
|
|
259
297
|
|
|
260
298
|
Pos np = op + dir;
|
|
261
|
-
if (not pos_ok(np))
|
|
299
|
+
if (not pos_ok(np))
|
|
300
|
+
{
|
|
262
301
|
cerr << "warning: cannot move to position " << np << " out of the board." << endl;
|
|
263
302
|
return false;
|
|
264
303
|
}
|
|
265
304
|
|
|
266
|
-
Cell&
|
|
267
|
-
|
|
305
|
+
Cell &nc = grid[np.i][np.j];
|
|
268
306
|
|
|
269
|
-
if (type == Zombie)
|
|
270
|
-
|
|
307
|
+
if (type == Zombie)
|
|
308
|
+
{
|
|
309
|
+
if (nc.type == Waste)
|
|
310
|
+
{
|
|
271
311
|
return false;
|
|
272
312
|
}
|
|
273
|
-
else if (nc.food)
|
|
313
|
+
else if (nc.food)
|
|
314
|
+
{ // Cell with food
|
|
274
315
|
++food_to_regenerate[num_players()]; // last position is for zombies
|
|
275
316
|
nc.food = false;
|
|
276
317
|
nc.owner = -1;
|
|
277
318
|
nc.id = id;
|
|
278
319
|
un.pos = np;
|
|
279
|
-
oc.id = -1;
|
|
320
|
+
oc.id = -1;
|
|
280
321
|
}
|
|
281
|
-
else if (nc.id == -1)
|
|
322
|
+
else if (nc.id == -1)
|
|
323
|
+
{ // Cell with no unit
|
|
282
324
|
nc.owner = -1;
|
|
283
325
|
nc.id = id;
|
|
284
326
|
un.pos = np;
|
|
285
327
|
oc.id = -1;
|
|
286
328
|
}
|
|
287
|
-
else
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
329
|
+
else
|
|
330
|
+
{ // Cell with unit
|
|
331
|
+
Unit &au = units[nc.id]; // attacked unit
|
|
332
|
+
if (au.type == Zombie or au.type == Dead)
|
|
333
|
+
{ // Zombie attacks zombie
|
|
334
|
+
return false;
|
|
291
335
|
}
|
|
292
|
-
else
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
336
|
+
else
|
|
337
|
+
{ // Attack and bite a live unit
|
|
338
|
+
if (au.rounds_for_zombie == -1)
|
|
339
|
+
{
|
|
340
|
+
au.rounds_for_zombie = rounds_before_becoming_zombie() + 1;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
else if (type == Alive)
|
|
346
|
+
{
|
|
347
|
+
if (nc.type == Waste)
|
|
348
|
+
{
|
|
301
349
|
cerr << "warning: cannot move to position " << np << " with waste." << endl;
|
|
302
350
|
return false;
|
|
303
351
|
}
|
|
304
|
-
else if (nc.food)
|
|
352
|
+
else if (nc.food)
|
|
353
|
+
{ // Cell with food
|
|
305
354
|
++food_to_regenerate[pl];
|
|
306
355
|
nc.food = false;
|
|
307
356
|
nc.owner = pl;
|
|
308
357
|
nc.id = id;
|
|
309
358
|
un.pos = np;
|
|
310
|
-
oc.id = -1;
|
|
359
|
+
oc.id = -1;
|
|
311
360
|
}
|
|
312
|
-
else if (nc.id == -1)
|
|
361
|
+
else if (nc.id == -1)
|
|
362
|
+
{ // Cell with no unit
|
|
313
363
|
nc.owner = pl;
|
|
314
364
|
nc.id = id;
|
|
315
365
|
un.pos = np;
|
|
316
366
|
oc.id = -1;
|
|
317
367
|
}
|
|
318
|
-
else
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
368
|
+
else
|
|
369
|
+
{ // Cell with unit
|
|
370
|
+
Unit &au = units[nc.id]; // attacked unit
|
|
371
|
+
if (au.type == Zombie)
|
|
372
|
+
{ // Kill a zombie
|
|
373
|
+
zombie_to_unit[pl].push_back(nc.id); // zombie will be regenerated as unit of this clan
|
|
374
|
+
nc.id = -1; // nobody is in the cell previouly occupied by the zombie
|
|
375
|
+
au.pos = {-1, -1}; // no position (pending to be regenerated)
|
|
376
|
+
scr_accumulated[pl] += points_for_killing_zombie();
|
|
325
377
|
}
|
|
326
|
-
else if (au.type == Dead)
|
|
327
|
-
|
|
378
|
+
else if (au.type == Dead)
|
|
379
|
+
{
|
|
380
|
+
return false;
|
|
328
381
|
}
|
|
329
|
-
else if (au.player == pl)
|
|
330
|
-
|
|
382
|
+
else if (au.player == pl)
|
|
383
|
+
{ // attacks among same clan not allowed
|
|
384
|
+
return false;
|
|
331
385
|
}
|
|
332
|
-
else
|
|
333
|
-
|
|
386
|
+
else
|
|
387
|
+
{ // attacks among different clans
|
|
388
|
+
perform_attack(un, au, alive_to_dead);
|
|
334
389
|
}
|
|
335
390
|
}
|
|
336
391
|
}
|
|
@@ -338,31 +393,40 @@ bool Board::execute (const Command& m,
|
|
|
338
393
|
return true;
|
|
339
394
|
}
|
|
340
395
|
|
|
396
|
+
bool Board::is_good_pos_to_regen(const Pos &p) const
|
|
397
|
+
{
|
|
341
398
|
|
|
342
|
-
|
|
399
|
+
if (not grid[p.i][p.j].is_empty())
|
|
400
|
+
return false;
|
|
343
401
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
if (pos_ok(Pos(i,j)) and grid[i][j].id != -1)
|
|
402
|
+
for (int i = p.i - 2; i <= p.i + 2; ++i)
|
|
403
|
+
{ // Check nobody is nearby
|
|
404
|
+
for (int j = p.j - 2; j <= p.j + 2; ++j)
|
|
405
|
+
{
|
|
406
|
+
if (pos_ok(Pos(i, j)) and grid[i][j].id != -1)
|
|
407
|
+
return false;
|
|
349
408
|
}
|
|
350
409
|
}
|
|
351
410
|
return true;
|
|
352
411
|
}
|
|
353
412
|
|
|
354
|
-
Pos Board::get_random_pos_where_regenerate
|
|
413
|
+
Pos Board::get_random_pos_where_regenerate()
|
|
414
|
+
{
|
|
355
415
|
vector<Pos> res;
|
|
356
|
-
for (int i = 0; i < board_rows(); ++i)
|
|
357
|
-
|
|
358
|
-
|
|
416
|
+
for (int i = 0; i < board_rows(); ++i)
|
|
417
|
+
{
|
|
418
|
+
for (int j = 0; j < board_cols(); ++j)
|
|
419
|
+
{
|
|
420
|
+
if (is_good_pos_to_regen(Pos(i, j)))
|
|
421
|
+
res.push_back(Pos(i, j));
|
|
359
422
|
}
|
|
360
423
|
}
|
|
361
|
-
|
|
362
|
-
if (res.size() != 0) return res[random(0,res.size()-1)];
|
|
363
|
-
else return get_empty_pos();
|
|
364
|
-
}
|
|
365
424
|
|
|
425
|
+
if (res.size() != 0)
|
|
426
|
+
return res[random(0, res.size() - 1)];
|
|
427
|
+
else
|
|
428
|
+
return get_empty_pos();
|
|
429
|
+
}
|
|
366
430
|
|
|
367
431
|
// pair<bool,Pos> Board::get_random_pos_where_regenerate ( ) {
|
|
368
432
|
// vector<Pos> res;
|
|
@@ -371,12 +435,13 @@ Pos Board::get_random_pos_where_regenerate ( ) {
|
|
|
371
435
|
// if (is_good_pos_to_regen(Pos(i,j))) res.push_back(Pos(i,j));
|
|
372
436
|
// }
|
|
373
437
|
// }
|
|
374
|
-
|
|
438
|
+
|
|
375
439
|
// if (res.size() != 0) return {true,res[random(0,res.size()-1)]};
|
|
376
440
|
// else return {false,Pos()};
|
|
377
441
|
// }
|
|
378
442
|
|
|
379
|
-
void Board::next
|
|
443
|
+
void Board::next(const vector<Action> &act, ostream &os)
|
|
444
|
+
{
|
|
380
445
|
|
|
381
446
|
_my_assert(ok(), "Invariants are not satisfied.");
|
|
382
447
|
|
|
@@ -384,26 +449,29 @@ void Board::next (const vector<Action>& act, ostream& os) {
|
|
|
384
449
|
_my_assert(int(act.size()) == npl, "Size should be number of players.");
|
|
385
450
|
|
|
386
451
|
// Elements to be regenerated
|
|
387
|
-
vector<int> food_to_regenerate(num_players()+1,0); // we know how much food each clan has collected, in order to change overall_strength at the end of the round. Last position is for food eaten by zombies
|
|
452
|
+
vector<int> food_to_regenerate(num_players() + 1, 0); // we know how much food each clan has collected, in order to change overall_strength at the end of the round. Last position is for food eaten by zombies
|
|
388
453
|
vector<vector<int>> zombie_to_unit(num_players());
|
|
389
454
|
vector<vector<int>> alive_to_dead(num_players());
|
|
390
|
-
|
|
455
|
+
|
|
391
456
|
// Chooses (at most) one command per unit.
|
|
392
457
|
set<int> seen;
|
|
393
458
|
vector<vector<Command>> v(npl);
|
|
394
459
|
for (int pl = 0; pl < npl; ++pl)
|
|
395
|
-
for (const Command&
|
|
396
|
-
|
|
460
|
+
for (const Command &m : act[pl].v)
|
|
461
|
+
{
|
|
462
|
+
int id = m.id;
|
|
397
463
|
int c_type = m.c_type;
|
|
398
|
-
int dir
|
|
464
|
+
int dir = m.dir;
|
|
399
465
|
|
|
400
466
|
auto it = units.find(id);
|
|
401
467
|
|
|
402
|
-
if (it == units.end())
|
|
468
|
+
if (it == units.end())
|
|
469
|
+
cerr << "warning: invalid id : " << id << endl;
|
|
403
470
|
else if (it->second.player != pl)
|
|
404
471
|
cerr << "warning: unit " << id << " of player " << it->second.player
|
|
405
472
|
<< " not owned by " << pl << endl;
|
|
406
|
-
else
|
|
473
|
+
else
|
|
474
|
+
{
|
|
407
475
|
// Here an assert as repetitions should have already been filtered out.
|
|
408
476
|
_my_assert(not seen.count(id), "More than one command for the same unit.");
|
|
409
477
|
seen.insert(id);
|
|
@@ -412,39 +480,41 @@ void Board::next (const vector<Action>& act, ostream& os) {
|
|
|
412
480
|
}
|
|
413
481
|
}
|
|
414
482
|
|
|
415
|
-
|
|
416
483
|
// Makes all players' commands using a random order,
|
|
417
484
|
// but respecting the relative order of the units of the same player.
|
|
418
485
|
// Permutations are not equally likely to avoid favoring leading clans.
|
|
419
486
|
int num = 0; // Counts number of pending commands
|
|
420
|
-
for (int pl = 0; pl < npl; ++pl)
|
|
487
|
+
for (int pl = 0; pl < npl; ++pl)
|
|
488
|
+
num += v[pl].size();
|
|
421
489
|
|
|
422
490
|
set<int> killed;
|
|
423
491
|
vector<Command> commands_done;
|
|
424
492
|
vector<int> index(npl, 0);
|
|
425
|
-
while (num--)
|
|
493
|
+
while (num--)
|
|
494
|
+
{
|
|
426
495
|
int q = 0; // Counts number of players with some action pending
|
|
427
|
-
for (int pl = 0; pl < npl; ++pl)
|
|
496
|
+
for (int pl = 0; pl < npl; ++pl)
|
|
497
|
+
q += index[pl] < (int)v[pl].size();
|
|
428
498
|
_my_assert(q > 0, "q > 0 in next.");
|
|
429
|
-
int ran = random(1,q); // Decide whether 1st, 2nd, 3rd,, player with something pending is chosen
|
|
499
|
+
int ran = random(1, q); // Decide whether 1st, 2nd, 3rd,, player with something pending is chosen
|
|
430
500
|
int pl = -1;
|
|
431
501
|
int acum = 0;
|
|
432
|
-
while (acum < ran)
|
|
502
|
+
while (acum < ran)
|
|
503
|
+
{
|
|
433
504
|
++pl;
|
|
434
505
|
acum += index[pl] < (int)v[pl].size(); // If index > ..., then player has nothing pending
|
|
435
506
|
// and does not count
|
|
436
507
|
}
|
|
437
508
|
|
|
438
|
-
const Command&
|
|
509
|
+
const Command &m = v[pl][index[pl]++];
|
|
439
510
|
if (execute(m, food_to_regenerate, zombie_to_unit, alive_to_dead))
|
|
440
511
|
commands_done.push_back(m);
|
|
441
|
-
|
|
442
512
|
}
|
|
443
513
|
|
|
444
514
|
move_zombies(food_to_regenerate, zombie_to_unit, alive_to_dead, commands_done);
|
|
445
515
|
// Es mouen els zombies (de moment, que facin moviments random, ja els farem intel·ligents)
|
|
446
516
|
// Mirar com es fa a Moria (pel que sembla, s'execute un move i es posar a la llista de commands_done)
|
|
447
|
-
|
|
517
|
+
|
|
448
518
|
os << "commands" << endl;
|
|
449
519
|
Action::print(commands_done, os);
|
|
450
520
|
|
|
@@ -464,55 +534,63 @@ void Board::next (const vector<Action>& act, ostream& os) {
|
|
|
464
534
|
|
|
465
535
|
execute_conversion_alive_to_dead(alive_to_dead);
|
|
466
536
|
|
|
467
|
-
execute_random_conversion_live_unit(
|
|
468
|
-
|
|
537
|
+
execute_random_conversion_live_unit();
|
|
538
|
+
|
|
469
539
|
regenerate_food_and_update_strength(food_to_regenerate); // also substracts the food consumed per round
|
|
470
540
|
|
|
471
541
|
update_nb_cells();
|
|
472
542
|
|
|
473
543
|
update_score();
|
|
474
|
-
|
|
544
|
+
|
|
475
545
|
++rnd;
|
|
476
546
|
|
|
477
547
|
_my_assert(ok(), "Invariants are not satisfied.");
|
|
478
548
|
}
|
|
479
549
|
|
|
480
|
-
void Board::execute_conversion_to_zombie
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
550
|
+
void Board::execute_conversion_to_zombie()
|
|
551
|
+
{
|
|
552
|
+
for (auto &p : units)
|
|
553
|
+
{
|
|
554
|
+
Unit &u = p.second;
|
|
555
|
+
if (u.rounds_for_zombie == 0)
|
|
556
|
+
{
|
|
484
557
|
_my_assert(u.type != Zombie, "Cannot convert zombie to zombie");
|
|
485
|
-
if (u.type == Alive)
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
558
|
+
if (u.type == Alive)
|
|
559
|
+
{ // Alive to zombie
|
|
560
|
+
_my_assert(player2alive_units[u.player].count(u.id), "Alive unit not found in player2alive_units");
|
|
561
|
+
player2alive_units[u.player].erase(u.id);
|
|
562
|
+
zombies_.insert(u.id);
|
|
563
|
+
u.type = Zombie;
|
|
564
|
+
u.player = -1;
|
|
565
|
+
u.rounds_for_zombie = -1;
|
|
566
|
+
grid[u.pos.i][u.pos.j].owner = -1;
|
|
493
567
|
}
|
|
494
|
-
else
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
568
|
+
else
|
|
569
|
+
{
|
|
570
|
+
_my_assert(u.type == Dead, "If not zombie or alive, should be dead");
|
|
571
|
+
_my_assert(player2dead_units[u.player].count(u.id), "Dead unit not found in player2dead_units");
|
|
572
|
+
player2dead_units[u.player].erase(u.id);
|
|
573
|
+
zombies_.insert(u.id);
|
|
574
|
+
u.type = Zombie;
|
|
575
|
+
u.player = -1;
|
|
576
|
+
u.rounds_for_zombie = -1;
|
|
577
|
+
grid[u.pos.i][u.pos.j].owner = -1;
|
|
503
578
|
}
|
|
504
579
|
}
|
|
505
580
|
}
|
|
506
581
|
}
|
|
507
582
|
|
|
508
|
-
void Board::execute_conversion_zombie_to_alive
|
|
509
|
-
|
|
510
|
-
|
|
583
|
+
void Board::execute_conversion_zombie_to_alive(vector<vector<int>> &zombie_to_unit)
|
|
584
|
+
{
|
|
585
|
+
for (int p = 0; p < num_players(); ++p)
|
|
586
|
+
{
|
|
587
|
+
for (int id : zombie_to_unit[p])
|
|
588
|
+
{
|
|
511
589
|
_my_assert(units.count(id) != 0, "Unit which should be converted zombie->unit not found in units");
|
|
512
590
|
_my_assert(zombies_.count(id) != 0, "Unit which should be converted zombie->unit not found in zombies_");
|
|
513
591
|
_my_assert(units[id].type == Zombie, "Unit in zombie_to_unit is not a zombie");
|
|
514
|
-
Pos new_pos = get_random_pos_where_regenerate(
|
|
515
|
-
Unit&
|
|
592
|
+
Pos new_pos = get_random_pos_where_regenerate();
|
|
593
|
+
Unit &u = units[id];
|
|
516
594
|
u.type = Alive;
|
|
517
595
|
u.player = p;
|
|
518
596
|
u.pos = new_pos;
|
|
@@ -520,211 +598,250 @@ void Board::execute_conversion_zombie_to_alive (vector<vector<int>>& zombie_to_u
|
|
|
520
598
|
zombies_.erase(id);
|
|
521
599
|
player2alive_units[p].insert(id);
|
|
522
600
|
|
|
523
|
-
Cell&
|
|
601
|
+
Cell &c = grid[new_pos.i][new_pos.j];
|
|
524
602
|
c.owner = p;
|
|
525
603
|
c.id = id;
|
|
526
604
|
}
|
|
527
605
|
}
|
|
528
606
|
}
|
|
529
607
|
|
|
530
|
-
void Board::execute_conversion_alive_to_dead
|
|
531
|
-
|
|
532
|
-
|
|
608
|
+
void Board::execute_conversion_alive_to_dead(vector<vector<int>> &alive_to_dead)
|
|
609
|
+
{
|
|
610
|
+
for (int p = 0; p < num_players(); ++p)
|
|
611
|
+
{
|
|
612
|
+
for (int id : alive_to_dead[p])
|
|
613
|
+
{
|
|
533
614
|
_my_assert(units.count(id) != 0, "Unit which should be converted alive->dead not found in units");
|
|
534
615
|
_my_assert(player2alive_units[p].count(id) != 0, "Unit which should be converted alive->dead not found in player2alive_units");
|
|
535
616
|
_my_assert(units[id].type == Dead, "Unit in alive_to_dead should have already been markes as dead");
|
|
536
|
-
Unit&
|
|
617
|
+
Unit &u = units[id];
|
|
537
618
|
u.type = Dead;
|
|
538
619
|
u.player = p;
|
|
539
620
|
u.rounds_for_zombie = rounds_before_becoming_zombie();
|
|
540
621
|
player2alive_units[p].erase(id);
|
|
541
622
|
player2dead_units[p].insert(id);
|
|
542
623
|
}
|
|
543
|
-
}
|
|
624
|
+
}
|
|
544
625
|
}
|
|
545
626
|
|
|
546
|
-
pair<int,int> Board::selectLargestSmallestClan
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
627
|
+
pair<int, int> Board::selectLargestSmallestClan()
|
|
628
|
+
{
|
|
629
|
+
vector<pair<int, int>> alive_clan(num_players());
|
|
630
|
+
for (uint p = 0; p < alive_clan.size(); ++p)
|
|
631
|
+
alive_clan[p] = {player2alive_units[p].size(), p};
|
|
632
|
+
sort(alive_clan.begin(), alive_clan.end(), greater<pair<int, int>>()); // sort descending
|
|
633
|
+
|
|
634
|
+
if (alive_clan[0].first == alive_clan.back().first)
|
|
635
|
+
{ // All clans same number of alive units
|
|
636
|
+
int clan_wins = random(0, 3);
|
|
637
|
+
int clan_loses = random(0, 3);
|
|
638
|
+
while (clan_loses == clan_wins)
|
|
639
|
+
clan_loses = random(0, 3);
|
|
555
640
|
return {clan_wins, clan_loses};
|
|
556
641
|
}
|
|
557
642
|
|
|
558
643
|
vector<int> largest_clans = {alive_clan[0].second};
|
|
559
644
|
int i = 1;
|
|
560
|
-
while (i < int(alive_clan.size()) and alive_clan[i].first == alive_clan[0].first)
|
|
645
|
+
while (i < int(alive_clan.size()) and alive_clan[i].first == alive_clan[0].first)
|
|
646
|
+
{
|
|
561
647
|
largest_clans.push_back(alive_clan[i].second);
|
|
562
648
|
++i;
|
|
563
649
|
}
|
|
564
650
|
|
|
565
|
-
|
|
566
|
-
int clan_that_loses_unit = largest_clans[random(0,largest_clans.size()-1)];
|
|
651
|
+
int clan_that_loses_unit = largest_clans[random(0, largest_clans.size() - 1)];
|
|
567
652
|
|
|
568
653
|
vector<int> smallest_clans = {alive_clan.back().second};
|
|
569
654
|
i = int(alive_clan.size()) - 2;
|
|
570
|
-
while (i >= 0 and alive_clan[i].first == alive_clan.back().first)
|
|
655
|
+
while (i >= 0 and alive_clan[i].first == alive_clan.back().first)
|
|
656
|
+
{
|
|
571
657
|
smallest_clans.push_back(alive_clan[i].second);
|
|
572
658
|
--i;
|
|
573
659
|
}
|
|
574
660
|
|
|
575
|
-
int clan_that_wins_unit = smallest_clans[random(0,smallest_clans.size()-1)];
|
|
661
|
+
int clan_that_wins_unit = smallest_clans[random(0, smallest_clans.size() - 1)];
|
|
576
662
|
return {clan_that_wins_unit, clan_that_loses_unit};
|
|
577
663
|
}
|
|
578
664
|
|
|
579
|
-
void Board::execute_random_conversion_live_unit
|
|
580
|
-
|
|
665
|
+
void Board::execute_random_conversion_live_unit()
|
|
666
|
+
{
|
|
667
|
+
if (random(0, 4) != 0)
|
|
668
|
+
return; // 20% probability of conversion
|
|
581
669
|
|
|
582
|
-
pair<int,int> tmp = selectLargestSmallestClan();
|
|
670
|
+
pair<int, int> tmp = selectLargestSmallestClan();
|
|
583
671
|
int wins = tmp.first;
|
|
584
672
|
int loses = tmp.second;
|
|
585
|
-
|
|
673
|
+
|
|
586
674
|
_my_assert(wins != loses, "A clan cannot win and lose a unit");
|
|
587
675
|
|
|
588
|
-
if (player2alive_units[loses].size() == 0)
|
|
589
|
-
|
|
676
|
+
if (player2alive_units[loses].size() == 0)
|
|
677
|
+
return; // No alive unit (very strange)
|
|
678
|
+
|
|
590
679
|
// Choose randomly a unit from clan "loses"
|
|
591
|
-
int k = random(0,player2alive_units[loses].size()-1);
|
|
680
|
+
int k = random(0, player2alive_units[loses].size() - 1);
|
|
592
681
|
auto it = player2alive_units[loses].begin();
|
|
593
|
-
advance(it,k);
|
|
682
|
+
advance(it, k);
|
|
594
683
|
int u_t = *it; // unit transferred
|
|
595
684
|
|
|
596
685
|
player2alive_units[loses].erase(it);
|
|
597
686
|
player2alive_units[wins].insert(u_t);
|
|
598
|
-
Unit&
|
|
687
|
+
Unit &u = units[u_t];
|
|
599
688
|
_my_assert(u.type == Alive, "Transferred unit should be alive");
|
|
600
689
|
u.player = wins;
|
|
601
|
-
grid[u.pos.i][u.pos.j].owner = wins;
|
|
690
|
+
grid[u.pos.i][u.pos.j].owner = wins;
|
|
602
691
|
}
|
|
603
692
|
|
|
604
|
-
void Board::decrement_rounds_for_becoming_zombie
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
693
|
+
void Board::decrement_rounds_for_becoming_zombie()
|
|
694
|
+
{
|
|
695
|
+
for (auto &p : units)
|
|
696
|
+
{
|
|
697
|
+
Unit &u = p.second;
|
|
698
|
+
if (u.rounds_for_zombie > 0)
|
|
608
699
|
--u.rounds_for_zombie;
|
|
609
700
|
}
|
|
610
701
|
}
|
|
611
702
|
|
|
612
|
-
void Board::generate_food_item
|
|
613
|
-
|
|
614
|
-
|
|
703
|
+
void Board::generate_food_item()
|
|
704
|
+
{
|
|
705
|
+
Pos p = get_random_pos_where_regenerate();
|
|
706
|
+
Cell &c = grid[p.i][p.j];
|
|
615
707
|
c.food = true;
|
|
616
|
-
_my_assert(c.id == -1 and c.type == Street, "Generated food in already full cell");
|
|
708
|
+
_my_assert(c.id == -1 and c.type == Street, "Generated food in already full cell");
|
|
617
709
|
}
|
|
618
710
|
|
|
619
|
-
void Board::regenerate_food_and_update_strength
|
|
620
|
-
|
|
621
|
-
|
|
711
|
+
void Board::regenerate_food_and_update_strength(vector<int> &food_to_regenerate)
|
|
712
|
+
{
|
|
713
|
+
for (int p = 0; p < num_players(); ++p)
|
|
714
|
+
{
|
|
715
|
+
overall_strength[p] += food_strength() * food_to_regenerate[p];
|
|
622
716
|
overall_strength[p] -= player2alive_units[p].size(); // One unit of food is eaten by each alive unit
|
|
623
|
-
overall_strength[p] = max(0,overall_strength[p]);
|
|
624
|
-
for (int k = 0; k < food_to_regenerate[p]
|
|
717
|
+
overall_strength[p] = max(0, overall_strength[p]); // Strength >= 0
|
|
718
|
+
for (int k = 0; k < food_to_regenerate[p]; ++k)
|
|
625
719
|
generate_food_item();
|
|
626
720
|
}
|
|
627
721
|
|
|
628
722
|
// Food items eaten by zombies
|
|
629
|
-
for (int k = 0; k < food_to_regenerate.back()
|
|
630
|
-
|
|
723
|
+
for (int k = 0; k < food_to_regenerate.back(); ++k)
|
|
724
|
+
generate_food_item();
|
|
631
725
|
}
|
|
632
726
|
|
|
633
|
-
void Board::update_nb_cells
|
|
727
|
+
void Board::update_nb_cells()
|
|
728
|
+
{
|
|
634
729
|
// Set all to zero
|
|
635
|
-
for (auto&
|
|
730
|
+
for (auto &x : nb_cells)
|
|
731
|
+
x = 0;
|
|
636
732
|
|
|
637
733
|
// Add the ones in the grid
|
|
638
734
|
for (int i = 0; i < board_rows(); ++i)
|
|
639
|
-
for (int j = 0; j < board_cols(); ++j)
|
|
640
|
-
if (grid[i][j].owner != -1)
|
|
641
|
-
|
|
735
|
+
for (int j = 0; j < board_cols(); ++j)
|
|
736
|
+
if (grid[i][j].owner != -1)
|
|
737
|
+
++nb_cells[grid[i][j].owner];
|
|
642
738
|
}
|
|
643
739
|
|
|
644
|
-
void Board::update_score
|
|
740
|
+
void Board::update_score()
|
|
741
|
+
{
|
|
645
742
|
for (int p = 0; p < num_players(); ++p)
|
|
646
|
-
scr[p] = scr_accumulated[p] + nb_cells[p]*1;
|
|
743
|
+
scr[p] = scr_accumulated[p] + nb_cells[p] * 1;
|
|
647
744
|
}
|
|
648
745
|
|
|
649
|
-
bool Board::cell_has_dead_unit
|
|
650
|
-
|
|
651
|
-
|
|
746
|
+
bool Board::cell_has_dead_unit(int i, int j)
|
|
747
|
+
{
|
|
748
|
+
if (grid[i][j].id == -1)
|
|
749
|
+
return false;
|
|
750
|
+
Unit &u = units[grid[i][j].id];
|
|
652
751
|
return (u.type == Dead);
|
|
653
752
|
}
|
|
654
753
|
|
|
655
|
-
bool Board::cell_has_zombie
|
|
656
|
-
|
|
657
|
-
|
|
754
|
+
bool Board::cell_has_zombie(int i, int j)
|
|
755
|
+
{
|
|
756
|
+
if (grid[i][j].id == -1)
|
|
757
|
+
return false;
|
|
758
|
+
Unit &u = units[grid[i][j].id];
|
|
658
759
|
return (u.type == Zombie);
|
|
659
760
|
}
|
|
660
761
|
|
|
661
|
-
void Board::move_zombies
|
|
762
|
+
void Board::move_zombies(vector<int> &food_to_regenerate, vector<vector<int>> &zombie_to_unit, vector<vector<int>> &alive_to_dead, vector<Command> &commands_done)
|
|
763
|
+
{
|
|
662
764
|
// First compute distances
|
|
663
765
|
int r = board_rows();
|
|
664
766
|
int c = board_cols();
|
|
665
767
|
|
|
666
768
|
int inf = 1e9;
|
|
667
|
-
vector<vector<int>> T(r,vector<int>(c,inf));
|
|
769
|
+
vector<vector<int>> T(r, vector<int>(c, inf));
|
|
668
770
|
queue<Pos> Q;
|
|
669
771
|
for (int i = 0; i < r; ++i)
|
|
670
|
-
for (int j = 0; j < c; ++j)
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
772
|
+
for (int j = 0; j < c; ++j)
|
|
773
|
+
{
|
|
774
|
+
const Cell &c = grid[i][j];
|
|
775
|
+
if (c.id != -1 and units[c.id].type == Alive)
|
|
776
|
+
{
|
|
777
|
+
Q.push(Pos(i, j));
|
|
778
|
+
T[i][j] = 0;
|
|
675
779
|
}
|
|
676
780
|
}
|
|
677
|
-
|
|
678
|
-
while (not Q.empty())
|
|
679
|
-
|
|
680
|
-
|
|
781
|
+
|
|
782
|
+
while (not Q.empty())
|
|
783
|
+
{
|
|
784
|
+
Pos p = Q.front();
|
|
785
|
+
Q.pop();
|
|
786
|
+
for (auto d : {Down, DR, Right, RU, Up, UL, Left, LD})
|
|
787
|
+
{
|
|
681
788
|
Pos np = p + d;
|
|
682
789
|
if (pos_ok(np) and
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
790
|
+
not cell_has_dead_unit(np.i, np.j) and
|
|
791
|
+
not cell_has_zombie(np.i, np.j) and
|
|
792
|
+
grid[np.i][np.j].type != Waste and
|
|
793
|
+
T[np.i][np.j] == inf)
|
|
794
|
+
{
|
|
795
|
+
T[np.i][np.j] = T[p.i][p.j] + 1;
|
|
796
|
+
Q.push(np);
|
|
690
797
|
}
|
|
691
798
|
}
|
|
692
799
|
}
|
|
693
800
|
|
|
694
|
-
for (int z_id : zombies_)
|
|
695
|
-
|
|
696
|
-
|
|
801
|
+
for (int z_id : zombies_)
|
|
802
|
+
{
|
|
803
|
+
if (units[z_id].pos != Pos(-1, -1))
|
|
804
|
+
{ // Not dead
|
|
805
|
+
const Unit &u = units[z_id];
|
|
697
806
|
Pos p1 = u.pos;
|
|
698
807
|
vector<int> C;
|
|
699
808
|
int minim = 1e8;
|
|
700
|
-
for (int d = 0; d < 8; ++d)
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
809
|
+
for (int d = 0; d < 8; ++d)
|
|
810
|
+
{
|
|
811
|
+
Pos p2 = p1 + Dir(d);
|
|
812
|
+
if (pos_ok(p2))
|
|
813
|
+
{
|
|
814
|
+
int dist = T[p2.i][p2.j];
|
|
815
|
+
if (dist < minim)
|
|
816
|
+
{
|
|
817
|
+
minim = dist;
|
|
818
|
+
C = {d};
|
|
819
|
+
}
|
|
820
|
+
else if (dist == minim)
|
|
821
|
+
C.push_back(d);
|
|
822
|
+
}
|
|
710
823
|
}
|
|
711
824
|
|
|
712
|
-
if (not C.empty())
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
825
|
+
if (not C.empty())
|
|
826
|
+
{
|
|
827
|
+
Dir dir = Dir(C[random(0, C.size() - 1)]);
|
|
828
|
+
Command com(z_id, Move, dir);
|
|
829
|
+
if (execute(com, food_to_regenerate, zombie_to_unit, alive_to_dead))
|
|
830
|
+
{
|
|
831
|
+
commands_done.push_back(com);
|
|
832
|
+
}
|
|
718
833
|
}
|
|
719
834
|
}
|
|
720
835
|
}
|
|
721
836
|
}
|
|
722
837
|
|
|
723
|
-
vector<Dir> Board::dir_permutation
|
|
838
|
+
vector<Dir> Board::dir_permutation()
|
|
839
|
+
{
|
|
724
840
|
vector<Dir> dirs = {Up, Down, Left, Right};
|
|
725
841
|
vector<int> p = random_permutation(4);
|
|
726
842
|
vector<Dir> new_dirs(4);
|
|
727
|
-
for (int i = 0; i < 4; ++i)
|
|
843
|
+
for (int i = 0; i < 4; ++i)
|
|
844
|
+
new_dirs[i] = dirs[p[i]];
|
|
728
845
|
return new_dirs;
|
|
729
846
|
}
|
|
730
847
|
|
|
@@ -732,37 +849,43 @@ vector<Dir> Board::dir_permutation ( ) {
|
|
|
732
849
|
// BOARD GENERATION
|
|
733
850
|
//************************************************************
|
|
734
851
|
|
|
735
|
-
int Board::generate_waste
|
|
852
|
+
int Board::generate_waste(int s_id, int length)
|
|
853
|
+
{
|
|
736
854
|
int filled = 0;
|
|
737
855
|
vector<Dir> dirs = {Up, Down, Left, Right};
|
|
738
|
-
Dir last_dir = dirs[random(0,dirs.size()-1)];
|
|
856
|
+
Dir last_dir = dirs[random(0, dirs.size() - 1)];
|
|
739
857
|
Pos p = get_ok_pos_for_initial_street();
|
|
740
858
|
street_plan[p.i][p.j] = s_id;
|
|
741
859
|
++filled;
|
|
742
|
-
while (length > 0)
|
|
743
|
-
|
|
744
|
-
|
|
860
|
+
while (length > 0)
|
|
861
|
+
{
|
|
862
|
+
shuffle_vector(dirs);
|
|
863
|
+
// dirs = dir_permutation();
|
|
745
864
|
Dir new_possible_dir = Up; // Explore the possibility of turning
|
|
746
865
|
bool dir_found = false;
|
|
747
|
-
for (auto&
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
866
|
+
for (auto &d : dirs)
|
|
867
|
+
{
|
|
868
|
+
if (pos_ok_for_street(s_id, p + d))
|
|
869
|
+
{
|
|
870
|
+
new_possible_dir = d;
|
|
871
|
+
dir_found = true;
|
|
872
|
+
break;
|
|
752
873
|
}
|
|
753
874
|
}
|
|
754
|
-
|
|
755
|
-
if (random(1,8) != 1 and pos_ok_for_street(s_id,p+last_dir))
|
|
875
|
+
|
|
876
|
+
if (random(1, 8) != 1 and pos_ok_for_street(s_id, p + last_dir))
|
|
877
|
+
{ // Continue same direction
|
|
756
878
|
p += last_dir;
|
|
757
879
|
street_plan[p.i][p.j] = s_id;
|
|
758
880
|
--length;
|
|
759
881
|
++filled;
|
|
760
882
|
}
|
|
761
|
-
else if (dir_found)
|
|
883
|
+
else if (dir_found)
|
|
884
|
+
{ // Turn
|
|
762
885
|
last_dir = new_possible_dir;
|
|
763
|
-
_my_assert(cell(p+new_possible_dir).is_empty(), "Cell no empty");
|
|
886
|
+
_my_assert(cell(p + new_possible_dir).is_empty(), "Cell no empty");
|
|
764
887
|
p += new_possible_dir;
|
|
765
|
-
_my_assert(pos_ok_for_street(s_id,p), "Pos not ok for street.");
|
|
888
|
+
_my_assert(pos_ok_for_street(s_id, p), "Pos not ok for street.");
|
|
766
889
|
street_plan[p.i][p.j] = s_id;
|
|
767
890
|
--length;
|
|
768
891
|
++filled;
|
|
@@ -773,129 +896,176 @@ int Board::generate_waste (int s_id, int length) {
|
|
|
773
896
|
return filled;
|
|
774
897
|
}
|
|
775
898
|
|
|
776
|
-
void Board::generate_all_waste
|
|
777
|
-
|
|
778
|
-
|
|
899
|
+
void Board::generate_all_waste(int num_waste_cells, int num_streets)
|
|
900
|
+
{
|
|
901
|
+
street_plan = vector<vector<int>>(board_rows(), vector<int>(board_cols(), 0));
|
|
902
|
+
|
|
779
903
|
int num_streets_pending = num_streets;
|
|
780
|
-
while (num_streets_pending > 0)
|
|
904
|
+
while (num_streets_pending > 0)
|
|
905
|
+
{
|
|
781
906
|
int length;
|
|
782
|
-
if (num_streets_pending != 1)
|
|
783
|
-
|
|
784
|
-
|
|
907
|
+
if (num_streets_pending != 1)
|
|
908
|
+
length = num_waste_cells / num_streets_pending;
|
|
909
|
+
else
|
|
910
|
+
length = num_waste_cells;
|
|
911
|
+
num_waste_cells -= generate_waste(num_streets_pending, length);
|
|
785
912
|
--num_streets_pending;
|
|
786
913
|
}
|
|
787
914
|
|
|
788
|
-
for (int i = 0; i < board_rows(); ++i)
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
915
|
+
for (int i = 0; i < board_rows(); ++i)
|
|
916
|
+
{
|
|
917
|
+
for (int j = 0; j < board_cols(); ++j)
|
|
918
|
+
{
|
|
919
|
+
if (street_plan[i][j] != 0)
|
|
920
|
+
{
|
|
921
|
+
grid[i][j].type = Waste;
|
|
792
922
|
}
|
|
793
923
|
}
|
|
794
924
|
}
|
|
795
|
-
|
|
796
925
|
}
|
|
797
926
|
|
|
798
|
-
Pos Board::get_empty_pos
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
927
|
+
Pos Board::get_empty_pos()
|
|
928
|
+
{
|
|
929
|
+
while (true)
|
|
930
|
+
{
|
|
931
|
+
int i = random(0, board_rows() - 1);
|
|
932
|
+
int j = random(0, board_cols() - 1);
|
|
933
|
+
if (cell(i, j).is_empty())
|
|
934
|
+
return Pos(i, j);
|
|
803
935
|
}
|
|
804
936
|
}
|
|
805
937
|
|
|
806
|
-
Pos Board::get_ok_pos_for_street(int s_id)
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
938
|
+
Pos Board::get_ok_pos_for_street(int s_id)
|
|
939
|
+
{
|
|
940
|
+
while (true)
|
|
941
|
+
{
|
|
942
|
+
int i = random(1, board_rows() - 2);
|
|
943
|
+
int j = random(1, board_cols() - 2);
|
|
944
|
+
if (pos_ok_for_street(s_id, Pos(i, j)))
|
|
945
|
+
return Pos(i, j);
|
|
811
946
|
}
|
|
812
947
|
}
|
|
813
948
|
|
|
814
|
-
Pos Board::get_ok_pos_for_initial_street()
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
949
|
+
Pos Board::get_ok_pos_for_initial_street()
|
|
950
|
+
{
|
|
951
|
+
while (true)
|
|
952
|
+
{
|
|
953
|
+
int i = random(1, board_rows() - 2);
|
|
954
|
+
int j = random(1, board_cols() - 2);
|
|
955
|
+
if (pos_ok_for_initial_street(Pos(i, j)))
|
|
956
|
+
return Pos(i, j);
|
|
819
957
|
}
|
|
820
958
|
}
|
|
821
959
|
|
|
822
|
-
bool Board::pos_ok_for_street(int s_id, const Pos&
|
|
960
|
+
bool Board::pos_ok_for_street(int s_id, const Pos &p)
|
|
961
|
+
{
|
|
823
962
|
int i = p.i, j = p.j;
|
|
824
|
-
if (not pos_ok(p))
|
|
825
|
-
|
|
826
|
-
if (i
|
|
827
|
-
|
|
828
|
-
if (
|
|
829
|
-
|
|
963
|
+
if (not pos_ok(p))
|
|
964
|
+
return false;
|
|
965
|
+
if (street_plan[i][j] != 0)
|
|
966
|
+
return false;
|
|
967
|
+
if (i == 0)
|
|
968
|
+
return false;
|
|
969
|
+
if (i == board_rows() - 1)
|
|
970
|
+
return false;
|
|
971
|
+
if (j == 0)
|
|
972
|
+
return false;
|
|
973
|
+
if (j == board_cols() - 1)
|
|
974
|
+
return false;
|
|
830
975
|
|
|
831
976
|
int num_occupied = 0;
|
|
832
977
|
vector<Dir> dirs = {Up, Down, Left, Right};
|
|
833
|
-
for (auto&
|
|
978
|
+
for (auto &d : dirs)
|
|
979
|
+
{
|
|
834
980
|
Pos newPos = p + d; // Will exists because p is not on a border
|
|
835
981
|
int ni = newPos.i, nj = newPos.j;
|
|
836
|
-
if (street_plan[ni][nj] != 0 and street_plan[ni][nj] != s_id)
|
|
837
|
-
|
|
982
|
+
if (street_plan[ni][nj] != 0 and street_plan[ni][nj] != s_id)
|
|
983
|
+
return false;
|
|
984
|
+
else if (street_plan[ni][nj] == s_id)
|
|
985
|
+
++num_occupied;
|
|
838
986
|
}
|
|
839
987
|
|
|
840
|
-
vector<pair<int,int>> diags = {{1,1},{1
|
|
841
|
-
for (auto&
|
|
988
|
+
vector<pair<int, int>> diags = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
|
|
989
|
+
for (auto &d : diags)
|
|
990
|
+
{
|
|
842
991
|
Pos newPos = Pos(p.i + d.first, p.j + d.second);
|
|
843
992
|
int ni = newPos.i, nj = newPos.j;
|
|
844
|
-
if (street_plan[ni][nj] != 0 and street_plan[ni][nj] != s_id)
|
|
845
|
-
|
|
993
|
+
if (street_plan[ni][nj] != 0 and street_plan[ni][nj] != s_id)
|
|
994
|
+
return false;
|
|
995
|
+
else if (street_plan[ni][nj] == s_id)
|
|
996
|
+
++num_occupied;
|
|
846
997
|
}
|
|
847
|
-
|
|
998
|
+
|
|
848
999
|
return num_occupied <= 2;
|
|
849
1000
|
}
|
|
850
1001
|
|
|
851
|
-
bool Board::pos_ok_for_initial_street(const Pos&
|
|
1002
|
+
bool Board::pos_ok_for_initial_street(const Pos &p)
|
|
1003
|
+
{
|
|
852
1004
|
int i = p.i, j = p.j;
|
|
853
|
-
if (not pos_ok(p))
|
|
854
|
-
|
|
855
|
-
if (i
|
|
856
|
-
|
|
857
|
-
if (
|
|
858
|
-
|
|
1005
|
+
if (not pos_ok(p))
|
|
1006
|
+
return false;
|
|
1007
|
+
if (street_plan[i][j] != 0)
|
|
1008
|
+
return false;
|
|
1009
|
+
if (i == 0)
|
|
1010
|
+
return false;
|
|
1011
|
+
if (i == board_rows() - 1)
|
|
1012
|
+
return false;
|
|
1013
|
+
if (j == 0)
|
|
1014
|
+
return false;
|
|
1015
|
+
if (j == board_cols() - 1)
|
|
1016
|
+
return false;
|
|
859
1017
|
|
|
860
1018
|
int num_occupied = 0;
|
|
861
1019
|
vector<Dir> dirs = {Up, Down, Left, Right};
|
|
862
|
-
for (auto&
|
|
1020
|
+
for (auto &d : dirs)
|
|
1021
|
+
{
|
|
863
1022
|
Pos newPos = p + d; // Will exists because p is not on a border
|
|
864
1023
|
int n_i = newPos.i, n_j = newPos.j;
|
|
865
|
-
if (street_plan[n_i][n_j] != 0)
|
|
1024
|
+
if (street_plan[n_i][n_j] != 0)
|
|
1025
|
+
return false;
|
|
866
1026
|
}
|
|
867
1027
|
|
|
868
|
-
vector<pair<int,int>> diags = {{1,1},{1
|
|
869
|
-
for (auto&
|
|
1028
|
+
vector<pair<int, int>> diags = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
|
|
1029
|
+
for (auto &d : diags)
|
|
1030
|
+
{
|
|
870
1031
|
Pos newPos = Pos(p.i + d.first, p.j + d.second);
|
|
871
1032
|
int n_i = newPos.i, n_j = newPos.j;
|
|
872
|
-
if (street_plan[n_i][n_j] != 0)
|
|
1033
|
+
if (street_plan[n_i][n_j] != 0)
|
|
1034
|
+
return false;
|
|
873
1035
|
}
|
|
874
|
-
|
|
1036
|
+
|
|
875
1037
|
return true;
|
|
876
1038
|
}
|
|
877
1039
|
|
|
878
|
-
void Board::explore_from(vector<vector<int
|
|
1040
|
+
void Board::explore_from(vector<vector<int>> &G, int i, int j, int n)
|
|
1041
|
+
{
|
|
879
1042
|
G[i][j] = n;
|
|
880
|
-
for (auto&
|
|
881
|
-
|
|
882
|
-
|
|
1043
|
+
for (auto &d : {Up, Down, Left, Right})
|
|
1044
|
+
{
|
|
1045
|
+
Pos np = Pos(i, j) + d;
|
|
1046
|
+
if (pos_ok(np) and G[np.i][np.j] == -1)
|
|
1047
|
+
explore_from(G, np.i, np.j, n);
|
|
883
1048
|
}
|
|
884
1049
|
}
|
|
885
1050
|
|
|
886
|
-
int Board::num_connected_components(
|
|
887
|
-
|
|
1051
|
+
int Board::num_connected_components()
|
|
1052
|
+
{
|
|
1053
|
+
vector<vector<int>> G(board_rows(), vector<int>(board_cols(), -1));
|
|
888
1054
|
|
|
889
|
-
for (int i = 0; i < board_rows(); ++i)
|
|
1055
|
+
for (int i = 0; i < board_rows(); ++i)
|
|
890
1056
|
for (int j = 0; j < board_cols(); ++j)
|
|
891
|
-
if (grid[i][j].type == Waste)
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
1057
|
+
if (grid[i][j].type == Waste)
|
|
1058
|
+
G[i][j] = -2;
|
|
1059
|
+
|
|
1060
|
+
int n = 0;
|
|
1061
|
+
for (int i = 0; i < board_rows(); ++i)
|
|
1062
|
+
{
|
|
1063
|
+
for (int j = 0; j < board_cols(); ++j)
|
|
1064
|
+
{
|
|
1065
|
+
if (G[i][j] == -1)
|
|
1066
|
+
{
|
|
1067
|
+
explore_from(G, i, j, n);
|
|
1068
|
+
++n;
|
|
899
1069
|
}
|
|
900
1070
|
}
|
|
901
1071
|
}
|
|
@@ -903,73 +1073,77 @@ int Board::num_connected_components( ){
|
|
|
903
1073
|
return n;
|
|
904
1074
|
}
|
|
905
1075
|
|
|
906
|
-
void Board::create_new_unit
|
|
1076
|
+
void Board::create_new_unit(Pos &p, int player)
|
|
1077
|
+
{
|
|
907
1078
|
int id = fresh_id;
|
|
908
1079
|
++fresh_id;
|
|
909
1080
|
_my_assert(not units.count(id), "Identifier is not fresh.");
|
|
910
1081
|
|
|
911
1082
|
units[id] = Unit(Alive, id, player, p, -1);
|
|
912
1083
|
player2alive_units[player].insert(id);
|
|
913
|
-
|
|
914
|
-
_my_assert(grid[p.i][p.j].is_empty(),
|
|
1084
|
+
|
|
1085
|
+
_my_assert(grid[p.i][p.j].is_empty(), "Cell is already full.");
|
|
915
1086
|
|
|
916
1087
|
grid[p.i][p.j].id = id;
|
|
917
1088
|
grid[p.i][p.j].owner = player;
|
|
918
1089
|
}
|
|
919
1090
|
|
|
920
|
-
void Board::create_new_zombie
|
|
1091
|
+
void Board::create_new_zombie(Pos &p)
|
|
1092
|
+
{
|
|
921
1093
|
int id = fresh_id;
|
|
922
1094
|
++fresh_id;
|
|
923
1095
|
_my_assert(not units.count(id), "Identifier is not fresh.");
|
|
924
|
-
_my_assert(grid[p.i][p.j].is_empty(),
|
|
925
|
-
|
|
1096
|
+
_my_assert(grid[p.i][p.j].is_empty(), "Cell is already full.");
|
|
1097
|
+
|
|
926
1098
|
units[id] = Unit(Zombie, id, -1, p, -1);
|
|
927
1099
|
zombies_.insert(id);
|
|
928
1100
|
|
|
929
1101
|
grid[p.i][p.j].id = id;
|
|
930
|
-
|
|
931
1102
|
}
|
|
932
1103
|
|
|
933
|
-
void Board::generate_random_board
|
|
1104
|
+
void Board::generate_random_board()
|
|
1105
|
+
{
|
|
934
1106
|
int rows = board_rows();
|
|
935
1107
|
int cols = board_cols();
|
|
936
1108
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
static const int num_waste_cells = 0.5*rows*cols; // goal of 50% waste
|
|
1109
|
+
// Generate buildings (leaving space for citizens)
|
|
1110
|
+
static const int num_waste_cells = 0.5 * rows * cols; // goal of 50% waste
|
|
940
1111
|
static const int num_streets = 8;
|
|
941
1112
|
|
|
942
|
-
do
|
|
1113
|
+
do
|
|
1114
|
+
{
|
|
943
1115
|
// Create grid
|
|
944
1116
|
grid = vector<vector<Cell>>(rows, vector<Cell>(cols));
|
|
945
1117
|
generate_all_waste(num_waste_cells, num_streets);
|
|
946
1118
|
} while (num_connected_components() != 1);
|
|
947
1119
|
|
|
948
|
-
for (int i = 0; i < board_rows(); ++i)
|
|
1120
|
+
for (int i = 0; i < board_rows(); ++i)
|
|
949
1121
|
for (int j = 0; j < board_cols(); ++j)
|
|
950
|
-
if (street_plan[i][j] != 0)
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1122
|
+
if (street_plan[i][j] != 0)
|
|
1123
|
+
grid[i][j].type = Waste;
|
|
1124
|
+
|
|
954
1125
|
// Generate units
|
|
955
|
-
for (int pl = 0; pl < num_players(); ++pl)
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
1126
|
+
for (int pl = 0; pl < num_players(); ++pl)
|
|
1127
|
+
{
|
|
1128
|
+
for (int i = 0; i < num_ini_units_per_clan(); ++i)
|
|
1129
|
+
{
|
|
1130
|
+
Pos p = get_random_pos_where_regenerate();
|
|
1131
|
+
create_new_unit(p, pl);
|
|
959
1132
|
++nb_cells[pl];
|
|
960
1133
|
}
|
|
961
1134
|
}
|
|
962
1135
|
|
|
963
1136
|
// Generate zombies
|
|
964
|
-
for (int i = 0; i < num_ini_zombies(); ++i)
|
|
965
|
-
|
|
1137
|
+
for (int i = 0; i < num_ini_zombies(); ++i)
|
|
1138
|
+
{
|
|
1139
|
+
Pos p = get_random_pos_where_regenerate();
|
|
966
1140
|
create_new_zombie(p);
|
|
967
1141
|
}
|
|
968
1142
|
|
|
969
1143
|
// Generate food
|
|
970
|
-
for (int i = 0; i < num_ini_food(); ++i)
|
|
971
|
-
|
|
1144
|
+
for (int i = 0; i < num_ini_food(); ++i)
|
|
1145
|
+
{
|
|
1146
|
+
Pos p = get_random_pos_where_regenerate();
|
|
972
1147
|
grid[p.i][p.j].food = true;
|
|
973
1148
|
}
|
|
974
1149
|
}
|
|
975
|
-
|