Skip to content

Fix EightPuzzle class implementation in search.py (#710) #733

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 23, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 88 additions & 75 deletions search.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,91 +404,104 @@ def astar_search(problem, h=None):
# ______________________________________________________________________________
# A* heuristics

class EightPuzzle():
class EightPuzzle(Problem):

def __init__(self):
self.path = []
self.final = []
"""The problem of sliding tiles numbered from 1 to 8 on a 3x3 board,
where one of the squares is a blank. A state is represented as a 3x3 list,
where element at index i,j represents the tile number (0 if it's an empty square)."""

def __init__(self, initial, goal=None):
if goal:
self.goal = goal
else:
self.goal = [ [0,1,2],
[3,4,5],
[6,7,8] ]
Problem.__init__(self, initial, goal)

def find_blank_square(self, state):
"""Return the index of the blank square in a given state"""
for row in len(state):
for column in len(row):
if state[row][column] == 0:
index_blank_square = (row, column)
return index_blank_square

def actions(self, state):
"""Return the actions that can be executed in the given state.
The result would be a list, since there are only four possible actions
in any given state of the environment."""

possible_actions = list()
index_blank_square = self.find_blank_square(state)

if index_blank_square(0) == 0:
possible_actions += ['DOWN']
elif index_blank_square(0) == 1:
possible_actions += ['UP', 'DOWN']
elif index_blank_square(0) == 2:
possible_actions += ['UP']

if index_blank_square(1) == 0:
possible_actions += ['RIGHT']
elif index_blank_square(1) == 1:
possible_actions += ['LEFT', 'RIGHT']
elif index_blank_square(1) == 2:
possible_actions += ['LEFT']

return possible_actions

def result(self, state, action):
"""Given state and action, return a new state that is the result of the action.
Action is assumed to be a valid action in the state."""

blank_square = self.find_blank_square(state)
new_state = [row[:] for row in state]

if action=='UP':
new_state[blank_square(0)][blank_square(1)] = new_state[blank_square(0)-1][blank_square(1)]
new_state[blank_square(0)-1][blank_square(1)] = 0
elif action=='LEFT':
new_state[blank_square(0)][blank_square(1)] = new_state[blank_square(0)][blank_square(1)-1]
new_state[blank_square(0)][blank_square(1)-1] = 0
elif action=='DOWN':
new_state[blank_square(0)][blank_square(1)] = new_state[blank_square(0)+1][blank_square(1)]
new_state[blank_square(0)+1][blank_square(1)] = 0
elif action=='RIGHT':
new_state[blank_square(0)][blank_square(1)] = new_state[blank_square(0)][blank_square(1)+1]
new_state[blank_square(0)][blank_square(1)+1] = 0
else:
print("Invalid Action!")
return new_state

def goal_test(self, state):
"""Given a state, return True if state is a goal state or False, otherwise"""
for row in len(state):
for column in len(row):
if state[row][col] != self.goal[row][column]:
return False
return True

def checkSolvability(self, state):
inversion = 0
for i in range(len(state)):
for j in range(i,len(state)):
if (state[i]>state[j] and state[j]!=0):
for j in range(i, len(state)):
if (state[i] > state[j] and state[j] != 0):
inversion += 1
check = True
if inversion%2 != 0:
check = False
print(check)

def getPossibleMoves(self,state,heuristic,goal,moves):
move = {0:[1,3], 1:[0,2,4], 2:[1,5], 3:[0,6,4], 4:[1,3,5,7], 5:[2,4,8], 6:[3,7], 7:[4,6,8], 8:[7,5]} # create a dictionary of moves
index = state[0].index(0)
possible_moves = []
for i in range(len(move[index])):
conf = list(state[0][:])
a = conf[index]
b = conf[move[index][i]]
conf[move[index][i]] = a
conf[index] = b
possible_moves.append(conf)
scores = []
for i in possible_moves:
scores.append(heuristic(i,goal))
scores = [x+moves for x in scores]
allowed_state = []
for i in range(len(possible_moves)):
node = []
node.append(possible_moves[i])
node.append(scores[i])
node.append(state[0])
allowed_state.append(node)
return allowed_state


def create_path(self,goal,initial):
node = goal[0]
self.final.append(goal[0])
if goal[2] == initial:
return reversed(self.final)
else:
parent = goal[2]
for i in self.path:
if i[0] == parent:
parent = i
self.create_path(parent,initial)

def show_path(self,initial):
move = []
for i in range(0,len(self.path)):
move.append(''.join(str(x) for x in self.path[i][0]))

print("Number of explored nodes by the following heuristic are: ", len(set(move)))
print(initial)
for i in reversed(self.final):
print(i)

del self.path[:]
del self.final[:]
return

def solve(self,initial,goal,heuristic):
root = [initial,heuristic(initial,goal),'']
nodes = [] # nodes is a priority Queue based on the state score
nodes.append(root)
moves = 0
while len(nodes) != 0:
node = nodes[0]
del nodes[0]
self.path.append(node)
if node[0] == goal:
soln = self.create_path(self.path[-1],initial )
self.show_path(initial)
return
moves +=1
opened_nodes = self.getPossibleMoves(node,heuristic,goal,moves)
nodes = sorted(opened_nodes+nodes, key=itemgetter(1))


def h(self, state):
"""Return the heuristic value for a given state. Heuristic function used is
h(n) = number of misplaced tiles."""
num_misplaced_tiles = 0
for row in len(state):
for column in len(row):
if state[row][col] != self.goal[row][column]:
num_misplaced_tiles += 1
return num_misplaced_tiles

# ______________________________________________________________________________
# Other search algorithms
Expand Down