Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
oorrja
GitHub Repository: oorrja/learntosolveit
Path: blob/master/languages/python/algorithm_npuzzle.py
1240 views
1
#!/usr/bin/python
2
# -*- coding: utf-8 -*-
3
# vim: ts=4 sw=4 et ai ff=unix ft=python nowrap
4
#
5
# Program: npuzzle.py
6
#
7
# Description: Solves the N-Puzzle Sliding Block Problem.
8
#
9
# Usage: python npuzzle.py.
10
#
11
# License: GNU GPL Version 2.0. Please refer www.gnu.org.
12
13
import random
14
15
16
class State:
17
18
def __init__(self, nsize):
19
"""Initialze the n-puzzle problem, with n-size value, tsize the total nodes and initial the goal state from n.
20
"""
21
22
self.nsize = nsize
23
self.tsize = pow(self.nsize, 2)
24
self.goal = list(range(1, self.tsize))
25
self.goal.append(0)
26
27
def printst(self, st):
28
"""Print the list in a Matrix Format."""
29
30
for (index, value) in enumerate(st):
31
print(' %s ' % value, end=' ')
32
if index in [x for x in range(self.nsize - 1, self.tsize,
33
self.nsize)]:
34
print()
35
print()
36
37
def getvalues(self, key):
38
"""Utility function to gather the Free Motions at various key positions in the Matrix."""
39
40
values = [1, -1, self.nsize, -self.nsize]
41
valid = []
42
for x in values:
43
if 0 <= key + x < self.tsize:
44
if x == 1 and key in range(self.nsize - 1, self.tsize,
45
self.nsize):
46
continue
47
if x == -1 and key in range(0, self.tsize, self.nsize):
48
continue
49
valid.append(x)
50
return valid
51
52
def expand(self, st):
53
"""Provide the list of next possible states from current state."""
54
55
pexpands = {}
56
for key in range(self.tsize):
57
pexpands[key] = self.getvalues(key)
58
pos = st.index(0)
59
moves = pexpands[pos]
60
expstates = []
61
for mv in moves:
62
nstate = st[:]
63
(nstate[pos + mv], nstate[pos]) = (nstate[pos], nstate[pos +
64
mv])
65
expstates.append(nstate)
66
return expstates
67
68
def one_of_poss(self, st):
69
"""Choose one of the possible states."""
70
71
exp_sts = self.expand(st)
72
rand_st = random.choice(exp_sts)
73
return rand_st
74
75
def start_state(self, seed=1000):
76
"""Determine the Start State of the Problem."""
77
78
start_st = (self.goal)[:]
79
for sts in range(seed):
80
start_st = self.one_of_poss(start_st)
81
return start_st
82
83
def goal_reached(self, st):
84
"""Check if the Goal Reached or Not."""
85
86
return st == self.goal
87
88
def manhattan_distance(self, st):
89
"""Calculate the Manhattan Distances of the particular State.
90
Manhattan distances are calculated as Total number of Horizontal and Vertical moves required by the values in the current state to reach their position in the Goal State.
91
"""
92
93
mdist = 0
94
for node in st:
95
if node != 0:
96
gdist = abs(self.goal.index(node) - st.index(node))
97
(jumps, steps) = (gdist // self.nsize, gdist % self.nsize)
98
mdist += jumps + steps
99
return mdist
100
101
def huristic_next_state(self, st):
102
"""This is the Huristic Function. It determines the next state to follow and uses Mahattan distances method as the huristics. This this determined way, a A* approach for path finding is used.
103
If more than one path have same manhattan distance, then a random choice of one of them is analyzed and carried forward. If not best path, randomness to providethe other choice is relied upon. No Depth First search is Used."""
104
105
exp_sts = self.expand(st)
106
mdists = []
107
for st in exp_sts:
108
mdists.append(self.manhattan_distance(st))
109
mdists.sort()
110
short_path = mdists[0]
111
if mdists.count(short_path) > 1:
112
least_paths = [st for st in exp_sts if self.manhattan_distance(st) == short_path]
113
return random.choice(least_paths)
114
else:
115
for st in exp_sts:
116
if self.manhattan_distance(st) == short_path:
117
return st
118
119
def solve_it(self, st):
120
while not self.goal_reached(st):
121
st = self.huristic_next_state(st)
122
self.printst(st)
123
124
125
if __name__ == '__main__':
126
print('N-Puzzle Solver!')
127
print(10 * '-')
128
state = State(3)
129
print('The Starting State is:')
130
start = state.start_state(5)
131
state.printst(start)
132
print('The Goal State should be:')
133
state.printst(state.goal)
134
print('Here it Goes:')
135
state.printst(start)
136
state.solve_it(start)
137
138
139
140