def start(self): # initialize the init state and goal state as 2d array #init_tile = np.array([[2, 3, 6], [1, 4, 8], [7, 5, 0]]) init_tile = np.array([[1, 2, 3], [0, 4, 6], [7, 5, 8]]) init = State(init_tile, 0, 0) goal_tile = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 0]]) goal = State(goal_tile, 0, 0) self.tiles = 8 UIS_solver = UninformedSearchSolver(init, goal) UIS_solver.run() IS_solver = InformedSearchSolver(init, goal) IS_solver.run()
def start(self): # initialize the init state and goal state as 2d array #init_tile = np.array([[2, 3, 6], [1, 4, 8], [7, 5, 0]]) init_tile = np.array([[1, 2, 3], [0, 4, 6], [7, 5, 8]]) # initial state given in prompt for testing #init_tile = np.array([[2, 3, 1], [0, 4, 6], [7, 5, 8]]) init = State(init_tile, 0, 0) goal_tile = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 0]]) goal = State(goal_tile, 0, 0) self.tiles = 8 print("\nBegin uninformed (Breadth-First) search:") UIS_solver = UninformedSearchSolver(init, goal) # Time the amount of time it takes to complete computation uStartTime = time.time() UIS_solver.run() uEndTime = time.time() uCompTime = uEndTime - uStartTime # Print time it took to compute print("\n") print("Took " + uCompTime.__str__() + " seconds to complete.") print("\n") print("************************************************************") print("\nBegin Informed (Best-First) search:") IS_solver = InformedSearchSolver(init, goal) # Time computational time iStartTime = time.time() IS_solver.run() iEndTime = time.time() iCompTime = iEndTime - iStartTime # Print time it took to compute print("\n") print("Took " + iCompTime.__str__() + " seconds to complete.")
class UninformedSearchSolver: current = State() goal = State() openlist = [] closed = [] depth = 0 def __init__(self, current, goal): self.current = current self.goal = goal self.openlist.append(current) def check_inclusive(self, s): isinopen = 0 isinclosed = 0 # Var will hold whether state is in open or closed list in position 0 and its index in pos 1 returnValue = [-1, -1] # If s is in the open list for i in self.openlist: if i.equals(s): isinopen = 1 returnValue[1] = self.openlist.index(i) break # If s is in the closed list for i in self.closed: if i.equals(s): isinclosed = 1 returnValue[1] = self.closed.index(i) break # If child is not in either list if isinopen == 0 and isinclosed == 0: returnValue[0] = 1 # If child is already in the open list elif isinopen == 1 and isinclosed == 0: returnValue[0] = 2 # If child is already in the closed list elif isinopen == 1 and isinclosed == 1: returnValue[0] = 3 return returnValue """ * four types of walks * best first search * ↑ ↓ ← → (move up, move down, move left, move right) * the blank tile is represent by '0' """ def state_walk(self): if len(self.openlist) > 0: self.current = self.openlist.pop( 0) # Remove leftmost state from open # Get location where blank tile is walk_state = self.current.tile_seq row = 0 col = 0 for i in range(len(walk_state)): for j in range(len(walk_state[i])): if walk_state[i][j] == 0: row = i col = j break # Generate children of current # Empty lists to hold children when moves are legal tempUp = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] tempDown = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] tempLeft = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] tempRight = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] # Move up blank space if (row - 1) >= 0: for i in range(len(walk_state)): for j in range(len(self.current.tile_seq[i])): tempUp[i][j] = self.current.tile_seq[i][j] tiletoswitch = tempUp[row - 1][ col] # The value where the blank tile is in the current state tempUp[row - 1][col] = self.current.tile_seq[row][ col] # Moving the blank tile up by placing 0 in row-1 tempUp[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempUp, self.current.depth + 1) # Creating new state from new configuration check = self.check_inclusive(s) # If child is neither on open or closed list, append it to the open list if check[0] == 1: self.openlist.append(s) # Move down blank space if (row + 1) < len(walk_state): for i in range(len(walk_state)): for j in range(len(walk_state[i])): tempDown[i][j] = walk_state[i][j] tiletoswitch = tempDown[row + 1][ col] # The value where the blank tile is in the current state tempDown[row + 1][col] = self.current.tile_seq[row][ col] # Moving blank tile up by placing 0 in row-1 tempDown[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempDown, self.current.depth + 1) check = self.check_inclusive(s) # If child is neither on open or closed list, append it to the open list if check[0] == 1: self.openlist.append(s) # Move left blank space if (col - 1) >= 0: for i in range(len(walk_state)): for j in range(len(walk_state[i])): tempLeft[i][j] = walk_state[i][j] tiletoswitch = tempLeft[row][ col - 1] # The value where the blank tile is in the current state tempLeft[row][col - 1] = self.current.tile_seq[row][ col] # Moving blank tile up by placing 0 in row-1 tempLeft[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempLeft, self.current.depth + 1) check = self.check_inclusive(s) # If child is neither on open or closed list, append it to the open list if check[0] == 1: self.openlist.append(s) # Move right blank space if (col + 1) < len(walk_state): for i in range(len(walk_state)): for j in range(len(walk_state[i])): tempRight[i][j] = walk_state[i][j] tiletoswitch = tempRight[row][ col + 1] # The value where the blank tile is in the current state tempRight[row][col + 1] = self.current.tile_seq[row][ col] # Moving blank tile up by placing 0 in row-1 tempRight[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempRight, self.current.depth + 1) check = self.check_inclusive(s) # If child is neither on open or closed list, append it to the open list if check[0] == 1: self.openlist.append(s) # add current to closed state list self.closed.append(self.current) # Check the following to make it work properly def run(self): # output the start state print("\nstart state: \n") print(self.current.tile_seq) print("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n") path = 0 while not self.current.equals(self.goal): self.state_walk() print(np.array(self.current.tile_seq)) path += 1 print("\nIt took ", path, " iterations") print("The length of the path is: ", self.current.depth) # output the goal state target = self.goal.tile_seq print("\ngoal state:\n") print(target)
def state_walk(self): if len(self.openlist) > 0: self.current = self.openlist.pop( 0) # Remove leftmost state from open # Get location where blank tile is walk_state = self.current.tile_seq row = 0 col = 0 for i in range(len(walk_state)): for j in range(len(walk_state[i])): if walk_state[i][j] == 0: row = i col = j break # Generate children of current # Empty lists to hold children when moves are legal tempUp = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] tempDown = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] tempLeft = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] tempRight = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] # Move up blank space if (row - 1) >= 0: for i in range(len(walk_state)): for j in range(len(self.current.tile_seq[i])): tempUp[i][j] = self.current.tile_seq[i][j] tiletoswitch = tempUp[row - 1][ col] # The value where the blank tile is in the current state tempUp[row - 1][col] = self.current.tile_seq[row][ col] # Moving the blank tile up by placing 0 in row-1 tempUp[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempUp, self.current.depth + 1) # Creating new state from new configuration check = self.check_inclusive(s) # If child is neither on open or closed list, append it to the open list if check[0] == 1: self.openlist.append(s) # Move down blank space if (row + 1) < len(walk_state): for i in range(len(walk_state)): for j in range(len(walk_state[i])): tempDown[i][j] = walk_state[i][j] tiletoswitch = tempDown[row + 1][ col] # The value where the blank tile is in the current state tempDown[row + 1][col] = self.current.tile_seq[row][ col] # Moving blank tile up by placing 0 in row-1 tempDown[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempDown, self.current.depth + 1) check = self.check_inclusive(s) # If child is neither on open or closed list, append it to the open list if check[0] == 1: self.openlist.append(s) # Move left blank space if (col - 1) >= 0: for i in range(len(walk_state)): for j in range(len(walk_state[i])): tempLeft[i][j] = walk_state[i][j] tiletoswitch = tempLeft[row][ col - 1] # The value where the blank tile is in the current state tempLeft[row][col - 1] = self.current.tile_seq[row][ col] # Moving blank tile up by placing 0 in row-1 tempLeft[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempLeft, self.current.depth + 1) check = self.check_inclusive(s) # If child is neither on open or closed list, append it to the open list if check[0] == 1: self.openlist.append(s) # Move right blank space if (col + 1) < len(walk_state): for i in range(len(walk_state)): for j in range(len(walk_state[i])): tempRight[i][j] = walk_state[i][j] tiletoswitch = tempRight[row][ col + 1] # The value where the blank tile is in the current state tempRight[row][col + 1] = self.current.tile_seq[row][ col] # Moving blank tile up by placing 0 in row-1 tempRight[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempRight, self.current.depth + 1) check = self.check_inclusive(s) # If child is neither on open or closed list, append it to the open list if check[0] == 1: self.openlist.append(s) # add current to closed state list self.closed.append(self.current)
def state_walk(self): self.closed.append(self.current) self.openlist.remove(self.current) walk_state = self.current.tile_seq row = 0 col = 0 # Get location where the blank tile is for i in range(len(walk_state)): for j in range(len(walk_state[i])): if walk_state[i][j] == 0: row = i col = j break self.depth += 1 """ add closed state if len(self.openlist) > 0: self.current = self.openlist.pop(0) # Remove leftmost state from open # move to the next heuristic state walk_state = self.current.tile_seq row = 0 col = 0 # Get location where the blank tile is for i in range(len(walk_state)): for j in range(len(walk_state[i])): if walk_state[i][j] == 0: row = i col = j break """ # Generate children of current based on legal moves tempUp = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] tempDown = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] tempLeft = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] tempRight = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] ''' The following program is used to do the state space walk ''' # ↑ move up if (row - 1) >= 0: for i in range(len(walk_state)): for j in range(len(self.current.tile_seq[i])): tempUp[i][j] = self.current.tile_seq[i][j] tiletoswitch = tempUp[row - 1][ col] # The value where the blank tile is in the current state tempUp[row - 1][col] = self.current.tile_seq[row][ col] # Moving the blank tile up by placing 0 in row-1 tempUp[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempUp, self.current.depth + 1) # Creating new state from new configuration check = self.check_inclusive(s) # If child not in open or closed if (check[0] == 1): # Assign child heuristic value self.heuristic_test(s) self.openlist.append(s) # If child in open elif (check[0] == 2): if s.depth < self.openlist[check[1]].depth: self.openlist[check[1]].depth = s.depth # If child in closed elif (check[0] == 3): if s.depth < self.closed[check[1]].depth: self.openlist.append(self.closed.pop(check[1])) """ *do the next steps according to flag (check) *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path *if flag = 3 //in the closed list *if the child was reached by a shorter path then begin *remove the state from closed; *add the child to open *end; """ # TODO your code end here # ↓ move down if (row + 1) < len(walk_state): for i in range(len(walk_state)): for j in range(len(walk_state[i])): tempDown[i][j] = walk_state[i][j] tiletoswitch = tempDown[row + 1][ col] # The value where the blank tile is in the current state tempDown[row + 1][col] = self.current.tile_seq[row][ col] # Moving blank tile up by placing 0 in row-1 tempDown[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempDown, self.current.depth + 1) check = self.check_inclusive(s) # If child not in open or closed if (check[0] == 1): # Assign child heuristic value self.heuristic_test(s) self.openlist.append(s) # If child in open elif (check[0] == 2): if s.depth < self.openlist[check[1]].depth: self.openlist[check[1]].depth = s.depth # If child in closed elif (check[0] == 3): if s.depth < self.closed[check[1]].depth: self.openlist.append(self.closed.pop(check[1])) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ # TODO your code end here # ← move left if (col - 1) >= 0: for i in range(len(walk_state)): for j in range(len(walk_state[i])): tempLeft[i][j] = walk_state[i][j] tiletoswitch = tempLeft[row][ col - 1] # The value where the blank tile is in the current state tempLeft[row][col - 1] = self.current.tile_seq[row][ col] # Moving blank tile up by placing 0 in row-1 tempLeft[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempLeft, self.current.depth + 1) check = self.check_inclusive(s) # If child not in open or closed if (check[0] == 1): # Assign child heuristic value self.heuristic_test(s) self.openlist.append(s) # If child in open elif (check[0] == 2): if s.depth < self.openlist[check[1]].depth: self.openlist[check[1]].depth = s.depth # If child in closed elif (check[0] == 3): if s.depth < self.closed[check[1]].depth: self.openlist.append(self.closed.pop(check[1])) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ # TODO your code end here # → move right if (col + 1) < len(walk_state): for i in range(len(walk_state)): for j in range(len(walk_state[i])): tempRight[i][j] = walk_state[i][j] tiletoswitch = tempRight[row][ col + 1] # The value where the blank tile is in the current state tempRight[row][col + 1] = self.current.tile_seq[row][ col] # Moving blank tile up by placing 0 in row-1 tempRight[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempRight, self.current.depth + 1) check = self.check_inclusive(s) # If child not in open or closed if (check[0] == 1): # Assign child heuristic value self.heuristic_test(s) self.openlist.append(s) # If child in open elif (check[0] == 2): if s.depth < self.openlist[check[1]].depth: self.openlist[check[1]].depth = s.depth # If child in closed elif (check[0] == 3): if s.depth < self.closed[check[1]].depth: self.openlist.append(self.closed.pop(check[1])) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ # TODO your code end here # sort the open list first by h(n) then g(n) self.openlist.sort(key=self.sortFun) self.current = self.openlist[0]
class InformedSearchSolver: current = State() goal = State() openlist = [] closed = [] depth = 0 def __init__(self, current, goal): self.current = current self.goal = goal self.openlist.append(current) def sortFun(self, e): return e.weight """ * check if the generated state is in open or closed * the purpose is to avoid a circle * @param s * @return """ def check_inclusive(self, s): in_open = 0 in_closed = 0 ret = [-1, -1] for item in self.openlist: if item.equals(s): in_open = 1 ret[1] = self.openlist.index(item) break for item in self.closed: if item.equals(s): in_closed = 1 ret[1] = self.closed.index(item) break if in_open == 0 and in_closed == 0: ret[0] = 1 # the child is not in open or closed elif in_open == 1 and in_closed == 0: ret[0] = 2 # the child is already in open elif in_open == 0 and in_closed == 1: ret[0] = 3 # the child is already in closed return ret """ * four types of walks * best first search * ↑ ↓ ← → (move up, move down, move left, move right) * the blank tile is represent by '0' """ def state_walk(self): self.closed.append(self.current) self.openlist.remove(self.current) walk_state = self.current.tile_seq row = 0 col = 0 # Get location where the blank tile is for i in range(len(walk_state)): for j in range(len(walk_state[i])): if walk_state[i][j] == 0: row = i col = j break self.depth += 1 """ add closed state if len(self.openlist) > 0: self.current = self.openlist.pop(0) # Remove leftmost state from open # move to the next heuristic state walk_state = self.current.tile_seq row = 0 col = 0 # Get location where the blank tile is for i in range(len(walk_state)): for j in range(len(walk_state[i])): if walk_state[i][j] == 0: row = i col = j break """ # Generate children of current based on legal moves tempUp = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] tempDown = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] tempLeft = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] tempRight = [[None for j in range(len(walk_state))] for i in range(len(walk_state))] ''' The following program is used to do the state space walk ''' # ↑ move up if (row - 1) >= 0: for i in range(len(walk_state)): for j in range(len(self.current.tile_seq[i])): tempUp[i][j] = self.current.tile_seq[i][j] tiletoswitch = tempUp[row - 1][ col] # The value where the blank tile is in the current state tempUp[row - 1][col] = self.current.tile_seq[row][ col] # Moving the blank tile up by placing 0 in row-1 tempUp[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempUp, self.current.depth + 1) # Creating new state from new configuration check = self.check_inclusive(s) # If child not in open or closed if (check[0] == 1): # Assign child heuristic value self.heuristic_test(s) self.openlist.append(s) # If child in open elif (check[0] == 2): if s.depth < self.openlist[check[1]].depth: self.openlist[check[1]].depth = s.depth # If child in closed elif (check[0] == 3): if s.depth < self.closed[check[1]].depth: self.openlist.append(self.closed.pop(check[1])) """ *do the next steps according to flag (check) *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path *if flag = 3 //in the closed list *if the child was reached by a shorter path then begin *remove the state from closed; *add the child to open *end; """ # TODO your code end here # ↓ move down if (row + 1) < len(walk_state): for i in range(len(walk_state)): for j in range(len(walk_state[i])): tempDown[i][j] = walk_state[i][j] tiletoswitch = tempDown[row + 1][ col] # The value where the blank tile is in the current state tempDown[row + 1][col] = self.current.tile_seq[row][ col] # Moving blank tile up by placing 0 in row-1 tempDown[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempDown, self.current.depth + 1) check = self.check_inclusive(s) # If child not in open or closed if (check[0] == 1): # Assign child heuristic value self.heuristic_test(s) self.openlist.append(s) # If child in open elif (check[0] == 2): if s.depth < self.openlist[check[1]].depth: self.openlist[check[1]].depth = s.depth # If child in closed elif (check[0] == 3): if s.depth < self.closed[check[1]].depth: self.openlist.append(self.closed.pop(check[1])) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ # TODO your code end here # ← move left if (col - 1) >= 0: for i in range(len(walk_state)): for j in range(len(walk_state[i])): tempLeft[i][j] = walk_state[i][j] tiletoswitch = tempLeft[row][ col - 1] # The value where the blank tile is in the current state tempLeft[row][col - 1] = self.current.tile_seq[row][ col] # Moving blank tile up by placing 0 in row-1 tempLeft[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempLeft, self.current.depth + 1) check = self.check_inclusive(s) # If child not in open or closed if (check[0] == 1): # Assign child heuristic value self.heuristic_test(s) self.openlist.append(s) # If child in open elif (check[0] == 2): if s.depth < self.openlist[check[1]].depth: self.openlist[check[1]].depth = s.depth # If child in closed elif (check[0] == 3): if s.depth < self.closed[check[1]].depth: self.openlist.append(self.closed.pop(check[1])) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ # TODO your code end here # → move right if (col + 1) < len(walk_state): for i in range(len(walk_state)): for j in range(len(walk_state[i])): tempRight[i][j] = walk_state[i][j] tiletoswitch = tempRight[row][ col + 1] # The value where the blank tile is in the current state tempRight[row][col + 1] = self.current.tile_seq[row][ col] # Moving blank tile up by placing 0 in row-1 tempRight[row][ col] = tiletoswitch # Replacing spot where the blank tile was with the value right above s = State(tempRight, self.current.depth + 1) check = self.check_inclusive(s) # If child not in open or closed if (check[0] == 1): # Assign child heuristic value self.heuristic_test(s) self.openlist.append(s) # If child in open elif (check[0] == 2): if s.depth < self.openlist[check[1]].depth: self.openlist[check[1]].depth = s.depth # If child in closed elif (check[0] == 3): if s.depth < self.closed[check[1]].depth: self.openlist.append(self.closed.pop(check[1])) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ # TODO your code end here # sort the open list first by h(n) then g(n) self.openlist.sort(key=self.sortFun) self.current = self.openlist[0] """ * Solve the game using heuristic search strategies * There are three types of heuristic rules: * (1) Tiles out of place * (2) Sum of distances out of place * (3) 2 x the number of direct tile reversals * evaluation function * f(n) = g(n) + h(n) * g(n) = depth of path length to start state * h(n) = (1) + (2) + (3) """ def heuristic_test(self, current): curr_seq = current.tile_seq goal_seq = self.goal.tile_seq # (1) Tiles out of place h1 = 0 """ *loop over the curr_seq *check the every entry in curr_seq with goal_seq If a tile is not in it's goal place, sum it to the heuristic estimate. """ for i in range(len(curr_seq)): for j in range(len(curr_seq[i])): if curr_seq[i][j] != goal_seq[i][j]: h1 += 1 # (2) Sum of distances out of place h2 = 0 """ *loop over the goal_seq and curr_seq in nested way *locate the entry which has the same value in *curr_seq and goal_seq then calculate the offset *through the absolute value of two differences *of curr_row-goal_row and curr_col-goal_col *absoulte value can be calculated by abs(...) """ for i in range(len(curr_seq)): for j in range(len(curr_seq[i])): """ If a tile is out of place, iterate through the goal state and find where it's supposed to be, then calculate the absolute value of the difference between them and add it to the heuristic score """ if curr_seq[i][j] != goal_seq[i][j]: for k in range(len(goal_seq)): for l in range(len(goal_seq[k])): if curr_seq[i][j] == goal_seq[k][l]: h2 += (abs(i - k) + abs(j - l)) # (3) 2 x the number of direct tile reversals h3 = 0 for i in range(len(curr_seq)): # Loop row for j in range(len(curr_seq[i])): # loop col # Check boundary of row if (i + 1) < len(curr_seq): # Check element is not 0 if curr_seq[i + 1][j] != 0 and curr_seq[i][j] != 0: if curr_seq[i + 1][j] == goal_seq[i][j] and curr_seq[ i][j] == goal_seq[i + 1][j]: h3 += 1 # Check boundary of col if (j + 1) < len(curr_seq[i]): # Check element is not 0 if curr_seq[i][j + 1] != 0 and curr_seq[i][j] != 0: if curr_seq[i][j + 1] == goal_seq[i][j] and curr_seq[ i][j] == goal_seq[i][j + 1]: h3 += 1 h3 *= 2 # set the heuristic value for current state current.weight = current.depth + h1 + h2 + h3 # You can choose to print all the states on the search path, or just the start and goal state def run(self): # output the start state print("\nstart state: \n") print(self.current.tile_seq) print("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n") path = 0 while not self.current.equals(self.goal): self.state_walk() print(np.array(self.current.tile_seq)) path += 1 print("\nIt took ", path, " iterations") print("The length of the path is: ", self.current.depth) # output the goal state target = self.goal.tile_seq print("\ngoal state: \n") print(target)
def state_walk(self): # add closed state self.closed.append(self.current) self.openlist.remove(self.current) # move to the next heuristic state walk_state = self.current.tile_seq row = 0 col = 0 for i in range(len(walk_state)): for j in range(len(walk_state[i])): if walk_state[i, j] == 0: row = i col = j break self.depth += 1 ''' The following program is used to do the state space walk ''' # ↑ move up if (row - 1) >= 0: # TODO your code start here """ *get the 2d array of current *define a temp 2d array and loop over current.tile_seq *pass the value from current.tile_seq to temp array """ tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) for i in range(len(self.current.tile_seq)): for j in range(len(self.current.tile_seq[i])): tempArray[i, j] = self.current.tile_seq[i, j] """ *↑ is correspond to (row, col) and (row-1, col) *exchange these two tiles of temp """ tempHolder = tempArray[row, col] tempArray[row, col] = tempArray[row - 1, col] tempArray[row - 1, col] = tempHolder #print("temp up \n", tempArray) """ *call check_inclusive(temp state) *define a new temp state via temp array """ tempState = State() tempState.tile_seq = tempArray tempState.depth = self.depth flag = self.check_inclusive(tempState) #print("TempState \n", tempState.tile_seq) """ *do the next steps according to flag *if flag = 1 //not in open and closed *begin *assign the child a heuristic value via heuristic_test(temp state); *add the child to open *end; """ if flag[0] == 1: self.heuristic_test(tempState) self.openlist.append(tempState) #print("open list \n", self.openlist) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path """ if flag[0] == 2: if self.openlist[flag[1]].depth > tempState.depth: self.openlist[flag[1]].depth = tempState.depth #print("depth", tempState.depth) """ *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ if flag[0] == 3: if self.closed[flag[1]].depth > tempState.depth: self.closed.remove(self.closed[flag[1]]) self.openlist.append(tempState) # TODO your code end here # ↓ move down if (row + 1) < len(walk_state): # TODO your code start here """ *get the 2d array of current *define a temp 2d array and loop over current.tile_seq *pass the value from current.tile_seq to temp array """ tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) for i in range(len(self.current.tile_seq)): for j in range(len(self.current.tile_seq[i])): tempArray[i, j] = self.current.tile_seq[i, j] """ *↓ is correspond to (row, col) and (row+1, col) *exchange these two tiles of temp """ tempHolder = tempArray[row, col] tempArray[row, col] = tempArray[row + 1, col] tempArray[row + 1, col] = tempHolder #print("temp down \n", tempArray) """ *call check_inclusive(temp state) *define a new temp state via temp array """ tempState = State() tempState.tile_seq = tempArray tempState.depth = self.depth flag = self.check_inclusive(tempState) # print("TempState \n", tempState.tile_seq) """ *do the next steps according to flag *if flag = 1 //not in open and closed *begin *assign the child a heuristic value via heuristic_test(temp state); *add the child to open *end; """ if flag[0] == 1: self.heuristic_test(tempState) self.openlist.append(tempState) # print("open list \n", self.openlist) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path """ if flag[0] == 2: if self.openlist[flag[1]].depth > tempState.depth: self.openlist[flag[1]].depth = tempState.depth # print("depth", tempState.depth) """ *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ if flag[0] == 3: if self.closed[flag[1]].depth > tempState.depth: self.closed.remove(self.closed[flag[1]]) self.openlist.append(tempState) # TODO your code end here # ← move left if (col - 1) >= 0: # TODO your code start here """ *get the 2d array of current *define a temp 2d array and loop over current.tile_seq *pass the value from current.tile_seq to temp array """ tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) for i in range(len(self.current.tile_seq)): for j in range(len(self.current.tile_seq[i])): tempArray[i, j] = self.current.tile_seq[i, j] """ *↑ is correspond to (row, col) and (row, col-1) *exchange these two tiles of temp """ tempHolder = tempArray[row, col] tempArray[row, col] = tempArray[row, col - 1] tempArray[row, col - 1] = tempHolder #print("temp left \n", tempArray) """ *call check_inclusive(temp state) *define a new temp state via temp array """ tempState = State() tempState.tile_seq = tempArray tempState.depth = self.depth flag = self.check_inclusive(tempState) # print("TempState \n", tempState.tile_seq) """ *do the next steps according to flag *if flag = 1 //not in open and closed *begin *assign the child a heuristic value via heuristic_test(temp state); *add the child to open *end; """ if flag[0] == 1: self.heuristic_test(tempState) self.openlist.append(tempState) # print("open list \n", self.openlist) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path """ if flag[0] == 2: if self.openlist[flag[1]].depth > tempState.depth: self.openlist[flag[1]].depth = tempState.depth # print("depth", tempState.depth) """ *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ if flag[0] == 3: if self.closed[flag[1]].depth > tempState.depth: self.closed.remove(self.closed[flag[1]]) self.openlist.append(tempState) # TODO your code end here # → move right if (col + 1) < len(walk_state): # TODO your code start here """ *get the 2d array of current *define a temp 2d array and loop over current.tile_seq *pass the value from current.tile_seq to temp array """ tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) for i in range(len(self.current.tile_seq)): for j in range(len(self.current.tile_seq[i])): tempArray[i, j] = self.current.tile_seq[i, j] """ *↑ is correspond to (row, col) and (row, col+1) *exchange these two tiles of temp """ tempHolder = tempArray[row, col] tempArray[row, col] = tempArray[row, col + 1] tempArray[row, col + 1] = tempHolder #print("temp right \n", tempArray) """ *call check_inclusive(temp state) *define a new temp state via temp array """ tempState = State() tempState.tile_seq = tempArray tempState.depth = self.depth flag = self.check_inclusive(tempState) # print("TempState \n", tempState.tile_seq) """ *do the next steps according to flag *if flag = 1 //not in open and closed *begin *assign the child a heuristic value via heuristic_test(temp state); *add the child to open *end; """ if flag[0] == 1: self.heuristic_test(tempState) self.openlist.append(tempState) # print("open list \n", self.openlist) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path """ if flag[0] == 2: if self.openlist[flag[1]].depth > tempState.depth: self.openlist[flag[1]].depth = tempState.depth # print("depth", tempState.depth) """ *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ if flag[0] == 3: if self.closed[flag[1]].depth > tempState.depth: self.closed.remove(self.closed[flag[1]]) self.openlist.append(tempState) # TODO your code end here # sort the open list first by h(n) then g(n) self.openlist.sort(key=self.sortFun) self.current = self.openlist[0]
class InformedSearchSolver: current = State() goal = State() openlist = [] closed = [] depth = 0 def __init__(self, current, goal): self.current = current self.goal = goal self.openlist.append(current) def sortFun(self, e): return e.weight """ * check if the generated state is in open or closed * the purpose is to avoid a circle * @param s * @return """ def check_inclusive(self, s): in_open = 0 in_closed = 0 ret = [-1, -1] for item in self.openlist: if item.equals(s): in_open = 1 ret[1] = self.openlist.index(item) break for item in self.closed: if item.equals(s): in_closed = 1 ret[1] = self.closed.index(item) break if in_open == 0 and in_closed == 0: ret[0] = 1 # the child is not in open or closed elif in_open == 1 and in_closed == 0: ret[0] = 2 # the child is already in open elif in_open == 0 and in_closed == 1: ret[0] = 3 # the child is already in closed return ret """ * four types of walks * best first search * ↑ ↓ ← → (move up, move down, move left, move right) * the blank tile is represent by '0' """ def state_walk(self): # add closed state self.closed.append(self.current) self.openlist.remove(self.current) # move to the next heuristic state walk_state = self.current.tile_seq row = 0 col = 0 for i in range(len(walk_state)): for j in range(len(walk_state[i])): if walk_state[i, j] == 0: row = i col = j break self.depth += 1 ''' The following program is used to do the state space walk ''' # ↑ move up if (row - 1) >= 0: # TODO your code start here """ *get the 2d array of current *define a temp 2d array and loop over current.tile_seq *pass the value from current.tile_seq to temp array """ tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) for i in range(len(self.current.tile_seq)): for j in range(len(self.current.tile_seq[i])): tempArray[i, j] = self.current.tile_seq[i, j] """ *↑ is correspond to (row, col) and (row-1, col) *exchange these two tiles of temp """ tempHolder = tempArray[row, col] tempArray[row, col] = tempArray[row - 1, col] tempArray[row - 1, col] = tempHolder #print("temp up \n", tempArray) """ *call check_inclusive(temp state) *define a new temp state via temp array """ tempState = State() tempState.tile_seq = tempArray tempState.depth = self.depth flag = self.check_inclusive(tempState) #print("TempState \n", tempState.tile_seq) """ *do the next steps according to flag *if flag = 1 //not in open and closed *begin *assign the child a heuristic value via heuristic_test(temp state); *add the child to open *end; """ if flag[0] == 1: self.heuristic_test(tempState) self.openlist.append(tempState) #print("open list \n", self.openlist) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path """ if flag[0] == 2: if self.openlist[flag[1]].depth > tempState.depth: self.openlist[flag[1]].depth = tempState.depth #print("depth", tempState.depth) """ *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ if flag[0] == 3: if self.closed[flag[1]].depth > tempState.depth: self.closed.remove(self.closed[flag[1]]) self.openlist.append(tempState) # TODO your code end here # ↓ move down if (row + 1) < len(walk_state): # TODO your code start here """ *get the 2d array of current *define a temp 2d array and loop over current.tile_seq *pass the value from current.tile_seq to temp array """ tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) for i in range(len(self.current.tile_seq)): for j in range(len(self.current.tile_seq[i])): tempArray[i, j] = self.current.tile_seq[i, j] """ *↓ is correspond to (row, col) and (row+1, col) *exchange these two tiles of temp """ tempHolder = tempArray[row, col] tempArray[row, col] = tempArray[row + 1, col] tempArray[row + 1, col] = tempHolder #print("temp down \n", tempArray) """ *call check_inclusive(temp state) *define a new temp state via temp array """ tempState = State() tempState.tile_seq = tempArray tempState.depth = self.depth flag = self.check_inclusive(tempState) # print("TempState \n", tempState.tile_seq) """ *do the next steps according to flag *if flag = 1 //not in open and closed *begin *assign the child a heuristic value via heuristic_test(temp state); *add the child to open *end; """ if flag[0] == 1: self.heuristic_test(tempState) self.openlist.append(tempState) # print("open list \n", self.openlist) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path """ if flag[0] == 2: if self.openlist[flag[1]].depth > tempState.depth: self.openlist[flag[1]].depth = tempState.depth # print("depth", tempState.depth) """ *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ if flag[0] == 3: if self.closed[flag[1]].depth > tempState.depth: self.closed.remove(self.closed[flag[1]]) self.openlist.append(tempState) # TODO your code end here # ← move left if (col - 1) >= 0: # TODO your code start here """ *get the 2d array of current *define a temp 2d array and loop over current.tile_seq *pass the value from current.tile_seq to temp array """ tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) for i in range(len(self.current.tile_seq)): for j in range(len(self.current.tile_seq[i])): tempArray[i, j] = self.current.tile_seq[i, j] """ *↑ is correspond to (row, col) and (row, col-1) *exchange these two tiles of temp """ tempHolder = tempArray[row, col] tempArray[row, col] = tempArray[row, col - 1] tempArray[row, col - 1] = tempHolder #print("temp left \n", tempArray) """ *call check_inclusive(temp state) *define a new temp state via temp array """ tempState = State() tempState.tile_seq = tempArray tempState.depth = self.depth flag = self.check_inclusive(tempState) # print("TempState \n", tempState.tile_seq) """ *do the next steps according to flag *if flag = 1 //not in open and closed *begin *assign the child a heuristic value via heuristic_test(temp state); *add the child to open *end; """ if flag[0] == 1: self.heuristic_test(tempState) self.openlist.append(tempState) # print("open list \n", self.openlist) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path """ if flag[0] == 2: if self.openlist[flag[1]].depth > tempState.depth: self.openlist[flag[1]].depth = tempState.depth # print("depth", tempState.depth) """ *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ if flag[0] == 3: if self.closed[flag[1]].depth > tempState.depth: self.closed.remove(self.closed[flag[1]]) self.openlist.append(tempState) # TODO your code end here # → move right if (col + 1) < len(walk_state): # TODO your code start here """ *get the 2d array of current *define a temp 2d array and loop over current.tile_seq *pass the value from current.tile_seq to temp array """ tempArray = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) for i in range(len(self.current.tile_seq)): for j in range(len(self.current.tile_seq[i])): tempArray[i, j] = self.current.tile_seq[i, j] """ *↑ is correspond to (row, col) and (row, col+1) *exchange these two tiles of temp """ tempHolder = tempArray[row, col] tempArray[row, col] = tempArray[row, col + 1] tempArray[row, col + 1] = tempHolder #print("temp right \n", tempArray) """ *call check_inclusive(temp state) *define a new temp state via temp array """ tempState = State() tempState.tile_seq = tempArray tempState.depth = self.depth flag = self.check_inclusive(tempState) # print("TempState \n", tempState.tile_seq) """ *do the next steps according to flag *if flag = 1 //not in open and closed *begin *assign the child a heuristic value via heuristic_test(temp state); *add the child to open *end; """ if flag[0] == 1: self.heuristic_test(tempState) self.openlist.append(tempState) # print("open list \n", self.openlist) """ *if flag = 2 //in the open list *if the child was reached by a shorter path *then give the state on open the shorter path """ if flag[0] == 2: if self.openlist[flag[1]].depth > tempState.depth: self.openlist[flag[1]].depth = tempState.depth # print("depth", tempState.depth) """ *if flag = 3 //in the closed list *if the child was reached by a shorter path then *begin *remove the state from closed; *add the child to open *end; """ if flag[0] == 3: if self.closed[flag[1]].depth > tempState.depth: self.closed.remove(self.closed[flag[1]]) self.openlist.append(tempState) # TODO your code end here # sort the open list first by h(n) then g(n) self.openlist.sort(key=self.sortFun) self.current = self.openlist[0] """ * Solve the game using heuristic search strategies * There are three types of heuristic rules: * (1) Tiles out of place * (2) Sum of distances out of place * (3) 2 x the number of direct tile reversals * evaluation function * f(n) = g(n) + h(n) * g(n) = depth of path length to start state * h(n) = (1) + (2) + (3) """ def heuristic_test(self, current): curr_seq = current.tile_seq goal_seq = self.goal.tile_seq # (1) Tiles out of place h1 = 0 # TODO your code start here """ *loop over the curr_seq *check the every entry in curr_seq with goal_seq """ for i in range(len(curr_seq)): for j in range(len(curr_seq[i])): if curr_seq[i, j] != goal_seq[i, j]: h1 += 1 # TODO your code end here # (2) Sum of distances out of place h2 = 0 # TODO your code start here """ *loop over the goal_seq and curr_seq in nested way *locate the entry which has the same value in *curr_seq and goal_seq then calculate the offset *through the absolute value of two differences *of curr_row-goal_row and curr_col-goal_col *absoulte value can be calculated by abs(...) """ # TODO your code end here # (3) 2 x the number of direct tile reversals h3 = 0 # TODO your code start here """ *loop over the curr_seq *use a Γ(gamma)shap slider to walk throught curr_seq and goal_seq *rule out the entry with value 0 *set the boundry restriction *don't forget to time 2 at last *for example *goal_seq 1 2 3 curr_seq 2 1 3 the Γ shape starts * 4 5 6 4 5 6 * 7 8 0 7 8 0 *with 1 2 in goal_seq and 2 1 in curr_seq thus the * 4 4 *reversal is 1 2 and 2 1 """ # TODO your code end here h3 *= 2 # set the heuristic value for current state current.weight = current.depth + h1 + h2 + h3 # You can choose to print all the states on the search path, or just the start and goal state def run(self): # output the start state print("start state !!!!!") print(self.current.tile_seq) path = 0 while not self.current.equals(self.goal): self.state_walk() print("decision \n", self.current.tile_seq) path += 1 print("It took ", path, " iterations") print("The length of the path is: ", self.current.depth) # output the goal state target = self.goal.tile_seq print(target) print("goal state !!!!!")