Skip to content

Commit 6a5d25e

Browse files
author
Kate Lovett
committed
initial commit
1 parent 1a20cb6 commit 6a5d25e

File tree

4 files changed

+420
-0
lines changed

4 files changed

+420
-0
lines changed

Makefile

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
ola1: a-star.cpp random_board.cpp
2+
g++ -o a-star a-star.cpp
3+
g++ -o random_board random_board.cpp
4+
5+
clean:
6+
rm -f a-star
7+
rm -f random_board
8+
rm -f *.o

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
# AStarPuzzleSolving
22
Implementing an a-star algorithm to solve a sliding tile puzzle game.
3+
4+
Intended use for these two programs is to generate a random, scrambled state with random_board, and pipe output into a-star to solve.
5+
The solution provided by a-star should result in the (same/fewer) number of moves given to the random board generator.

a-star.cpp

+284
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
// Kate Lovett
2+
// a-star.cpp
3+
// September 2017
4+
// This program reads in the current state of an 8-piece puzzle board from stdin.
5+
// It then utilizes the a-star algorithm to solve the puzzle, based on the
6+
// goal state 0,1,2,3,4,5,6,7,8. The 0 tile represents an empty space, which
7+
// allows the other tiles to move.
8+
// This program takes one command line argument, which determines the heuristic.
9+
// Once the goal has been found, the program will print the total # of nodes
10+
// visited, the max # of nodes stored in memory, the depth of the optimal solution,
11+
// the approximate effective branching factor, and the board's states from the
12+
// start to the goal.
13+
14+
#include <iostream>
15+
#include <queue>
16+
#include <vector>
17+
#include <cmath>
18+
#include <algorithm>
19+
#include <stack>
20+
#include <string>
21+
#include <set>
22+
using namespace std;
23+
24+
struct node{
25+
int idNum;
26+
string boardConfig;
27+
string parentConfig;
28+
int gN;
29+
int hN;
30+
int fN;
31+
char searchType;
32+
33+
// These two operator functions serve as the method for the closed set
34+
// to search and compare boards.
35+
bool operator<(const node& rhs) const{
36+
return boardConfig < rhs.boardConfig;
37+
}
38+
39+
bool operator==(const node& rhs) const{
40+
return boardConfig == rhs.boardConfig;
41+
}
42+
};
43+
44+
// This small class serves as the method for the frontier prioity
45+
// queue to compare and organize itself.
46+
class pqComp{
47+
public:
48+
pqComp(){}
49+
bool operator() (const node& lhs, const node& rhs) const{
50+
if(lhs.fN != rhs.fN){
51+
return lhs.fN > rhs.fN;
52+
}
53+
else{
54+
return lhs.idNum < rhs.idNum;
55+
}
56+
}
57+
};
58+
59+
int calcHN(int hMethod, string board);
60+
string swap(int a, int b, string board); //Non-destructive
61+
bool costComp(node a, node b);
62+
void printBoard(string boardConfig);
63+
64+
int main(int argc, char *argv[]){
65+
66+
priority_queue<node, vector<node>, pqComp> frontier;
67+
set<node> closed;
68+
stack<string> solution;
69+
int hMethod = atoi(argv[1]);
70+
string goal = "012345678";
71+
int nodeCounterV = 1;
72+
int idCounter = 0;
73+
74+
string temp;
75+
76+
node currentNode;
77+
currentNode.parentConfig = "";
78+
currentNode.idNum = 0;
79+
currentNode.boardConfig = "";
80+
for(int i =0; i < 9; i++){
81+
cin >> temp;
82+
currentNode.boardConfig += temp;
83+
}
84+
currentNode.gN = 0;
85+
currentNode.hN = calcHN(hMethod, currentNode.boardConfig);
86+
currentNode.fN = currentNode.gN + currentNode.hN;
87+
88+
frontier.push(currentNode);
89+
90+
while(currentNode.boardConfig!=goal){ // This will detect the goal, leaving the currentBoard as the solution at exit of loop
91+
92+
nodeCounterV += 1;
93+
94+
// If the goal has not been found, find out where zero is
95+
int zeroIndex = currentNode.boardConfig.find("0");
96+
97+
98+
// Add current node to the closed list and remove from the frontier.
99+
closed.insert(frontier.top());
100+
101+
frontier.pop();
102+
103+
104+
// Find next nodes + fn -> add to frontier after checking against the closed list
105+
// Testing for moves working clockwise around the current location of the empty tile.
106+
107+
if(zeroIndex - 3 >= 0){ // Up
108+
node newNode;
109+
newNode.boardConfig = swap(zeroIndex, zeroIndex-3, currentNode.boardConfig);
110+
111+
if(closed.find(newNode) == closed.end()){
112+
113+
idCounter += 1;
114+
newNode.idNum = idCounter;
115+
116+
newNode.parentConfig = currentNode.boardConfig;
117+
118+
newNode.gN = currentNode.gN + 1;
119+
newNode.hN = calcHN(hMethod, newNode.boardConfig);
120+
newNode.fN = newNode.hN + newNode.gN;
121+
122+
frontier.push(newNode);
123+
}
124+
}
125+
126+
if(zeroIndex + 3 <= 8){ // Down
127+
node newNode;
128+
newNode.boardConfig = swap(zeroIndex, zeroIndex+3, currentNode.boardConfig);
129+
130+
if(closed.find(newNode) == closed.end()){
131+
132+
idCounter += 1;
133+
newNode.idNum = idCounter;
134+
135+
newNode.parentConfig = currentNode.boardConfig;
136+
137+
newNode.gN = currentNode.gN + 1;
138+
newNode.hN = calcHN(hMethod, newNode.boardConfig);
139+
newNode.fN = newNode.hN + newNode.gN;
140+
141+
frontier.push(newNode);
142+
}
143+
}
144+
145+
if((zeroIndex != 0)&&(zeroIndex!=3)&&(zeroIndex != 6)){
146+
node newNode; // Left
147+
newNode.boardConfig = swap(zeroIndex, zeroIndex-1, currentNode.boardConfig);
148+
149+
if(closed.find(newNode) == closed.end()){
150+
151+
idCounter += 1;
152+
newNode.idNum = idCounter;
153+
154+
newNode.parentConfig = currentNode.boardConfig;
155+
156+
newNode.gN = currentNode.gN + 1;
157+
newNode.hN = calcHN(hMethod, newNode.boardConfig);
158+
newNode.fN = newNode.hN + newNode.gN;
159+
160+
frontier.push(newNode);
161+
}
162+
}
163+
164+
if((zeroIndex != 2)&&(zeroIndex!=5)&&(zeroIndex != 8)){
165+
node newNode; // Right
166+
newNode.boardConfig = swap(zeroIndex, zeroIndex+1, currentNode.boardConfig);
167+
168+
if(closed.find(newNode) == closed.end()){
169+
170+
idCounter += 1;
171+
newNode.idNum = idCounter;
172+
173+
newNode.parentConfig = currentNode.boardConfig;
174+
175+
newNode.gN = currentNode.gN + 1;
176+
newNode.hN = calcHN(hMethod, newNode.boardConfig);
177+
newNode.fN = newNode.hN + newNode.gN;
178+
179+
frontier.push(newNode);
180+
}
181+
}
182+
183+
184+
// Choose next move & continue to solve
185+
currentNode = frontier.top();
186+
187+
// End of while loop
188+
}
189+
190+
191+
// Backtrack to find the solution path
192+
while(currentNode.parentConfig != ""){
193+
//printBoard(currentNode.boardConfig);
194+
//cout << endl;
195+
solution.push(currentNode.boardConfig);
196+
currentNode.boardConfig = currentNode.parentConfig;
197+
currentNode = *closed.find(currentNode);
198+
}
199+
// Push the final board (should be starting board) onto stack.
200+
solution.push(currentNode.boardConfig);
201+
202+
unsigned long n = frontier.size() + closed.size(); // Calculates N and d.
203+
unsigned long d = solution.size()-1;
204+
205+
cout << "V=" << nodeCounterV << endl; // Outputs data followed by each state
206+
cout << "N=" << n << endl; // along the optimal path to the goal.
207+
cout << "d=" << d << endl;
208+
cout << "b=" << pow(n, 1.0/d) << endl << endl << endl;
209+
210+
211+
// cout << "Printing solution: " << endl << endl;
212+
for(int i = 0; i <= d; i ++){
213+
printBoard(solution.top());
214+
solution.pop();
215+
cout << endl << endl;
216+
}
217+
218+
219+
return 0;
220+
}
221+
222+
string swap(int a, int b, string board){
223+
char temp = board[a];
224+
board[a] = board[b];
225+
board[b] = temp;
226+
return board;
227+
}
228+
229+
int calcHN(int hMethod, string board){
230+
int cost1 = 0;
231+
int cost2 = 0;
232+
int initialX, initialY, targetX, targetY;
233+
234+
for(int i = 0 ; i < 9; i++){
235+
236+
int tile = board[i] - '0';
237+
if((tile!=0)&&(tile != i)){
238+
239+
// for hN == 1
240+
cost1 += 1;
241+
242+
// for hN == 2
243+
int targetY = (int)tile/3;
244+
int initialY = (int)i/3;
245+
int diffY = abs(targetY-initialY);
246+
247+
if((i == 0)||(i == 3)||(i == 6)){
248+
initialX = 0;
249+
}
250+
else if((i == 1)||(i == 4)||(i == 7)){
251+
initialX = 1;
252+
}
253+
else{
254+
initialX = 2;
255+
}
256+
257+
if((tile == 0)||(tile == 3)||(tile == 6)){
258+
targetX = 0;
259+
}
260+
else if((tile == 1)||(tile == 4)||(tile == 7)){
261+
targetX = 1;
262+
}
263+
else{
264+
targetX = 2;
265+
}
266+
267+
int diffX = abs(targetX-initialX);
268+
269+
cost2 += diffY + diffX;
270+
}
271+
}
272+
273+
if(!hMethod) { return 0; }
274+
else if(hMethod == 1) { return cost1; }
275+
else if(hMethod == 2) { return cost2; }
276+
else { return ((cost2 + cost1)/2); }
277+
}
278+
279+
void printBoard(string boardConfig){
280+
281+
for(int i = 0; i < 9; i+=3){
282+
cout << boardConfig[i] << ' ' << boardConfig[i+1] << ' ' << boardConfig[i+2] << endl;
283+
}
284+
}

0 commit comments

Comments
 (0)