From e278e5d94055af2f04b15599b553d4dc94ffcf90 Mon Sep 17 00:00:00 2001 From: SasankYadati Date: Tue, 13 Feb 2018 22:38:35 +0530 Subject: [PATCH 1/3] Fix EightPuzzle class implementation --- search.py | 160 +++++++++++++++++++++++++++++------------------------- 1 file changed, 87 insertions(+), 73 deletions(-) diff --git a/search.py b/search.py index b705d6f28..f5ad215d0 100644 --- a/search.py +++ b/search.py @@ -404,12 +404,84 @@ 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.""" + + 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)): @@ -420,75 +492,17 @@ def checkSolvability(self, state): 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 From 0850239b01bf16fb386c46ffda7e62b6ec9c79ed Mon Sep 17 00:00:00 2001 From: SasankYadati Date: Tue, 13 Feb 2018 22:47:30 +0530 Subject: [PATCH 2/3] Fix EightPuzzle class implementation (#710) --- search.py | 1 - 1 file changed, 1 deletion(-) diff --git a/search.py b/search.py index f5ad215d0..45d79d677 100644 --- a/search.py +++ b/search.py @@ -497,7 +497,6 @@ 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]: From afe3a5a8c0de8a006bdd9ee8f3413b739f16a838 Mon Sep 17 00:00:00 2001 From: SasankYadati Date: Wed, 14 Feb 2018 04:01:34 +0530 Subject: [PATCH 3/3] Address style issues (#710) --- search.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/search.py b/search.py index 45d79d677..14388c684 100644 --- a/search.py +++ b/search.py @@ -420,11 +420,11 @@ def __init__(self, initial, goal=None): Problem.__init__(self, initial, goal) def find_blank_square(self, state): - """Return the index of the blank square in a given 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) + if state[row][column] == 0: + index_blank_square = (row, column) return index_blank_square def actions(self, state): @@ -435,25 +435,25 @@ def actions(self, state): possible_actions = list() index_blank_square = self.find_blank_square(state) - if index_blank_square(0)==0: + 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: + 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: + 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: + 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.""" + 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] @@ -475,18 +475,18 @@ def result(self, state, action): return new_state def goal_test(self, state): - """Given a state, return True if state is a goal state or False, otherwise.""" + """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]: + 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: @@ -499,8 +499,8 @@ def h(self, state): 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 + if state[row][col] != self.goal[row][column]: + num_misplaced_tiles += 1 return num_misplaced_tiles # ______________________________________________________________________________