def canvas_click(self, event: tk.EventType) -> None: x = math.floor((event.x - self.app_frame.x_axis_padding) / self.app_frame.grid_col_width) y = math.floor((event.y - self.app_frame.y_axis_padding) / self.app_frame.grid_row_height) if self.choosing_start: self.start = SearchNode(GridState(x, y)) self.chose_start = True self.choosing_start = False self.app_frame.entry1.delete(0, tk.END) self.app_frame.entry1.insert(0, str(self.start.state.x)) self.app_frame.entry2.delete(0, tk.END) self.app_frame.entry2.insert(0, str(self.start.state.y)) elif self.choosing_goal: self.goal = SearchNode(GridState(x, y)) self.chose_goal = True self.choosing_goal = False self.app_frame.entry3.delete(0, tk.END) self.app_frame.entry3.insert(0, str(self.goal.state.x)) self.app_frame.entry4.delete(0, tk.END) self.app_frame.entry4.insert(0, str(self.goal.state.y)) else: print(f"clicked ({x}, {y})") return self.draw_initial()
def apply_action(self, state: GridState, action: CardinalGridAction) -> GridState: if not self.is_defined(state): raise StateDoesNotExistError(state) if not self.is_valid(state): raise StateNotValidError(state) x = 0 y = 0 if action == CardinalGridAction.UP: y -= 1 elif action == CardinalGridAction.RIGHT: x += 1 elif action == CardinalGridAction.DOWN: y += 1 elif action == CardinalGridAction.LEFT: x -= 1 else: raise NotImplementedError(f"GridAction {action} not supported.") test_state = GridState(state.x + x, state.y + y) valid = self.is_valid(test_state) if not valid: raise StateNotValidError(test_state) new_state = GridState(state.x + x, state.y + y, valid=valid) if not self.is_defined(new_state): raise StateDoesNotExistError return new_state
def test_grid_state_undefined(): undefined_state = GridState(-1, env.get_random().y) assert not env.is_defined(undefined_state) undefined_state = GridState(env.get_random().x, -1) assert not env.is_defined(undefined_state) undefined_state = GridState(env._width + 1, env.get_random().y) assert not env.is_defined(undefined_state) undefined_state = GridState(env.get_random().x, env._height + 1) assert not env.is_defined(undefined_state)
def test_simple_shortest_search(): """Test a search where the start and goal are neighbors. Ensure correct path and open list sizes. Assumes start is in an 'open area' where all neighbors are valid. """ start = GridState(18, 24, valid=True) goal = GridState(19, 24, valid=True) astar = GenericBFS(env, start=start, goal=goal) astar.get_path() assert len(astar.path) == 2 # start, goal
def test_simple_shortest_search(): """Test a search where the start and goal are neighbors. Ensure correct path and open list sizes. Assumes start is in an 'open area' where all neighbors are valid. """ start = GridState(18, 24, valid=True) goal = GridState(19, 24, valid=True) astar = GenericAstar(env, heuristic=OctileGridHeuristic(), start=start, goal=goal) astar.get_path() print(astar.open) assert len(astar.path) == 2 # start, goal assert astar.nodes_expanded == 2 # start, goal assert len(astar.open) == 7 # start + 8 neighbors - start - goal
def test_undefined_goal(): """Test all 4 map boundaries <0, >width, <0, >height. if unchecked, negatives would index backwards into grid.env[][] """ bad_goal = GridState(-1, env.get_random().y) with pytest.raises(StateDoesNotExistError): GenericAstar(env, heuristic=OctileGridHeuristic(), goal=bad_goal) bad_goal = GridState(env.get_random().x, -1) with pytest.raises(StateDoesNotExistError): GenericAstar(env, heuristic=OctileGridHeuristic(), goal=bad_goal) bad_goal = GridState(env.width + 1, env.get_random().y) with pytest.raises(StateDoesNotExistError): GenericAstar(env, heuristic=OctileGridHeuristic(), goal=bad_goal) bad_goal = GridState(env.get_random().x, env._height + 1) with pytest.raises(StateDoesNotExistError): GenericAstar(env, heuristic=OctileGridHeuristic(), goal=bad_goal)
def test_search_failure_undefined_goal(): """Test scenario where someone bypasses the properties and messes with the private _goal member. Making the _start invalid or undefined after initialization should not impact the search at all. Making the goal invalid should let the search run until it has exhausted the state space and then return no path. """ gastar = get_random_search() gastar._goal = GridState(-1, -1) assert len(gastar.get_path()) == 0
def test_grid_get_actions(): middle_state = GridState(18, 23, valid=True) action_cost_tuples = env.get_actions(middle_state, None) actions = [ OctileGridAction.UP, OctileGridAction.DOWN, OctileGridAction.LEFT, OctileGridAction.RIGHT, OctileGridAction.DOWN_LEFT, OctileGridAction.DOWN_RIGHT, OctileGridAction.UP_LEFT, OctileGridAction.UP_RIGHT ] for action, _ in action_cost_tuples: assert action in actions
def test_grid_apply_action(): undefined_state = GridState(-1, env.get_random().y) with pytest.raises(StateDoesNotExistError): env.apply_action(undefined_state, CardinalGridAction.UP) impassable_state = GridState(18, 9) with pytest.raises(StateNotValidError): env.apply_action(impassable_state, CardinalGridAction.UP) middle_state = GridState(18, 23, valid=True) assert env.apply_action(middle_state, CardinalGridAction.UP) == GridState(18, 22) assert env.apply_action(middle_state, CardinalGridAction.LEFT) == GridState(17, 23) assert env.apply_action(middle_state, CardinalGridAction.DOWN) == GridState(18, 24) assert env.apply_action(middle_state, CardinalGridAction.RIGHT) == GridState(19, 23)
def test_history_on_failure(): """Test to make sure history dict is being filled in with all the correct info for a failed search. Checking keys are correct - not validating data. """ gastar = get_random_search() gastar._goal = GridState(-1, -1) gastar.get_path() assert 'start' in gastar.history assert 'goal' in gastar.history assert 'heuristic' in gastar.history assert 'nodes_expanded' in gastar.history assert 'steps' in gastar.history assert 'path' not in gastar.history for i in range(gastar.history['nodes_expanded'] - 1): step = 'step-' + str(i + 1) assert step in gastar.history['steps'] assert 'expanded' in gastar.history['steps'][step] assert 'to_open' in gastar.history['steps'][step]
def test_grid_state_passable(): passable_state = GridState(18, 10) assert env.is_valid(passable_state) assert not env.is_valid(GridState(18, 9))