-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathBoard.cpp
341 lines (306 loc) · 9.14 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
#include "Board.h"
#include <iostream>
#include <cstdlib> // for calculating manhattan distance; need abs()
using namespace std;
/*
default board is 3x3 1 2 * goal state: 1 2 3
definitely a better way to this 4 5 3 4 5 6
has hardcoded numbers ---------> 7 8 6 7 8 *
*/
puzzleBoard::puzzleBoard() {
vector<vector<int> > temp(3, vector<int>(3, 0));
board = temp;
goalState = temp;
row = 3;
column = 3;
hasMoved = false;
depth = 0;
move = "";
//definitely a better way of doing this
// hard code default board
board[0][0] = 1;
board[0][1] = 2;
board[0][2] = 0;
board[1][0] = 4;
board[1][1] = 5;
board[1][2] = 3;
board[2][0] = 7;
board[2][1] = 8;
board[2][2] = 6;
// hard coded goal state
goalState[0][0] = 1;
goalState[0][1] = 2;
goalState[0][2] = 3;
goalState[1][0] = 4;
goalState[1][1] = 5;
goalState[1][2] = 6;
goalState[2][0] = 7;
goalState[2][1] = 8;
goalState[2][2] = 0;
// update location of blank
xBlank = 0;
yBlank = 2;
// after populating board and storing goal state
// we can calculate the misplaced tiles & manhattan distance
misplacedTiles = calcMisplaced();
manhattanDistance = calcManhattan();
}
// define a row x column board with 0's
// definitely a better way to do this?
puzzleBoard::puzzleBoard(int row, int column){
// declare a row x column vector fill with 0
vector<vector<int> > temp(row, vector<int>(column, 0));
board = temp;
goalState = temp;
this->row = row;
this->column = column;
hasMoved = false;
depth = 0;
move = "";
// generate goal state
int counter = 1;
for(int i = 0; i < row; i++){
for(int j = 0; j < column; j++){
if(counter != (row * column)){
goalState[i][j] = counter;
counter++;
} else { // last spot is a blank
goalState[i][j] = 0;
}
}
}
}
// modify board to user input
void puzzleBoard::populateBoard() {
int input;
cout << "Enter your puzzle, use a zero to represent the blank" << endl;
for(int i = 0; i < row; i++){
cout << "Enter row " << i + 1 << ", use space between numbers:\t\t";
for(int j = 0; j < column; j++){
cin >> input;
board[i][j] = input;
if(input == 0){
xBlank = i;
yBlank = j;
}
}
}
// after populating the board we can calculate misplaced tiles & manhattan
misplacedTiles = calcMisplaced();
manhattanDistance = calcManhattan();
}
// check if board is in goal State
bool puzzleBoard::isGoalState(){
for(int i = 0; i < row; i++){
for(int j = 0; j < column; j++){
if(board[i][j] != goalState[i][j])
return false;
}
}
return true;
}
// accessors
int puzzleBoard::getRow(){ return row; }
int puzzleBoard::getColumn(){ return column; }
int puzzleBoard::getXBlank(){ return xBlank; }
int puzzleBoard::getYBlank(){ return yBlank; }
bool puzzleBoard::getHasMoved(){ return hasMoved; }
int puzzleBoard::getDepth(){ return depth; }
string puzzleBoard::getMove(){ return move; }
void puzzleBoard::setMove(string n){ move += " " + n; }
// prints n x n board
void puzzleBoard::printBoard() {
for(int i = 0; i < board.size(); i++){
for(int j = 0; j < board[i].size(); j++){
cout << board[i][j] << " ";
if(j == board[i].size() - 1){
cout << endl;
}
}
}
}
// print goal state
void puzzleBoard::printGoalState() {
for(int i = 0; i < goalState.size(); i++){
for(int j = 0; j < goalState[i].size(); j++){
cout << goalState[i][j] << " ";
if(j == goalState[i].size() - 1){
cout << endl;
}
}
}
}
// ----------------------------------------------------------------------
// operators
bool puzzleBoard::moveBlankUp(){
// if on the first row, you can't move the blank up
if(xBlank == 0){
//cout << "can't move up" << endl;
hasMoved = false;
return false;
} else {
// switch places square above
int temp = board[xBlank - 1][yBlank];
board[xBlank - 1][yBlank] = 0;
board[xBlank][yBlank] = temp;
// update blank location
xBlank -= 1;
hasMoved = true;
depth++;
if(move == "")
move = "up";
else
move += " up";
}
return true;
}
bool puzzleBoard::moveBlankDown(){
// if on the bottom row, you can't move the blank down
if(xBlank == row - 1){
//cout << "can't move down" << endl;
hasMoved = false;
return false;
} else {
// switch places square below
int temp = board[xBlank + 1][yBlank];
board[xBlank + 1][yBlank] = 0;
board[xBlank][yBlank] = temp;
// update blank location
xBlank += 1;
hasMoved = true;
depth++;
if(move == "")
move = "down";
else
move += " down";
}
return true;
}
bool puzzleBoard::moveBlankLeft(){
// if on the left column, you can't move it left
if(yBlank == 0){
//cout << "can't move left" << endl;
hasMoved = false;
return false;
} else {
// switch places square on left
int temp = board[xBlank][yBlank - 1];
board[xBlank][yBlank - 1] = 0;
board[xBlank][yBlank] = temp;
// update blank location
yBlank -= 1;
hasMoved = true;
depth++;
if(move == "")
move = "left";
else
move += " left";
}
return true;
}
bool puzzleBoard::moveBlankRight(){
// if on the right column, you can't move it right
if(yBlank == column - 1){
//cout << "can't move right" << endl;
hasMoved = false;
return false;
} else {
// switch places square on right
int temp = board[xBlank][yBlank + 1];
board[xBlank][yBlank + 1] = 0;
board[xBlank][yBlank] = temp;
// update blank location
yBlank += 1;
hasMoved = true;
depth++;
if(move == "")
move = "right";
else
move += " right";
}
return true;
}
// ----------------------------------------------------------------------
puzzleBoard& puzzleBoard::operator=(const puzzleBoard& rhs){
// HOW IS THIS THING WORKING???
// these are all private data fields??
board = rhs.board;
goalState = rhs.goalState;
row = rhs.row;
column = rhs.column;
xBlank = rhs.xBlank;
yBlank = rhs.yBlank;
depth = rhs.depth;
hasMoved = hasMoved;
move = rhs.move;
return *this;
}
bool puzzleBoard::operator==(const puzzleBoard& rhs) const{
for(int i = 0; i < row; i++){
for(int j = 0; j < column; j++){
if(board[i][j] != rhs.board[i][j])
return false;
}
}
return true;
}
// calculates # of misplaced tiles
// g(n) = depth/cost, h(n) = # of misplaced tiles
int puzzleBoard::calcMisplaced(){
misplacedTiles = 0;
// iterate through the current board and compare [i][j] with the goal state
// if it's different then increment misplace tiles.
for(int i = 0; i < row; i++){
for(int j = 0; j < column; j++)
// don't count blanks as one
if(board[i][j] != 0 && board[i][j] != goalState[i][j]){
misplacedTiles++;
}
}
//cout << "misplaced Tiles: " << misplacedTiles << endl;
return misplacedTiles;
}
// calculates manhattan distance
// f(n) = g(n) + h(n); g(n) = depth/cost to get to node h(n) = manhattan distance
int puzzleBoard::calcManhattan(){
manhattanDistance = 0;
// add vertical + horizontal lengths
// manhattan distance is subtracting distance and add the absolute value of
// x and y together
/* current goal(x1,y1) 0 is at (0, 0), it should be at (2,2).
0 1 2 1 2 3 | x1 - x | = | 2 - 0 | = 2
4 5 3 4 5 6 | y1 - y | = | 2 - 0 | = 2
7 8 6 7 8 0 2 + 2 = 4; so the manhattan distance is 4
x1 = (value - 1) / row
i.g. value 6, row size = 3. we know it's gonna be on second row
y1 = i + j + i + (i + 1)
i.g. for 3x3: 6 is at (1,2) so 6 = 1 + 2 + 1 + (1 + 1) = 6
I wrote out value / indexes and tried to find a pattern
I mean technically I didn't prove this is right for ever input
...but I think it is?
alternative is to use 4 nested loop to iterate through board to get index
then iterate through the goalState to get the correct index
*/
int x1, y1 = 0;
for(int i = 0; i < row; i++){
for(int j = 0; j < column; j++){
// don't want to include blank space
if(board[i][j] != 0 && board[i][j] != goalState[i][j]){
// calculate index of value in goal state
x1 = (board[i][j] - 1) / row;
y1 = board[i][j] - (3 * x1) - 1;
//out << board[i][j] << " index: " << x1 << " " << y1 << endl;
manhattanDistance += abs(x1 - i) + abs(y1 - j);
//cout << "manhattanDistance: " << manhattanDistance << endl;
}
}
}
return manhattanDistance;
}
// calculate the heurstic so misplaced + depth
int puzzleBoard::getMisplacedHeurstic(){
return calcMisplaced() + depth;
}
int puzzleBoard::getManhattanHeurstic(){
return calcManhattan() + depth;
}