def __init__(self, square_size=3, puzzle=None): self.square_size = square_size self.goal_block_location = self.in_order_goal_block_location self.goal_state = self.in_order_goal_state #self.heuristic = self.heuristic_misplaced self.heuristic = self.heuristic_manhatten_distance self.puzzle = SliderPuzzle(self.square_size, puzzle)
def test_block_location(self): sp = SliderPuzzle(4) assert sp.current_block_location(15) == (3, 3) assert sp.current_block_location(0) == (0, 0) sp = SliderPuzzle(3, [8, 1, 2, 7, 4, 5, 6, 3, 0 ]) assert sp.current_block_location(8) == (0, 0) assert sp.current_block_location(0) == (2, 2) assert sp.current_block_location(7) == (1, 0) assert sp.current_block_location(3) == (2, 1)
def test_possible_states(self): sp = SliderPuzzle(3) pm = sp.possible_moves() assert len(pm) == 2 assert pm[0] == [ 1, 0, 2, 3, 4, 5, 6, 7, 8 ] assert pm[1] == [ 3, 1, 2, 0, 4, 5, 6, 7, 8 ] sp.puzzle = sp.swapped_state(0, 4) pm = sp.possible_moves() assert len(pm) == 4 sp.puzzle = [4, 1, 2, 3, 0, 5, 6, 7, 8] exp_states = [ [4, 1, 2, 0, 3, 5, 6, 7, 8], [4, 1, 2, 3, 5, 0, 6, 7, 8], [4, 0, 2, 3, 1, 5, 6, 7, 8], [4, 1, 2, 3, 7, 5, 6, 0, 8] ] pm = sp.possible_moves() assert len(pm) == len(exp_states) for state in pm: assert state in exp_states
def test_tour(self): sp = SliderPuzzle(3) assert sp.puzzle == [0, 1, 2, 3, 4, 5, 6, 7, 8] ps = sp.possible_moves() exp_p = [ [1, 0, 2, 3, 4, 5, 6, 7, 8], [3, 1, 2, 0, 4, 5, 6, 7, 8] ] assert len(ps) == len(exp_p) for state in exp_p: assert state in ps sp.puzzle = sp.swapped_blocks(0, 1) assert sp.puzzle == [1, 0, 2, 3, 4, 5, 6, 7, 8] ps = sp.possible_moves() exp_p = [ [0, 1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 0, 3, 4, 5, 6, 7, 8], [1, 4, 2, 3, 0, 5, 6, 7, 8] ] assert len(ps) == len(exp_p) for state in exp_p: assert state in ps sp.puzzle = sp.swapped_blocks(0, 2) assert sp.puzzle == [1, 2, 0, 3, 4, 5, 6, 7, 8] ps = sp.possible_moves() exp_p = [ [1, 0, 2, 3, 4, 5, 6, 7, 8], [1, 2, 5, 3, 4, 0, 6, 7, 8] ] assert len(ps) == len(exp_p) for state in exp_p: assert state in ps sp.puzzle = sp.swapped_blocks(0, 5) assert sp.puzzle == [1, 2, 5, 3, 4, 0, 6, 7, 8] ps = sp.possible_moves() exp_p = [ [1, 2, 0, 3, 4, 5, 6, 7, 8], [1, 2, 5, 3, 0, 4, 6, 7, 8], [1, 2, 5, 3, 4, 8, 6, 7, 0] ] assert len(ps) == len(exp_p) for state in exp_p: assert state in ps sp.puzzle = sp.swapped_blocks(0, 4) assert sp.puzzle == [1, 2, 5, 3, 0, 4, 6, 7, 8] ps = sp.possible_moves() exp_p = [ [1, 0, 5, 3, 2, 4, 6, 7, 8], [1, 2, 5, 3, 7, 4, 6, 0, 8], [1, 2, 5, 0, 3, 4, 6, 7, 8], [1, 2, 5, 3, 4, 0, 6, 7, 8] ] assert len(ps) == len(exp_p) for state in exp_p: assert state in ps sp.puzzle = sp.swapped_blocks(0, 3) assert sp.puzzle == [1, 2, 5, 0, 3, 4, 6, 7, 8] ps = sp.possible_moves() exp_p = [ [0, 2, 5, 1, 3, 4, 6, 7, 8], [1, 2, 5, 3, 0, 4, 6, 7, 8], [1, 2, 5, 6, 3, 4, 0, 7, 8] ] assert len(ps) == len(exp_p) for state in exp_p: assert state in ps sp.puzzle = sp.swapped_blocks(0, 6) assert sp.puzzle == [1, 2, 5, 6, 3, 4, 0, 7, 8] ps = sp.possible_moves() exp_p = [ [1, 2, 5, 0, 3, 4, 6, 7, 8], [1, 2, 5, 6, 3, 4, 7, 0, 8] ] assert len(ps) == len(exp_p) for state in exp_p: assert state in ps sp.puzzle = sp.swapped_blocks(0, 7) assert sp.puzzle == [1, 2, 5, 6, 3, 4, 7, 0, 8] ps = sp.possible_moves() exp_p = [ [1, 2, 5, 6, 0, 4, 7, 3, 8], [1, 2, 5, 6, 3, 4, 0, 7, 8], [1, 2, 5, 6, 3, 4, 7, 8, 0] ] assert len(ps) == len(exp_p) for state in exp_p: assert state in ps sp.puzzle = sp.swapped_blocks(0, 8) assert sp.puzzle == [1, 2, 5, 6, 3, 4, 7, 8, 0] ps = sp.possible_moves() exp_p = [ [1, 2, 5, 6, 3, 0, 7, 8, 4], [1, 2, 5, 6, 3, 4, 7, 0, 8] ] assert len(ps) == len(exp_p) for state in exp_p: assert state in ps
def test_swap_state(self): sp = SliderPuzzle(3) swapped_sp = sp.swapped_state(0,8) assert swapped_sp[0] == 8 assert swapped_sp[-1] == 0
class SliderSearch(object): """ Represents a searcher on SliderPuzzles """ def __init__(self, square_size=3, puzzle=None): self.square_size = square_size self.goal_block_location = self.in_order_goal_block_location self.goal_state = self.in_order_goal_state #self.heuristic = self.heuristic_misplaced self.heuristic = self.heuristic_manhatten_distance self.puzzle = SliderPuzzle(self.square_size, puzzle) def in_order_goal_block_location(self, block_number): """ Gets the goal block location as a tuple (rowindex, columnindex) Assumes goal state is all values in order """ return (block_number // self.square_size, block_number % self.square_size) def in_order_goal_state(self): """ Gets the goal state for the puzzle when goal is all values in order """ return [x for x in xrange(self.square_size**2)] def heuristic_misplaced(self, state): """ Gets the heuristic value for the given state using a simple count of misplaced blocks """ misplaced = 0 for x in self.puzzle.puzzle: if self.goal_block_location(x) != self.puzzle.current_block_location(x, state): misplaced += 1 return misplaced def heuristic_manhatten_distance(self, state): """ Gets the heuristic value for the given state using manhatten distance """ m_distances = [abs((self.puzzle.current_block_location(x, state)[0] - self.goal_block_location(x)[0])) + abs((self.puzzle.current_block_location(x, state)[1] - self.goal_block_location(x)[1])) for x in state] return sum(m_distances) def search_a_star(self): """ Find best path solution using A* Returns the list of states from initial to goal or None if no solution possible """ frontier = [] explored = set() frontier_seen = {} goal = self.goal_state() initial = (self.heuristic(self.puzzle.puzzle), 0, Node(self.puzzle.puzzle, None, 0)) frontier_seen[str(initial[2].state)] = 0 heapq.heappush(frontier, initial) while 1: if not frontier: return None else: # choose node sel_node = heapq.heappop(frontier) selected = sel_node[2] stsel = str(selected) if frontier_seen[stsel] <= sel_node[1]: if (selected.state == goal): path = [] while selected.parent is not None: path.append(selected.state) selected = selected.parent path.append(selected.state) path = path[::-1] return path else: # Expand the node self.puzzle.puzzle = selected.state ps = self.puzzle.possible_moves() for x in ps: strx = str(x) vx = (self.heuristic(x) + selected.path_cost+1, selected.path_cost+1, Node(x, selected, selected.path_cost+1)) if strx in frontier_seen: if frontier_seen[strx] > vx[1]: heapq.heappush(frontier, vx) frontier_seen[strx] = vx[1] elif vx not in explored: heapq.heappush(frontier, vx) frontier_seen[strx] = vx[1] # Move checked into explored explored.add(sel_node)