-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBoard.cpp
376 lines (345 loc) · 9.18 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
375
376
/*
Title: Helper2 (CPSC 427)
Date: 07-December-2012
File: Board.cpp
Author: Rosie Buchanan
Version: 7.0
Helper: Sudoku helper application that can be run by a user from the command line that will let him or her interactively solve a Sudoku puzzle. The program stores information for a sudoku board by storing information for the individual sudoku squares. Information stored for each square includes row and column position within the board, the possibility set of marks, the current mark, and whether or not the mark is immutable. Additional information is stored for the board itself: the number of rows, the number of columns, and the total number of squares. Clusters, a set of squares that must be filled in with distinct marks, has been introduced. This program handles three types of classical Sudoku clusters: rows, columns and squares. Each time a mark is recorded for a square, the mark is removed from the possibility sets of the the other squares in each of the clusters it is contained in. The board now prints the Board nicely using Unicode characters (U+2500 code chart). Users are able to use undo and redo functions, and add or erase individual marks.
Board: Represents a Sudoku board with constant data members that contain the number of rows, number of columns, and the total number of squares. It has a constant data member pointer that points to a dynamically allocated array of BSquares. Board maintains a master list of all cluster objects.
*/
#include "tools.hpp"
#include "Cluster.hpp"
//reads board from file, stores marks
//if invalid file, no memory leak
bool Board::readMarks(string boardFile)
{
bool success = true;
ifstream inFile(boardFile.c_str()); //open stringname as file
//check valid file
if (!inFile)
{
cout << "Error: Can't open board file " << boardFile;
success = false;
}
else
{
int currRow = 1; // reading row index
int currCol = 1; // reading col index
char store; // for reading in file chars
int storeInt = 0; // for storing corresponding ints
int subsc = 0;
while(!inFile.eof())
{
inFile >> store;
//check for blank mark and store appropriately
if (store == '-')
{
storeInt = -1;
}
//store mark as int
else
{
storeInt = (store - '0');
}
//calculate linear subscript array position
subsc = sub(currRow, currCol);
//set initial mark
//if (storeInt != -1) {brd[subsc].BSquare::clear(); }
success = brd[subsc].BSquare::setInitialMark(storeInt);
if (success == false) {return success;}
//stop reading after last square is read
if ((currRow == rows) && (currCol == cols)) {break;}
//move on to next row once encounter last square in column
if (currCol == cols)
{
currCol = 1;
currRow++;
}
//move on to square in next column if currCol is not the last one
else
{
currCol++;
}
}
if (!isStillPossible())
{
cout << "Board is not solvable" << endl;
success = false;
return success;
}
else
{
clearPossSets();
}
}
return success;
}
//construct Board with nr rows, nc columns, assigns correct row and column indices
//memory leaks now impossible
Board::Board(int nr, int nc): rows(nr), cols(nc), total(nr*nc)
{
brd = (new BSquare[nr*nc]);
int i = 0;
int currRow = 1; // reading row index
int currCol = 1; // reading col index
while (i < (nr*nc))
{
brd[i].BSquare::setCoordinates(currRow, currCol);
if (currCol == nc)
{
currRow++;
currCol = 1;
}
else
{
currCol++;
}
i++;
}
//create clusters
makeRowClusters();
makeColClusters();
makeBoxClusters();
}
//calculate linear subscript between 0 and (total-1) for Bsquare in position (r,c)
int Board::sub(int r, int c) const
{
int rowMultiplier = (r-1)*cols; //account for row number and 0-indexing
int subscript = rowMultiplier+(c-1);
return subscript;
}
// writes current board marking to stream out in the same format as is used by the Board constructor when creating the Board
ostream& Board::writeMarks(ostream& out) const
{
out << "Writing the marks:" << endl;
int currRow = 1; // current column index
int currCol = 1; // current row index
int subsc = 0; // current square index of Board
while (currRow <= rows && currCol <= cols) // still inside bounds of Board
{
// test for blank mark by using getMark() method in Square class
if (brd[subsc].Square::getMark() == -1)
{
out << "-"; // output symbol for blank
}
// square is not blank
else
{
out << brd[subsc].Square::getMark(); // output mark
}
// test for reaching end of row and move on to beginning of next row
if (currCol == cols)
{
out << "\n";
currCol = 1;
currRow++;
}
else
{
currCol++; // move to next square
}
subsc++; // increment Board square
}
return out;
}
// print function that prints the dimensions of the board of the first line
// followed by one line for each square of the board
ostream& Board::print(ostream& out) const
{
for (int i = 0; i < total; i++) // loops through all the squares
{
brd[i].BSquare::print(out); // print information for each Square
out << endl; // move to next line
}
//print cluster information
// one line per cluster containing the coordinates of squares included
out << "Clusters:";
for (unsigned int i = 0; i < clu.size(); i++)
{
out << "\n" << *clu[i];
}
out << "\n" << endl;
return out;
}
//store list of all row clusters
void Board::makeRowClusters()
{
BSquare* temp[9];
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
temp[j] = &brd[sub(i+1,j+1)]; //store in temp array
}
//create new cluster from temp
clu.push_back(new Cluster(Cluster::ROW, i+1, cols, temp));
}
}
//store list of all column clusters
void Board::makeColClusters()
{
BSquare* temp[9];
int i = 0;
int j = 0;
for (i = 0; i < cols; i++)
{
for (j = 0; j < rows; j++)
{
temp[j] = &brd[sub(j+1,i+1)]; //store in temp array
}
//create new cluster from temp
clu.push_back(new Cluster(Cluster::COL, i+1, rows, temp));
}
}
//store list of all box clusteres
void Board::makeBoxClusters()
{
BSquare* temp[9];
//determine number of horizontal box clusters
int numHorClu;
if (rows % 3 == 0)
{
numHorClu = rows/3;
}
else
{
numHorClu = (rows/3) + 1;
}
//determine number of vertical box clusters
int numVerClu;
if (cols % 3 == 0)
{
numVerClu = cols/3;
}
else
{
numVerClu = (cols/3) + 1;
}
//loop indices
int i = 0;
int j = 0;
int k;
int l;
int count = 0;
//loop through clusters
for (i = 0; i < numHorClu; i++)
{
for (j = 0; j < numVerClu; j++)
{
count = 0; //counter
//loop through squares in cluster
for (k = 1+(3*i); k < 1+(3*(i+1)) && k <= rows; k++)
{
for (l = 1+(3*j); l < 1+(3*(j+1)) && l <= cols; l++)
{
temp[count] = &brd[sub(k,l)]; //store in temp array
count++;
}
}
//create new cluster from temp
clu.push_back(new Cluster(Cluster::BOX, 1+(3*i)+j, count, temp));
}
}
}
//delete clusters
Board::~Board()
{
//delete board
delete[] brd;
unsigned int i = 0;
//delete individual clusters
for (i = 0; i<clu.size(); i++)
{
delete clu[i];
}
}
//returns true if all unmarked squares have non-empty possibility lists
bool Board::isStillPossible() const
{
bool isStillPossible = true;
for (int i = 0; i < total; i++) // loops through all the squares
{
if (brd[i].BSquare::isBlank()) //blank square
{
if (brd[i].BSquare::somePossible() != true) //no possibilities
{
isStillPossible = false;
}
}
}
return isStillPossible;
}
// returns mark at given row and column of board
int Board::boardGetMark(int row, int col) const
{
int sub = Board::sub(row, col); //calculate index
return brd[sub].BSquare::getMark();
}
//returns possibility set of given row and column of board
string Board::boardGetPossString(int row, int col) const
{
int sub = Board::sub(row, col); //calculate index
string possString = brd[sub].BSquare::getPossible();
return possString;
}
//unset possible mk from square at (row, col)
void Board::boardUnsetPoss(int row, int col, int mark)
{
int sub = Board::sub(row, col); //calculate index
brd[sub].BSquare::unsetPossible(mark);
}
//initializes board to empty, with all marks possible
void Board::initializeBoard()
{
//initialze every square of board
for (int i = 0; i < total; i++)
{
brd[i].initializeSquare();
}
}
//sets mark m at (r,c) and returns bool representing successfulness
bool Board::boardSetMark(int r, int c, int m)
{
bool markSet = false;
int index = sub(r, c); //calculate index
//square already marked
if (brd[index].getMark() != -1)
{
cout << "Error: Attempt to mark already-marked square" << endl;
}
//square can be marked, mark square
else if (brd[index].BSquare::isPossible(m))
{
brd[index].setMark(m);
markSet = true;
}
//mark not in possibility set
else
{
cout << "Mark " << m << " not possible in square " << brd[index].stringName() << endl;
}
return markSet;
}
//copies square s to board at given index
void Board::copySquare(int index, Square s)
{
brd[index].Square::copySquare(s);
}
//clears the possibility sets for marked squares of the board
Square Board::getSquare(int i)
{
return brd[i];
}
//clears the possibility sets for marked squares of the board
void Board::clearPossSets()
{
for (int i = 0; i < total; i++)
{
if (brd[i].getMark() != -1)
{
brd[i].clear();
}
}
}