forked from JKomskis/GameOfLife
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Board.cpp
374 lines (327 loc) · 8.76 KB
/
Board.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
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
#include "Board.h"
using namespace std;
//a constructor for the Board class if height, width, and wraparound options are chosen
Board::Board(bool wrap, int h, int w): matrix(h, vector<bool> (w, 0))
{
this->height = h;
this->width = w;
this->wrapAround = wrap;
this->iterations = 0;
this->births = 0;
this->deaths = 0;
isSaved = true;
birthRule = {3,};
survivalRule = {2, 3,};
}
//a constructor for the board class if just a filename is given
Board::Board(string filename)
{
BoardData data = loadFormat(filename);
height = data.height;
width = data.width;
wrapAround = data.wrapAround;
iterations = data.iterations;
births = data.births;
deaths = data.deaths;
isSaved = true;
matrix = data.matrix;
birthRule = data.birthRule;
survivalRule = data.survivalRule;
}
void Board::toggle(int r, int c) //toggles the cell from true to false or false to true
{
matrix[r][c] = !matrix[r][c];
isSaved = false;
}
//allows a board to be randomly generated
void Board::randomize(double ratio)
{
ratio = (ratio < 0) ? 0 : ratio;
ratio = (ratio > 1) ? 1 : ratio;
for (int r = 0; r < height; r++)
{
for (int c = 0; c < width; c++)
{
if (((double)rand()/RAND_MAX) <= ratio)
{
toggle(r, c);
}
}
}
}
//counts how many live neighbours a given cell has
int Board::numNeigh(int r,int c)
{
/*creating a count variable, setting it equal to -1 if cell is alive (thus
avoiding counting it twice)*/
int count = ((matrix[r][c]) ? -1 : 0);
if (wrapAround)
{
for (int i = r-1; i <= r+1; i++)
{
for (int j = c-1; j <= c+1; j++)
{
//std::cout << "r+i " << r+i << "c+j " << c+j <<std::endl;
if ( matrix[((i < 0) ? height+i : i) % height][((j < 0) ? width + j : j) % width])
count++;
}
}
}
/*neighbor count nested for loops for wrapAround = false
the ternary operators are used to detect when the cell is on the edge of
the board*/
else {
for (int i = ((r == 0) ? 0: r - 1); i <= ((r == height - 1 ) ? r:r+1); i++)
{
for (int j = ((c == 0) ? 0: c - 1); j <= ((c == width - 1) ? c:c+1); j++)
{
//std::cout << "r+i " << r+i << "c+j " << c+j <<std::endl; //for testing purposes
if (matrix[i][j])
count++;
}
}
}
//std::cout << "count:" << count <<endl; //for testing purposes
return count;
}
//runs one iteration (for example, when the user presses the "Enter" key in the GameOfLife)
void Board::runIteration()
{
int **nMatrix = new int*[height]; //creates a new matrix
for (int i = 0; i < height; i++) //make the second dimension of the matrix
{
nMatrix[i] = new int[width];
}
for(int r = 0; r < height; r++) //gets the numvber of live neighbours
{
for(int c = 0; c < width; c++)
{
nMatrix[r][c] = numNeigh(r, c);
//std::cout << nMatrix[r][c] << " ";
}
//std::cout << endl;
}
//std::cout << "Now we are looking at if the cells do what they are supposed to:\n";
for(int r = 0; r < height; r++) //runs logic based on whether or not a cell is alive and how many live neighbours it has
{
for(int c = 0; c < width; c++)
{
if(matrix[r][c] == 1) //if the cell is alive (equal to 1)
{
if(survivalRule.find(nMatrix[r][c]) == survivalRule.end())
{
toggle(r, c);
deaths++;
}
}
else //if the cell is dead (equal to 0)
{
if(birthRule.find(nMatrix[r][c]) != birthRule.end())
{
toggle(r, c);
births++;
}
}
}
}
for (int i = 0; i < height; i++) //delete the matrix that held how many neighbours the cell had (saves space)
{
delete nMatrix[i];
}
delete nMatrix;
iterations++;
}
void Board::runIteration(int runs) //runs the interation the correct number of times
{
for(int i = 0; i < runs; i++)
{
runIteration();
//std::cout << "This is the matrix after " << i + 1 << " iterations.\n"; //for testing purposes
//getMatrix();
//cout << endl;
}
}
//returns the matrix
vector<vector<bool>>& Board::getMatrix()
{
return this->matrix;
}
//prints the board as a matrix of 1s and 0s
//very useful for testing purposes
void Board::printBoard()
{
for(auto row : matrix)
{
for(auto cell : row)
cout << cell << " ";
cout << endl;
}
cout << "Birth Rule: " << set2rule(birthRule) << endl;
cout << "Survival Rule: " << set2rule(survivalRule) << endl;
cout << endl;
}
//save a given state or board, given a name for the file
void Board::saveState(string fileName)
{
ofstream out(fileName);
out << height << endl; //first line tells the program the height of the saved matrix
out << width << endl; //second line tells the program the width of the saved matrix
out << wrapAround << endl; //third line tells the program if wrapAround was true or not
out << iterations << endl; //tells the program how many iterations there were
out << births << endl; //how many births there were
out << deaths << endl; //how many deaths there were
out << set2rule(birthRule) << endl; //rule for cells to spawn
out << set2rule(survivalRule) << endl; //rule for cells to live
for (int i = 0; i < height; i++) //tells the program what the matrix actually looked like
{
for (int j = 0; j < width; j++)
{
out << matrix[i][j];
}
out << "\n";
}
out.close();
}
//allows the user to add an existing pattern to the board by calling with the filename, along with an x and y position
void Board::addPattern(string fileName, int x, int y)
{
ifstream in;
in.open(fileName);
//check if the file was able to be opened
if (!in.is_open())
{
cerr << "File not opened" << endl;
}
int heightOfSaved = 0;
int widthOfSaved = 0;
string line;
heightOfSaved = fs_atoi(in);
widthOfSaved = fs_atoi(in);
//initialize new patternMatrix
bool **patternMatrix = new bool *[heightOfSaved];
for(int i = 0; i < heightOfSaved; i++)
{
patternMatrix[i] = new bool[widthOfSaved];
}
//store file values into the patternMatrix
int row = 0;
while(getline(in, line))
{
for(int i = 0; i <widthOfSaved; i++)
{
patternMatrix[row][i] = line.at(i) == '1';
}
row++;
}
// 4/3/17 - JJK - Bad logic here - now fixed
//check if the pattern will fit in the pattern matrix
if((heightOfSaved + y) > height || (widthOfSaved + x) > width)
{
cerr << "Saved Pattern is larger than board" << endl;
}
// pretty sure there's a bug here - 4/6/17 JJK
// x is supposed to be horizontal
// used to access the y component of the matrix
for(int i = 0; i < heightOfSaved; i++)
for(int j = 0; j < widthOfSaved; j++)
matrix[x+i][y+j] = patternMatrix[i][j];
in.close();
}
//allows the user to add an existing pattern to the board by calling with the actual bool matrix, along with an x and y position
void Board::addPattern(vector<vector<bool>> patternMatrix, int y, int x)
{
for(size_t i = 0; i < patternMatrix.size(); i++)
{
for(size_t j = 0; j < patternMatrix[0].size(); j++)
{
matrix[(y + i) % matrix.size()][(x + j) % matrix[0].size()] = patternMatrix[i][j];
}
}
}
//returns the height of the board
int Board::getHeight()
{
return height;
}
//returns the width of the board
int Board::getWidth()
{
return width;
}
//returns the number of iterations that were run
int Board::getIterations()
{
return iterations;
}
//returns the number of births that occurred
int Board::getBirths()
{
return this->births;
}
//returns the number of deaths that occurred
int Board::getDeaths()
{
return deaths;
}
//returns a boolean value of if the board has been saved
bool Board::getIsSaved()
{
return isSaved;
}
void Board::setBirthRule(set<int> input)
{
birthRule = input;
}
void Board::setSurvivalRule(set<int> input)
{
survivalRule = input;
}
string Board::getBirthRule()
{
return set2rule(birthRule);
}
string Board::getSurvivalRule()
{
return set2rule(survivalRule);
}
//Used for testing purposes
/*
int main()
{
int height;
int width;
cout << "Height of board: ";
cin >> height;
cout << "Width of board: ";
cin >> width;
cout << "Add a board called test\n";
Board test(false, height, width);
cout << "Print out the matrix:\n";
test.printBoard();
cout << endl;
cout << "Add a pattern called patterntest.txt and then print out the matrix\n";
test.addPattern("patterntest.txt", 1, 1);
test.printBoard();
cout << endl;
//test.getMatrix();
//cout << endl;
cout << "Try running the runIteration function: \n";
test.runIteration();
cout << "This is the matrix now\n";
test.printBoard();
cout << endl;
test.runIteration(3);
cout << "This is the matrix after 3 runIterations\n";
test.printBoard();
cout << endl;
cout << "Random Board\n";
test.randomize();
test.printBoard();
cout << endl;
while (true)
{
test.runIteration(100);
}
return 0;
}
*/