Skip to content

Commit 18843f8

Browse files
pushinig the project
1 parent d86ef04 commit 18843f8

File tree

7 files changed

+365
-1
lines changed

7 files changed

+365
-1
lines changed

Nodes.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
1.000000000000000000e+00 4.000000000000000000e+00 0.000000000000000000e+00 2.000000000000000000e+00 5.000000000000000000e+00 7.000000000000000000e+00 3.000000000000000000e+00 6.000000000000000000e+00 8.000000000000000000e+00
2+
1.000000000000000000e+00 0.000000000000000000e+00 4.000000000000000000e+00 2.000000000000000000e+00 5.000000000000000000e+00 7.000000000000000000e+00 3.000000000000000000e+00 6.000000000000000000e+00 8.000000000000000000e+00
3+
1.000000000000000000e+00 4.000000000000000000e+00 7.000000000000000000e+00 2.000000000000000000e+00 5.000000000000000000e+00 0.000000000000000000e+00 3.000000000000000000e+00 6.000000000000000000e+00 8.000000000000000000e+00
4+
0.000000000000000000e+00 1.000000000000000000e+00 4.000000000000000000e+00 2.000000000000000000e+00 5.000000000000000000e+00 7.000000000000000000e+00 3.000000000000000000e+00 6.000000000000000000e+00 8.000000000000000000e+00
5+
1.000000000000000000e+00 5.000000000000000000e+00 4.000000000000000000e+00 2.000000000000000000e+00 0.000000000000000000e+00 7.000000000000000000e+00 3.000000000000000000e+00 6.000000000000000000e+00 8.000000000000000000e+00
6+
1.000000000000000000e+00 4.000000000000000000e+00 7.000000000000000000e+00 2.000000000000000000e+00 0.000000000000000000e+00 5.000000000000000000e+00 3.000000000000000000e+00 6.000000000000000000e+00 8.000000000000000000e+00
7+
1.000000000000000000e+00 4.000000000000000000e+00 7.000000000000000000e+00 2.000000000000000000e+00 5.000000000000000000e+00 8.000000000000000000e+00 3.000000000000000000e+00 6.000000000000000000e+00 0.000000000000000000e+00

NodesInfo.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
1.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00
2+
2.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00
3+
3.000000000000000000e+00 1.000000000000000000e+00 1.000000000000000000e+01
4+
4.000000000000000000e+00 1.000000000000000000e+00 1.000000000000000000e+01
5+
5.000000000000000000e+00 2.000000000000000000e+00 1.000000000000000000e+01
6+
6.000000000000000000e+00 2.000000000000000000e+00 1.000000000000000000e+01

