def astar(state, heuristic): queue = [] # prevStateDict[state] = (previous state, move to get there, g) prevStateDict = {} prevStateDict[state] = (None, None, 0) heappush(queue, (heuristic(state), state)) while queue: f, state = heappop(queue) # f is total astar cost if state == puzzle8.solution(): prevState = prevStateDict[state] path = [] #print("backtracing") while prevState[0]: path = [prevState[1]] + path prevState = prevStateDict[prevState[0]] return path g = f - heuristic(state) # g is cost in moves to get to current state neighbors = puzzle8.neighbors(puzzle8.blankSquare(state)) for neighbor in neighbors: newState = puzzle8.moveBlank(state, neighbor) if newState not in prevStateDict: prevStateDict[newState] = (state, neighbor, g+1) else: if prevStateDict[newState][2] > g+1: # if we just found a cheaper path to newState, override prevStateDict prevStateDict[newState] = (state, neighbor, g+1) f = g + 1 + heuristic(newState) heappush(queue, (f, newState))
def manhattanDistance(state): manhattanDistance = 0 for i in range(9): tile = puzzle8.getTile(state, i) j = xyposition(puzzle8.solution(), tile) manhattanDistance += math.fabs(puzzle8.xylocation(i)[0] - puzzle8.xylocation(j)[0]) manhattanDistance += math.fabs(puzzle8.xylocation(i)[1] - puzzle8.xylocation(j)[1]) return manhattanDistance
def numWrongTiles(state): '''gives number of tiles differing between given state and solution state''' numWrong = 0 for i in range(0,9): if puzzle8.getTile(state,i) != 0 and \ puzzle8.getTile(state,i) != puzzle8.getTile(puzzle8.solution(),i): numWrong += 1 return numWrong
def testItdeep(self): self.assertEqual(search.itdeep(puzzle8.solution()),[]) self.assertEqual(len(search.itdeep(puzzle8.randomState(1))),1) testPuzzle = puzzle8.state([1,2,0,8,6,3,7,5,4]) self.assertEqual(search.itdeep(testPuzzle),[5,8,7,4]) random.seed(12345) randomMoves = 32 testPuzzle2 = puzzle8.randomState(randomMoves) puzzle8.display(testPuzzle2) solnPath = search.itdeep(testPuzzle2) self.assertLessEqual(len(solnPath),randomMoves)
def astar(initial_state, heuristic): fringe = Queue.PriorityQueue() fringe.put((0+heuristic(initial_state), initial_state, [])) while True: h, state, path = fringe.get() if state == puzzle8.solution(): return path zero_position = xyposition(state, 0) for neighbor in puzzle8.neighbors(zero_position): next_state = puzzle8.moveBlank(state, neighbor) # note: we add neighbor/10. to make sure that neighbors are taken out in the appropriate order fringe.put((len(path)+1+heuristic(next_state)+neighbor/10., next_state, path+[[zero_position, neighbor]]))
def manhattanDistance(state): '''gives sum of manhattan distance of all tiles from their respective places in the solution state.''' dist = 0 for i in range(0,9): tile = puzzle8.getTile(state, i) if tile == 0: continue loc1 = puzzle8.xylocation(i) loc2 = puzzle8.xylocation(findTile(puzzle8.solution(), tile)) dist += abs(loc1[0]-loc2[0]) + abs(loc1[1]-loc2[1]) return dist
def depthLimitedDFS(initial_state, depth): fringe = Queue.LifoQueue() fringe.put((initial_state, [])) while not fringe.empty(): state, path = fringe.get() if state == puzzle8.solution(): return path if len(path) == depth: continue zero_position = xyposition(state, 0) for neighbor in puzzle8.neighbors(zero_position): next_state = puzzle8.moveBlank(state, neighbor) fringe.put((next_state, path+[[zero_position, neighbor]])) return False
def recdepthLimitedDFS(state, height): # if found, return if state == puzzle8.solution(): return [] # if we're at the bottom, return if height == 0: return False # find 0 and iterate over neighbors zero_position = xyposition(state, 0) for neighbor in puzzle8.neighbors(zero_position): next_result = depthLimitedDFS(puzzle8.moveBlank(state, neighbor), height-1) # if next_result is a list, we've found a solution if isinstance(next_result, list): return [[zero_position, neighbor]] + next_result # we're out of things to do return False
def recurDeep(state, depthRemaining): '''searches for a path with depth given. if not found, returns [-1].''' if state == puzzle8.solution(): return [] if depthRemaining <= 0: return [-1] neighbors = puzzle8.neighbors(puzzle8.blankSquare(state)) depthRemaining -= 1 for neighbor in neighbors: newState = puzzle8.moveBlank(state, neighbor) possiblePath = recurDeep(newState, depthRemaining) if -1 not in possiblePath: path = [neighbor] + possiblePath return path return [-1]
def testManhattanDistance(self): self.assertEqual(search.manhattanDistance(puzzle8.solution()),0) self.assertEqual(search.manhattanDistance(puzzle8.randomState(1)),1) self.assertEqual(search.manhattanDistance(self.offTwoPuzzle),16)
def testNumWrongTiles(self): self.assertEqual(search.numWrongTiles(puzzle8.solution()),0) self.assertEqual(search.numWrongTiles(puzzle8.randomState(1)),1) self.assertEqual(search.numWrongTiles(self.offTwoPuzzle),8)
def numWrongTiles(state): numWrongTiles = 0 for i in range(9): if puzzle8.getTile(state, i) != puzzle8.getTile(puzzle8.solution(), i): numWrongTiles += 1 return numWrongTiles