Ejemplo n.º 1
0
 def test_update_puzzle(self):
     p = Puzzle(3, 3)
     self.assertEqual(p._grid[0][0], 0)
     self.assertEqual(p._grid[0][1], 1)
     p.update_puzzle('r')
     self.assertEqual(p._grid[0][0], 1)
     self.assertEqual(p._grid[0][1], 0)
     self.assertEqual(p._grid[0][2], 2)
     p.update_puzzle('r')
     self.assertEqual(p._grid[0][0], 1)
     self.assertEqual(p._grid[0][1], 2)
     self.assertEqual(p._grid[0][2], 0)
     p.update_puzzle('dd')
     self.assertEqual(p._grid[0][0], 1)
     self.assertEqual(p._grid[0][1], 2)
     self.assertEqual(p._grid[0][2], 5)
     self.assertEqual(p._grid[1][2], 8)
     self.assertEqual(p._grid[2][2], 0)
     p.update_puzzle('lu')
     self.assertEqual(p._grid[0][0], 1)
     self.assertEqual(p._grid[0][1], 2)
     self.assertEqual(p._grid[0][2], 5)
     self.assertEqual(p._grid[1][2], 8)
     self.assertEqual(p._grid[2][2], 7)
     self.assertEqual(p._grid[2][1], 4)
     self.assertEqual(p._grid[1][1], 0)
     expected = [
         [1, 2, 5],
         [3, 0, 8],
         [6, 4, 7]
     ]
     self.assertEqual(p._grid, expected)
Ejemplo n.º 2
0
def example2():
    """
    This is a difficult puzzle and the choice of search algorithm now really matters. 
    Optimal solution is about 80 moves.
    """
    Joes_puzzle=Puzzle(4, 4, [[15, 11, 8, 12], \
                                [14, 10, 9, 13], \
                                [2, 6, 1, 4], \
                                [3, 7, 5, 0]])

    #Solve using Greedy Best Fist Search. This is really fast (about 0.2s on my machine)
    #but finds a solution w. relatively many moves (206 moves)
    Joes_puzzle.solve_puzzle("gbfs", print_results=True)
Ejemplo n.º 3
0
    def test_heap(self):
        """ 
        Just a test that I understand exactly how heappush of heappop works
        heappop should return the minimal element in the set
        
        """
        frontier = []
        heappush(frontier, (0, 0))
        heappush(frontier, (0, 1))
        self.assertEqual(heappop(frontier), (0, 0))
        self.assertEqual(heappop(frontier), (0, 1))

        frontier = []
        heappush(frontier, (0, 1))
        heappush(frontier, (0, 0))
        self.assertEqual(heappop(frontier), (0, 0))
        self.assertEqual(heappop(frontier), (0, 1))

        p0 = Puzzle(3, 3)
        p1 = Puzzle(3, 3)
        p2 = Puzzle(3, 3)
        p3 = Puzzle(3, 3)
        p4 = Puzzle(3, 3)

        frontier = []
        heappush(frontier, (0, p0))
        heappush(frontier, (1, p1))
        heappush(frontier, (2, p2))
        heappush(frontier, (3, p3))
        heappush(frontier, (4, p4))
        self.assertEqual(heappop(frontier), (0, p0))
        self.assertEqual(heappop(frontier), (1, p1))
        self.assertEqual(heappop(frontier), (2, p2))
        self.assertEqual(heappop(frontier), (3, p3))
        self.assertEqual(heappop(frontier), (4, p4))

        frontier = []
        heappush(frontier, (4, p0))
        heappush(frontier, (3, p1))
        heappush(frontier, (2, p2))
        heappush(frontier, (1, p3))
        heappush(frontier, (0, p4))
        self.assertEqual(heappop(frontier), (0, p4))
        self.assertEqual(heappop(frontier), (1, p3))
        self.assertEqual(heappop(frontier), (2, p2))
        self.assertEqual(heappop(frontier), (3, p1))
        self.assertEqual(heappop(frontier), (4, p0))
Ejemplo n.º 4
0
 def test_recover_path(self):
     p = Puzzle(4, 4)  # start out with initial grid = solved grid
     p1 = p.clone()
     p1.update_puzzle("r")
     p1._last_move = "r"
     p1._parent = p
     self.assertEqual("r", p1.recover_path())
     p2 = p1.clone()
     p2.update_puzzle("d")
     p2._last_move = "d"
     p2._parent = p1
     self.assertEqual("rd", p2.recover_path())
     p3 = p2.clone()
     p3.update_puzzle("d")
     p3._last_move = "d"
     p3._parent = p2
     self.assertEqual("rdd", p3.recover_path())
     # start out other initial grid
     p = Puzzle(3, 3, [[1, 2, 3], [4, 5, 6], [7, 9, 0]])
     p1 = p.clone()
     p1.update_puzzle("l")
     p1._last_move = "l"
     p1._parent = p
     self.assertEqual("l", p1.recover_path())
     p2 = p1.clone()
     p2.update_puzzle("l")
     p2._last_move = "l"
     p2._parent = p1
     self.assertEqual("ll", p2.recover_path())
     p3 = p2.clone()
     p3.update_puzzle("u")
     p3._last_move = "u"
     p3._parent = p2
     self.assertEqual("llu", p3.recover_path())