README.md

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,87 @@
11
# 8-Puzzle-Solver-using-BFS-Algorithm
2-
A solver to to find all the possible states of the 8-Puzzle and reach a user defined goal.
2+
3+
## Project Description
4+
5+
An instance of the 8-puzzle game consists of a board holding 8 distinct movable tiles ans empty space. For such a board, the empty space may be legally swapped with any tile horizontally or vertically adjacent to it. In this project, we are given an initial state of the puzzle, the search problem is to find a sequence of moves that transitions this state to the goal state; that is, the configuration with all tiles arranged in ascending order 0,1,2,3,4,5,6,7,8 or 8,7,6,5,4,3,2,1,0 or anyother user defined goal state.
6+
7+
## Objective
8+
9+
Use the Breadth First Search (BFS) Algorithm to solve the 8 puzzle. The slider should swap the empty space with a number to create a unique state. We need to make sure that no state is repeated so as to avoid infinite looping.
10+
11+
* **Breadth First Search (BFS)** : It is a traversing algorithm where you should start traversing from a selected node (source or starting node) and traverse the graph layerwise thus exploring the neighbour nodes (nodes which are directly connected to source node).
12+
* **Distance Metric** : Again, an abstract module to allow re-use, it includes the required distance metric that is Manhattan distance. Here Manhattan Distance is used because the slider either moves up, down, right or left for about one unit and not more than that. It also won't slide in any other angles directions i.e; diagonally.
13+
* **Unique State Checker** : We implement a set data structure to store all existing states. We will write an algorithm such that every unique state that is being entered into the set will be compared to all other existing states to avoid repitition.
14+
15+
## Contents
16+
17+
## Instructions for Usage
18+
19+
1. Clone the repository
20+
21+
```
22+
git clone https://github.com/bharadwaj-chukkala/8-Puzzle-Solver-using-BFS-Algorithm.git
23+
```
24+
25+
2. Install Python 3.9 and the libraries mentinoned below prior to running the code
26+
3. Go to the root directory from your IDE.
27+
4. Please mention the path to the datasets wherever necessary.
28+
5. Run the `Solver.py` file as it is.
29+
6. `Nodes.txt` will contain all possible states
30+
7. `nodePath.txt` will contain the generated path to the goal from initial state
31+
8. `NodesInfo.txt` will contain the information about child states, parent states and **cost2come**
32+
9. Note: if dataset and results are not given, please paste the py file in the folder where dataset is present and also create a results folder in the directory where you run the code.
33+
34+
### Dependencies
35+
36+
* NumPy
37+
* argparse
38+
39+
## Results
40+
I have defined the initial state and goal state as follows:
41+
<table style="width:50%">
42+
<tr>
43+
<td align="center"> Initial State </td>
44+
<td align="center"> ➡️</td>
45+
<td align="center"> Goal State</td>
46+
<tr>
47+
<td>
48+
<table style="width:80%" align="center">
49+
<tr>
50+
<td>8</td> <td> </td> <td>6</td>
51+
</tr>
52+
<tr>
53+
<td>5</td> <td>4</td> <td>7</td>
54+
</tr>
55+
<tr>
56+
<td>2</td> <td>3</td> <td>1</td>
57+
</tr>
58+
</table>
59+
</td>
60+
<td align="center"> should <br> change to </td>
61+
<td>
62+
<table style="width:80%" align="center">
63+
<tr>
64+
<td>1</td> <td>2</td> <td>3</td>
65+
</tr>
66+
<tr>
67+
<td>4</td> <td>5</td> <td>6</td>
68+
</tr>
69+
<tr>
70+
<td>7</td> <td>8</td> <td></td>
71+
</tr>
72+
</table>
73+
</td>
74+
</table>
75+
76+
## License
77+
78+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
79+
80+
## Contact
81+
82+
**Bharadwaj Chukkala** `<br>`
83+
UID: 118341705 `<br>`
84+
Bharadwaj Chukkala is currently a Master's student in Robotics at the University of Maryland, College Park, MD (Batch of 2023). His interests include Machine Learning, Perception and Path Planning for Autonomous Robots.`<br>`
85+
[![Contact](https://img.shields.io/badge/Gmail-D14836?style=for-the-badge&logo=gmail&logoColor=white)]([email protected])
86+
[![LinkedIn](https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/in/bharadwaj-chukkala/)
87+
[![GitHub](https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white)](https://github.com/bharadwaj-chukkala)

Solver.py

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
import numpy as np
2+
import argparse
3+
4+
##### To read the user input #####
5+
6+
def read(configuration):
7+
initial_state = []
8+
data = configuration.split(",")
9+
for element in data:
10+
initial_state.append(int(element))
11+
return np.reshape(initial_state,(3,3))
12+
13+
14+
##### Blank Tile Position #####
15+
def zeropos(Initial_state):
16+
index = np.argwhere(Initial_state == 0) #we get the position of zero in initial state
17+
return index
18+
19+
20+
##### Action set : Move UP #####
21+
def move_up(Curr_state):
22+
A = np.copy(Curr_state)
23+
loc = zeropos(A) #moving the slider up if possible
24+
i = loc[:,0]
25+
j= loc[:,1]
26+
if i-1<0:
27+
status = False
28+
return A, status
29+
else:
30+
#print("UP")
31+
A[i,j]= A[i-1, j]
32+
A[i-1, j] = 0
33+
status = True
34+
#print(A)
35+
return A, status
36+
37+
##### Action set : Move Down #####
38+
def move_down(Curr_state):
39+
A = np.copy(Curr_state)
40+
loc = zeropos(A)
41+
42+
i = loc[:,0]
43+
j= loc[:,1] #moving the slider down if possible
44+
if i+1>2:
45+
status = False
46+
return A, status
47+
else:
48+
#print("DOWN")
49+
A[i,j]= A[i+1, j]
50+
A[i+1, j] = 0
51+
status = True
52+
#print(A)
53+
return A, status
54+
55+
##### Action set : Move Left #####
56+
def move_left(Curr_state):
57+
A = np.copy(Curr_state)
58+
loc = zeropos(A)
59+
60+
i = loc[:,0]
61+
j= loc[:,1] #moving the slider left if possible
62+
if j-1<0:
63+
status = False
64+
return A, status
65+
else:
66+
#print("Left")
67+
A[i,j]= A[i, j-1]
68+
A[i, j-1] = 0
69+
status = True
70+
#print(A)
71+
return A, status
72+
73+
##### Action set : Move Right #####
74+
def move_right(Curr_state):
75+
A = np.copy(Curr_state)
76+
loc = zeropos(A)
77+
78+
i = loc[:,0]
79+
j= loc[:,1] #moving the slider right if possible
80+
if j+1>2:
81+
status = False
82+
return A, status
83+
else:
84+
#print("Right")
85+
A[i,j]= A[i, j+1]
86+
A[i, j+1] = 0
87+
status = True
88+
#print(A)
89+
return A, status
90+
91+
##### A logic to compare states #####
92+
def set_conversion(A):
93+
i = j = 0
94+
for iter1 in A:
95+
for iter2 in iter1:
96+
j+=iter2*(10**i)
97+
i+=1
98+
return j
99+
100+
101+
##### To see if the current state is already existing #####
102+
def check_if_visited(Current_state, exist_states):
103+
a = set_conversion(Current_state)
104+
return a in exist_states
105+
106+
107+
##### To see if the current state mathes with goal state #####
108+
def check_goal(A, goal_state):
109+
status = np.array_equal(A,goal_state)
110+
#print(status)
111+
return status
112+
113+
114+
##### Initializing a default Goal state #####
115+
goal_state = np.array([[1,2,3],[4,5,6],[7,8,0]])
116+
117+
##### Innitializing a state list #####
118+
state_list =[]
119+
exist_states = set([])
120+
121+
##### To get user input of initial state from Terminal #####
122+
parser = argparse.ArgumentParser()
123+
parser.add_argument('Initial_state')
124+
args = parser.parse_args()
125+
initial_state = read(args.Initial_state)
126+
state_list.append(initial_state)
127+
exist_states.add(set_conversion(initial_state))
128+
129+
130+
##### Initializing container lists for bactracking and calculating cost #####
131+
child_state_index = []
132+
child_state_index.append(0)
133+
temp_index = [] ### A temporary list for copying new child states indices to child state index
134+
cost = 0
135+
count = 0
136+
child_state_number = 0
137+
138+
state_info = []
139+
reached = False
140+
141+
142+
##### An iterative loop to perform an action set on parent states to create child states #####
143+
##### Also checks if any state that was created is possibly a goal state #####
144+
145+
while len(child_state_index)>0:
146+
147+
temp_index = []
148+
for i in child_state_index:
149+
150+
new_state, status = move_up(state_list[i])
151+
if status == True and not check_if_visited(new_state, exist_states):
152+
child_state_number += 1
153+
temp_index.append(child_state_number)
154+
state_list.append(new_state)
155+
temp_node_info = np.array([child_state_number,i,cost])
156+
state_info.append(temp_node_info)
157+
exist_states.add(set_conversion(new_state))
158+
159+
if check_goal(new_state,goal_state):
160+
reached = True
161+
goal_state_index = child_state_number
162+
break
163+
164+
new_state, status = move_down(state_list[i])
165+
if status == True and not check_if_visited(new_state, exist_states):
166+
child_state_number += 1
167+
temp_index.append(child_state_number)
168+
state_list.append(new_state)
169+
temp_node_info = np.array([child_state_number,i,cost])
170+
state_info.append(temp_node_info)
171+
exist_states.add(set_conversion(new_state))
172+
173+
if check_goal(new_state,goal_state):
174+
reached = True
175+
goal_state_index = child_state_number
176+
break
177+
178+
new_state, status = move_right(state_list[i])
179+
if status == True and not check_if_visited(new_state, exist_states):
180+
child_state_number += 1
181+
temp_index.append(child_state_number)
182+
state_list.append(new_state)
183+
temp_node_info = np.array([child_state_number,i,cost])
184+
state_info.append(temp_node_info)
185+
exist_states.add(set_conversion(new_state))
186+
187+
if check_goal(new_state,goal_state):
188+
reached = True
189+
goal_state_index = child_state_number
190+
break
191+
192+
new_state, status = move_left(state_list[i])
193+
if status == True and not check_if_visited(new_state, exist_states):
194+
child_state_number += 1
195+
temp_index.append(child_state_number)
196+
state_list.append(new_state)
197+
temp_node_info = np.array([child_state_number,i,cost])
198+
state_info.append(temp_node_info)
199+
exist_states.add(set_conversion(new_state))
200+
201+
if check_goal(new_state,goal_state):
202+
reached = True
203+
goal_state_index = child_state_number
204+
break
205+
206+
##### When the goal state is reached, we need to back track to find the shortest path ####
207+
if reached == True:
208+
### Generating the path to reach the goal state ###
209+
generate_path = []
210+
gl_temp = goal_state_index-1
211+
generate_path.append(state_list[goal_state_index])
212+
print(generate_path)
213+
214+
#writing the output(generated path) to a file
215+
while gl_temp>0:
216+
x = state_info[gl_temp]
217+
gl_temp = x[1]
218+
generate_path.append(state_list[gl_temp])
219+
print('Goal state reached =',reached)
220+
generate_path.reverse()
221+
generate_path_t = np.asarray(generate_path)
222+
223+
224+
with open('nodePath.txt', 'w') as node_path_file:
225+
for i in generate_path_t:
226+
t = np.empty([1,9])
227+
count = 0
228+
for j in i.T:
229+
for k in j:
230+
t[0,count] = k
231+
count+=1
232+
np.savetxt(node_path_file,t,delimiter='\t')
233+
break
234+
235+
child_state_index = temp_index
236+
cost+=10
237+
238+
state_info_t = np.asarray(state_info)
239+
240+
#writing the output(Information of all states CHILD | PARENT | COST2COME) to the file
241+
with open('NodesInfo.txt', 'w') as node_info_file:
242+
for i in state_info_t:
243+
t = np.empty([1,3])
244+
t[0,:]=i
245+
np.savetxt(node_info_file,t,delimiter='\t')
246+
247+
state_list_t = np.asarray(state_list)
248+
249+
#writing the output(All states possible) to the file
250+
with open('Nodes.txt', 'w') as node_list_file:
251+
for i in state_list_t:
252+
t = np.empty([1,9])
253+
count = 0
254+
for j in i.T:
255+
for k in j:
256+
t[0,count] = k
257+
count+=1
258+
np.savetxt(node_list_file,t,delimiter='\t')
259+
260+
# If the goal node is not reached
261+
if reached==False:
262+
print('Goal state cannot be achieved')
246 KB
Loading

assets/images/puzzle_gif.gif

295 KB
Loading

nodePath.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
1.000000000000000000e+00 4.000000000000000000e+00 0.000000000000000000e+00 2.000000000000000000e+00 5.000000000000000000e+00 7.000000000000000000e+00 3.000000000000000000e+00 6.000000000000000000e+00 8.000000000000000000e+00
2+
1.000000000000000000e+00 0.000000000000000000e+00 4.000000000000000000e+00 2.000000000000000000e+00 5.000000000000000000e+00 7.000000000000000000e+00 3.000000000000000000e+00 6.000000000000000000e+00 8.000000000000000000e+00
3+
1.000000000000000000e+00 4.000000000000000000e+00 7.000000000000000000e+00 2.000000000000000000e+00 5.000000000000000000e+00 0.000000000000000000e+00 3.000000000000000000e+00 6.000000000000000000e+00 8.000000000000000000e+00
4+
1.000000000000000000e+00 4.000000000000000000e+00 7.000000000000000000e+00 2.000000000000000000e+00 5.000000000000000000e+00 8.000000000000000000e+00 3.000000000000000000e+00 6.000000000000000000e+00 0.000000000000000000e+00

0 commit comments

Comments
 (0)