Ejemplo n.º 5
0
def example1():
    grid = [[6, 3, 4], [8, 5, 2], [1, 7, 0]]
    puzzle = Puzzle(3, 3, grid)
    print("New puzzle:\n", puzzle)
    puzzle.update_puzzle("luru")
    print("Puzzle after a few moves:\n", puzzle)

    #Solve puzzle using Breath First Search:
    puzzle.solve_puzzle("bfs", print_results=True)
Ejemplo n.º 6
0
 def test_current_position(self):
     p = Puzzle(3, 3)
     self.assertEqual(p.current_position(0, 0), (0, 0))
     self.assertEqual(p.current_position(0, 1), (0, 1))
     self.assertEqual(p.current_position(2, 1), (2, 1))
     p._grid = [
         [1, 0, 2],
         [8, 4, 5],
         [6, 7, 3]
     ]
     self.assertEqual(p.current_position(0, 0), (0, 1))
     self.assertEqual(p.current_position(0, 1), (0, 0))
     self.assertEqual(p.current_position(1, 0), (2, 2))
     self.assertEqual(p.current_position(2, 2), (1, 0))
Ejemplo n.º 7
0
 def test_solve_puzzle_ast(self):
     #Let's start out by testing a puzzle, that is already solved.
     p = Puzzle(3, 3)
     path_to_goal, num_expanded_nodes, max_search_depth = p.solve_puzzle_ast()
     self.assertTrue(p.is_solved)
     self.assertEqual(path_to_goal, "")
     self.assertEqual(max_search_depth, 0)
     self.assertEqual(num_expanded_nodes, 0)
     start_time = time.time()
     #Now, let's simply test that all eightpuzzles are solved - plus some basic sanity control
     for grid in eight_puzzles:
         puzzle = Puzzle(3, 3, grid)
         path_to_goal, num_expanded_nodes, max_search_depth = puzzle.solve_puzzle_ast()
         self.assertTrue(puzzle.is_solved)
         self.assertTrue(len(path_to_goal) > 0)
         self.assertTrue(max_search_depth >= len(path_to_goal))
         self.assertTrue(num_expanded_nodes >= max_search_depth)
Ejemplo n.º 8
0
        def test_solve_puzzle_bfs(self):
            #Let's start out by testing a puzzle, that is already solved.
            p = Puzzle(3, 3)
            path_to_goal, num_expanded_nodes, max_search_depth = p.solve_puzzle_bfs()
            self.assertTrue(p.is_solved)
            self.assertEqual(path_to_goal, "")
            self.assertEqual(max_search_depth, 0)
            self.assertEqual(num_expanded_nodes, 0)

            p = Puzzle(3, 3)
            p._grid = [
                [3, 1, 2],
                [6, 4, 5],
                [0, 7, 8]
            ]
            path_to_goal, num_expanded_nodes, max_search_depth = p.solve_puzzle_bfs()
            self.assertTrue(p.is_solved)
            self.assertEqual(path_to_goal, "uu")

            p = Puzzle(3, 3)
            p._grid = [
                [1, 4, 2],
                [3, 7, 5],
                [6, 0, 8]
            ]
            path_to_goal, num_expanded_nodes, max_search_depth = p.solve_puzzle_bfs()
            self.assertTrue(p.is_solved)
            self.assertEqual(path_to_goal, "uul")

            #Now, let's simply test that all eightpuzzles are solved - plus some basic sanity control
            for grid in eight_puzzles:
                puzzle = Puzzle(3, 3, grid)
                path_to_goal, num_expanded_nodes, max_search_depth = puzzle.solve_puzzle_bfs()
                self.assertTrue(puzzle.is_solved)
                self.assertTrue(len(path_to_goal) > 0)
                self.assertTrue(max_search_depth >= len(path_to_goal))
                self.assertTrue(num_expanded_nodes >= max_search_depth)
Ejemplo n.º 9
0
    def test_manhattan_distance(self):
        p = Puzzle(3, 3)
        # Manhattan distance of solved puzzle should be 0.
        self.assertEqual(p.manhattan_dist(), 0)

        p._grid = [
            [1, 0, 2],
            [3, 4, 5],
            [6, 7, 8]
        ]
        self.assertEqual(p.manhattan_dist(), 1)

        p._grid = [
            [2, 1, 0],
            [3, 4, 5],
            [6, 7, 8]
        ]
        self.assertEqual(p.manhattan_dist(), 2)

        p._grid = [
            [2, 0, 1],
            [3, 4, 5],
            [6, 7, 8]
        ]
        self.assertEqual(p.manhattan_dist(), 3)

        p._grid = [
            [6, 1, 2],
            [3, 4, 5],
            [0, 7, 8]
        ]
        self.assertEqual(p.manhattan_dist(), 2)

        p._grid = [
            [6, 1, 2],
            [3, 7, 5],
            [0, 4, 8]
        ]
        self.assertEqual(p.manhattan_dist(), 4)

        p._grid = [
            [6, 1, 2],
            [3, 7, 5],
            [0, 4, 8]
        ]
        self.assertEqual(p.manhattan_dist(), 4)

        p._grid = [
            [6, 8, 7],
            [3, 1, 2],
            [4, 0, 5]
        ]
        expected = 2 + 3 + 3 + 0 + 1 + 1 + 2 + 0 + 1      # = 13

        self.assertEqual(p.manhattan_dist(), expected)

        p._grid = [
            [8, 7, 6],
            [1, 4, 2],
            [5, 3, 0]
        ]
        expected = 4 + 2 + 4 + 2 + 0 + 1 + 3 + 2    # = 18
        self.assertEqual(p.manhattan_dist(), expected)
Ejemplo n.º 10
0
        def test_solve_puzzle_dfs(self):
            #Let's start out by testing a puzzle, that is already solved.
            p = Puzzle(3, 3)
            path_to_goal, num_expanded_nodes, max_search_depth = p.solve_puzzle_dfs()
            self.assertTrue(p.is_solved)
            self.assertEqual(path_to_goal, "")
            self.assertEqual(max_search_depth, 0)
            self.assertEqual(num_expanded_nodes, 0)

            #Now a more interesting example
            #Because of the search order (udlr), depth-first search should be lucky to immediately find the easy solution here.

            p = Puzzle(3, 3)
            p._grid = [
                [3, 1, 2],
                [6, 4, 5],
                [0, 7, 8]
            ]
            path_to_goal, num_expanded_nodes, max_search_depth = p.solve_puzzle_dfs()
            self.assertTrue(p.is_solved)
            self.assertEqual(path_to_goal, "uu")
            self.assertEqual(max_search_depth, 2)
            self.assertEqual(num_expanded_nodes, 2)

            #
            # #Because of the search order (udlr), depth-first search should be lucky to immediately find the easy solution here.
            p = Puzzle(3, 3)
            p._grid = [
                [1, 4, 2],
                [3, 7, 5],
                [6, 0, 8]
            ]
            path_to_goal, num_expanded_nodes, max_search_depth = p.solve_puzzle_dfs()
            self.assertTrue(p.is_solved)
            self.assertEqual(path_to_goal, "uul")
            self.assertEqual(max_search_depth, 3)
            self.assertEqual(num_expanded_nodes, 3)

            #Now, let's simply test that all eightpuzzles are solved - plus some basic sanity control
            for grid in eight_puzzles:
                puzzle = Puzzle(3, 3, grid)
                path_to_goal, num_expanded_nodes, max_search_depth = puzzle.solve_puzzle_dfs()
                self.assertTrue(p.is_solved)
                self.assertTrue(len(path_to_goal) > 0)
                self.assertTrue(max_search_depth >= len(path_to_goal))
                self.assertTrue(num_expanded_nodes >= max_search_depth)
Ejemplo n.º 11
0
 def test_is_solved(self):
     p = Puzzle(4, 4)
     self.assertTrue(p.is_solved())
     p = Puzzle(4, 4)
     p.update_puzzle("ddr")
     self.assertFalse(p.is_solved())
Ejemplo n.º 12
0
    def test_valid_directions(self):
        # up, down, left, right
        p = Puzzle(3, 3)
        self.assertEqual(p.valid_directions(), ["d", "r"])
        p._grid = [
            [1, 2, 5],
            [3, 0, 8],
            [6, 4, 7]
        ]
        self.assertEqual(p.valid_directions(), ["u", "d", "l", "r"])

        p._grid = [
            [1, 0, 5],
            [3, 4, 8],
            [6, 4, 7]
        ]
        self.assertEqual(p.valid_directions(), ["d", "l", "r"])

        p._grid = [
            [1, 4, 0],
            [3, 0, 8],
            [6, 4, 7]
        ]
        self.assertEqual(p.valid_directions(), ["d", "l"])

        p._grid = [
            [1, 4, 3],
            [3, 2, 8],
            [6, 4, 0]
        ]
        self.assertEqual(p.valid_directions(), ["u", "l"])

        p._grid = [
            [1, 4, 3],
            [3, 2, 8],
            [0, 4, 5]
        ]
        self.assertEqual(p.valid_directions(), ["u", "r"])

        p._grid = [
            [1, 4, 3],
            [0, 2, 8],
            [3, 4, 5]
        ]
        self.assertEqual(p.valid_directions(), ["u", "d", "r"])
Ejemplo n.º 13
0
def index():

    if request.method == 'GET':
        action = "new_sample"
        puzzle_dim = 3
        search_type = "ast"
        puzzle_type = "sample"

    else:
        # return(json.dumps(data))
        data = json.loads(request.form["json_data"])
        action = data["requested_action"]
        puzzle_dim = data["puzzle_dim"]
        search_type = data["search_type"]
        puzzle_type = data["puzzle_type"]

    if action == 'new_sample' or action == 'show_solved_puzzle':  # new sample btn or change puzzle size
        if action == 'new_sample':
            if puzzle_dim == 3:
                puzzle_collection = eight_puzzles
            else:
                puzzle_collection = fifteen_puzzles
            puzzle_number = random_choice(range(len(puzzle_collection)))
            puzzle = Puzzle(puzzle_dim, puzzle_dim,
                            puzzle_collection[puzzle_number])._grid
            puzzle_title = "Sample #" + str(puzzle_number + 1)
            puzzle_is_solved = False
        else:
            if puzzle_dim == 3:
                puzzle = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
            else:
                puzzle = [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11],
                          [12, 13, 14, 15]]
            puzzle_title = "Custom puzzle"
            puzzle_is_solved = True

        if puzzle_dim == 3:
            all_search_types = ["ast", "gbfs", "bfs", "dfs"]

        elif puzzle_dim == 4:
            all_search_types = ['ast', 'gbfs']

        data = {
            "puzzle_title": puzzle_title,
            "puzzle": puzzle,
            "original_puzzle": puzzle,
            "puzzle_dim": puzzle_dim,
            "search_type": search_type,
            "puzzle_is_solved": puzzle_is_solved,
            "solution_computed": False,
            "requested_action": action,
            "puzzle_type": puzzle_type,
            "move_count": 0,
            "solve_or_reset_btn_value": "Solve",
            "show_solution_details": False,
            "all_search_types": all_search_types,
            "search_names": {
                "ast": "A*-Search",
                "gbfs": "Greedy Best-First Search ",
                "dfs": "Depth-First Search",
                "bfs": "Breadth-First Search"
            }
        }

    elif action == 'human_move':
        puzzle = Puzzle(puzzle_dim, puzzle_dim, data["puzzle"])
        try:
            puzzle.update_puzzle(data["direction"])
            data["puzzle"] = puzzle._grid
            data["move_count"] += 1
            data["puzzle_is_solved"] = puzzle.is_solved()
            if data["puzzle_type"] == "sample":
                data["solve_or_reset_btn_value"] = "Reset Sample"
            else:
                data["solve_or_reset_btn_value"] = "Solve"
            data["show_solution_details"] = False
            if data["puzzle_type"] == "custom":
                data["original_puzzle"] = data["puzzle"]
        except:
            pass  # Move is off grid

    elif action == 'solve_puzzle':
        puzzle = Puzzle(puzzle_dim, puzzle_dim, data["puzzle"])
        solution_string, num_expanded_nodes, max_search_depth, running_time, max_ram_usage \
            = puzzle.solve_puzzle(data['search_type'])
        data['running_time'] = round(running_time, 5)
        data['max_ram_usage'] = round(max_ram_usage,
                                      2)  # number is in megabytes
        data['num_solution_steps'] = len(solution_string)
        data['num_expanded_nodes'] = num_expanded_nodes
        data['max_search_depth'] = max_search_depth
        data['solution_string'] = solution_string
        data["solution_computed"] = True
        data["show_solution_details"] = True
        if data["puzzle_type"] == "sample":
            data["solve_or_reset_btn_value"] = "Reset Sample"
        else:
            data["solve_or_reset_btn_value"] = "Reset Custom"

        # Compute all board positions on the road to solution:
        puzzle_clone = puzzle.clone()
        animated_solution = []
        for direction in solution_string:
            puzzle_clone.update_puzzle(direction)
            animated_solution.append(puzzle_clone.clone()._grid)
        data['animated_solution'] = animated_solution
        data["final_state"] = animated_solution[-1]

    elif action == 'reset':
        data["solution_computed"] = False
        data["solve_or_reset_btn_value"] = "Solve"
        data["show_solution_details"] = False
        data["puzzle"] = data["original_puzzle"]
        if data["puzzle_type"] == "sample":
            data["move_count"] = 0

    return render_template("index.html", data=data)