diff --git a/astar.py b/astar.py new file mode 100644 index 0000000..89f1642 --- /dev/null +++ b/astar.py @@ -0,0 +1,335 @@ +import heapq +from os import path +from settings import * + + +class Problem: + def __init__(self, initial, goal): + self.initial = initial + self.goal = goal + + def actions(self, state): + moves = [] + if self.turn_left(state): + moves.append('Left') + if self.turn_right(state): + moves.append('Right') + if self.move_forward(state): + moves.append('Forward') + + # print(moves) + return moves + + def turn_left(self, state): + return True + + def turn_right(self, state): + return True + + def move_forward(self, state): + + a_row = 0 + a_column = 0 + + for row in range(MAP_SIZE): + for column, pos in enumerate(state[row]): + if pos == ">": + a_row = row + a_column = column + + if a_column == MAP_SIZE-1: + return False + elif state[a_row][a_column+1] == '.': + return True + elif state[a_row][a_column+1] == 'p': + return True + return False + if pos == "<": + a_row = row + a_column = column + + if a_column == 0: + return False + elif state[a_row][a_column-1] == '.': + return True + return False + + if pos == "v": + a_row = row + a_column = column + + if a_row == MAP_SIZE-1: + return False + elif state[a_row+1][a_column] == '.': + return True + return False + if pos == "^": + a_row = row + a_column = column + + if row == 0: + return False + elif state[a_row-1][a_column] == '.': + return True + return False + + def turn_me_or_move(self, state, do_it): + + temp_map = [list(item) for item in state] + + # print(temp_map) + + #a_row = 0 + #a_column = 0 + + for row in range(MAP_SIZE): + for column, pos in enumerate(temp_map[row]): + if pos == ">": + a_row = row + a_column = column + #print("a_row:" + str(a_row)) + #print("a_column" + str(a_column)) + + if(do_it == 'Left'): + temp_map[a_row][a_column] = "^" + if(do_it == 'Right'): + temp_map[a_row][a_column] = 'v' + if(do_it == 'Forward'): + temp_map[a_row][a_column] = '.' + temp_map[a_row][a_column+1] = '>' + return temp_map + + if pos == "<": + a_row = row + a_column = column + if(do_it == 'Left'): + temp_map[a_row][a_column] = 'v' + if(do_it == 'Right'): + temp_map[a_row][a_column] = '^' + if(do_it == 'Forward'): + temp_map[a_row][a_column] = '.' + temp_map[a_row][a_column-1] = '<' + return temp_map + if pos == "v": + a_row = row + a_column = column + if(do_it == 'Left'): + temp_map[a_row][a_column] = '>' + if(do_it == 'Right'): + temp_map[a_row][a_column] = '<' + if(do_it == 'Forward'): + temp_map[a_row][a_column] = '.' + temp_map[a_row+1][a_column] = 'v' + return temp_map + if pos == "^": + a_row = row + a_column = column + if(do_it == 'Left'): + temp_map[a_row][a_column] = '<' + if(do_it == 'Right'): + temp_map[a_row][a_column] = '>' + if(do_it == 'Forward'): + temp_map[a_row][a_column] = '.' + temp_map[a_row-1][a_column] = '^' + return temp_map + return temp_map + + def result(self, state, action): + new_state = [] + + if action == 'Left': + new_state = self.turn_me_or_move(state, 'Left') + elif action == 'Right': + new_state = self.turn_me_or_move(state, 'Right') + elif action == 'Forward': + new_state = self.turn_me_or_move(state, 'Forward') + + super_new_state = tuple(map(tuple, new_state)) + + return super_new_state + + def goal_test(self, state): + if self.goal == state: + return True + return False + + def path_cost(self, c, state1, action, state2, in_puddle1, in_puddle2): + + + return c+1 + + # funkcja heurystyki + def h(self, node): + node_row = node.row + node_column = node.column + + + + +class Node: + def __init__(self, state, parent=None, action=None, path_cost=0): + """Create a search tree Node, derived from a parent by an action.""" + self.state = state + self.parent = parent + self.action = action + self.path_cost = path_cost + + self.in_puddle = False + + #self.row = row + #self.column = column + + def __repr__(self): + return "".format(self.state) + + def expand(self, problem): + """List the nodes reachable in one step from this node.""" + return [self.child_node(problem, action) + for action in problem.actions(self.state)] + + def child_node(self, problem, action): + next_state = problem.result(self.state, action) + next_node = Node(next_state, self, action, problem.path_cost(self.path_cost, self.state, action, next_state, in_puddle)) + return next_node + + def where_am_i(self): + temp_map = [list(item) for item in state] + + for row in range(MAP_SIZE): + for column, pos in enumerate(temp_map[row]): + if pos == ">" or pos == "<" or pos == "^" or pos == "v": + self.row = row + self.column = column + + + + + + + + def __eq__(self, other): + return isinstance(other, Node) and self.state == other.state + + def __hash__(self): + # We use the hash value of the state + # stored in the node instead of the node + # object itself to quickly search a node + # with the same state in a Hash Table + return hash(self.state) + + +class PriorityQueue: + """A Queue in which the minimum (or maximum) element (as determined by f and + order) is returned first. + If order is 'min', the item with minimum f(x) is + returned first; if order is 'max', then it is the item with maximum f(x). + Also supports dict-like lookup.""" + + def __init__(self, order='min', f=lambda x: x): + self.heap = [] + if order == 'min': + self.f = f + elif order == 'max': # now item with max f(x) + self.f = lambda x: -f(x) # will be popped first + else: + raise ValueError("Order must be either 'min' or 'max'.") + + def append(self, item): + """Insert item at its correct position.""" + heapq.heappush(self.heap, (self.f(item), item)) + + def extend(self, items): + """Insert each item in items at its correct position.""" + for item in items: + self.append(item) + + def pop(self): + """Pop and return the item (with min or max f(x) value) + depending on the order.""" + if self.heap: + return heapq.heappop(self.heap)[1] + else: + raise Exception('Trying to pop from empty PriorityQueue.') + + def __len__(self): + """Return current capacity of PriorityQueue.""" + return len(self.heap) + + def __contains__(self, key): + """Return True if the key is in PriorityQueue.""" + return any([item == key for _, item in self.heap]) + + def __getitem__(self, key): + """Returns the first value associated with key in PriorityQueue. + Raises KeyError if key is not present.""" + for value, item in self.heap: + if item == key: + return value + raise KeyError(str(key) + " is not in the priority queue") + + def __delitem__(self, key): + """Delete the first occurrence of key.""" + try: + del self.heap[[item == key for _, item in self.heap].index(True)] + except ValueError: + raise KeyError(str(key) + " is not in the priority queue") + heapq.heapify(self.heap) + + +class Astar: + @staticmethod + def best_first_graph_search(problem, f, display=False): + """Search the nodes with the lowest f scores first. + You specify the function f(node) that you want to minimize; for example, + if f is a heuristic estimate to the goal, then we have greedy best + first search; if f is node.depth then we have breadth-first search. + There is a subtlety: the line "f = memoize(f, 'f')" means that the f + values will be cached on the nodes as they are computed. So after doing + a best first search you can examine the f values of the path returned.""" + #f = memoize(f, 'f') + node = Node(problem.initial) + # PriorityQueue ma przechowywac g+h + frontier = PriorityQueue('min', f) + frontier.append(node) + explored = set() + while frontier: + node = frontier.pop() + if problem.goal_test(node.state): + if display: + print(len(explored), "paths have been expanded and", + len(frontier), "paths remain in the frontier") + return node + explored.add(node.state) + for child in node.expand(problem): + if child.state not in explored and child not in frontier: + frontier.append(child) + elif child in frontier: + if f(child) < frontier[child]: + del frontier[child] + frontier.append(child) + return None + + @staticmethod + def loadMap(map_name=''): + maze = [] + map_folder = path.dirname(__file__) + with open(path.join(map_folder, map_name), 'rt') as f: + for line in f: + maze.append(line.rstrip('\n')) + + #print(maze) + return maze + + @staticmethod + def run(): + initial_map = tuple(map(tuple, Astar.loadMap('map.txt'))) + goal_map = tuple(map(tuple, Astar.loadMap('goal_map.txt'))) + problem = Problem(initial_map, goal_map) + + #BFS.print_node_state(initial_map) + #BFS.print_node_state(goal_map) + + result = Astar.breadth_first_graph_search(problem) + print(result) + return result + #print(BFS.print_node_state(result)) diff --git a/astar2.py b/astar2.py new file mode 100644 index 0000000..f067005 --- /dev/null +++ b/astar2.py @@ -0,0 +1,542 @@ +from os import path +import heapq + +from settings import * +from sprites import Direction + + +class PlanRoute(): + """ The problem of moving the Hybrid Wumpus Agent from one place to other """ + + def __init__(self, initial, goal, allowed, puddles=None, dimrow=None): + """ Define goal state and initialize a problem """ + self.initial = initial + self.goal = goal + self.dimrow = dimrow + self.goal = goal + self.allowed = allowed + self.puddles = puddles + + def actions(self, state): + """ Return the actions that can be executed in the given state. + The result would be a list, since there are only three possible actions + in any given state of the environment """ + + possible_actions = ['Forward', 'Left', 'Right'] + x, y = state.get_location() + orientation = state.get_orientation() + + # Prevent Bumps + if x == 1 and orientation == 'LEFT': + if 'Forward' in possible_actions: + possible_actions.remove('Forward') + if y == 1 and orientation == 'DOWN': + if 'Forward' in possible_actions: + possible_actions.remove('Forward') + if x == self.dimrow and orientation == 'RIGHT': + if 'Forward' in possible_actions: + possible_actions.remove('Forward') + if y == self.dimrow and orientation == 'UP': + if 'Forward' in possible_actions: + possible_actions.remove('Forward') + + return possible_actions + + def result(self, state, action): + """ Given state and action, return a new state that is the result of the action. + Action is assumed to be a valid action in the state """ + x, y = state.get_location() + #proposed_loc = list() + proposed_loc = [] + + # Move Forward + if action == 'Forward': + if state.get_orientation() == 'UP': + proposed_loc = [x, y + 1] + elif state.get_orientation() == 'DOWN': + proposed_loc = [x, y - 1] + elif state.get_orientation() == 'LEFT': + proposed_loc = [x - 1, y] + elif state.get_orientation() == 'RIGHT': + proposed_loc = [x + 1, y] + else: + raise Exception('InvalidOrientation') + + # Rotate counter-clockwise + elif action == 'Left': + if state.get_orientation() == 'UP': + state.set_orientation('LEFT') + elif state.get_orientation() == 'DOWN': + state.set_orientation('RIGHT') + elif state.get_orientation() == 'LEFT': + state.set_orientation('DOWN') + elif state.get_orientation() == 'RIGHT': + state.set_orientation('UP') + else: + raise Exception('InvalidOrientation') + + # Rotate clockwise + elif action == 'Right': + if state.get_orientation() == 'UP': + state.set_orientation('RIGHT') + elif state.get_orientation() == 'DOWN': + state.set_orientation('LEFT') + elif state.get_orientation() == 'LEFT': + state.set_orientation('UP') + elif state.get_orientation() == 'RIGHT': + state.set_orientation('DOWN') + else: + raise Exception('InvalidOrientation') + + if tuple(proposed_loc) in self.allowed: + state.set_location(proposed_loc[0], [proposed_loc[1]]) + + return state + + def goal_test(self, state): + """ Given a state, return True if state is a goal state or False, otherwise """ + + return state.get_location() == self.goal.get_location() + + def path_cost(self, c, state1, action, state2): + """Return the cost of a solution path that arrives at state2 from + state1 via action, assuming cost c to get up to state1. If the problem + is such that the path doesn't matter, this function will only look at + state2. If the path does matter, it will consider c and maybe state1 + and action. The default method costs 1 for every step in the path.""" + + if action == "Forward" or action == "Left" or action == "Right": + + + x1, y1 = state1.get_location() + location1 = tuple([x1, y1]) + x2, y2 = state2.get_location() + location2 = tuple([x1, y1]) + + + if location2 in self.puddles: + return c + 1 + if location1 == location2 and state1 in self.puddles: + return c + 1 + return c + + def h(self, node): + """ Return the heuristic value for a given state.""" + + # Manhattan Heuristic Function + x1, y1 = node.state.get_location() + x2, y2 = self.goal.get_location() + + return abs(x2 - x1) + abs(y2 - y1) + + +class Node: + def __init__(self, state, parent=None, action=None, path_cost=0): + """Create a search tree Node, derived from a parent by an action.""" + self.state = state #AgentPosition? + self.parent = parent + self.action = action + self.path_cost = path_cost + + def __repr__(self): + return "".format(self.state) + + def solution(self): + """Return the sequence of actions to go from the root to this node.""" + return [node.action for node in self.path()[1:]] + + + def expand(self, problem): + """List the nodes reachable in one step from this node.""" + return [self.child_node(problem, action) + for action in problem.actions(self.state)] + + def child_node(self, problem, action): + + next_state = problem.result(self.state, action) + next_node = Node(next_state, self, action, problem.path_cost( + self.path_cost, self.state, action, next_state)) + print(problem.path_cost( + self.path_cost, self.state, action, next_state)) + return next_node + + def __eq__(self, other): + return isinstance(other, Node) and self.state == other.state + + def __hash__(self): + # We use the hash value of the state + # stored in the node instead of the node + # object itself to quickly search a node + # with the same state in a Hash Table + return hash(self.state) + + def path(self): + """Return a list of nodes forming the path from the root to this node.""" + node, path_back = self, [] + while node: + path_back.append(node) + node = node.parent + return list(reversed(path_back)) + + +class AgentPosition: + def __init__(self, x, y, orientation): + self.X = x + self.Y = y + self.orientation = orientation + + def get_location(self): + return self.X, self.Y + + def set_location(self, x, y): + self.X = x + self.Y = y + + def get_orientation(self): + return self.orientation + + def set_orientation(self, orientation): + self.orientation = orientation + + def __eq__(self, other): + if (other.get_location() == self.get_location() and + other.get_orientation() == self.get_orientation()): + return True + else: + return False + + def __hash__(self): + return hash((self.X, self.Y, self.orientation)) + + +class SweeperAgent: + def __init__(self, dimensions=None): + self.dimrow = dimensions + self.current_position = None + self.orientation = "" + self.initial = set() + self.goal = set() + self.allowed_points = set() + self.puddle_points = set() + + + def where_am_i(self): + temp_map = [list(item) for item in SweeperAgent.loadMap("map.txt")] + + for row in range(MAP_SIZE): + for column, pos in enumerate(temp_map[row]): + if pos == ">" or pos == "<" or pos == "^" or pos == "v": + self.row = row + self.column = column + + return row, column + + # add orientation + + def where_to_go(self): + temp_map = [list(item) for item in SweeperAgent.loadMap("goal_map.txt")] + + for row in range(MAP_SIZE): + for column, pos in enumerate(temp_map[row]): + if pos == ">" or pos == "<" or pos == "^" or pos == "v": + self.row = row + self.column = column + + return row, column + + @staticmethod + def set_allowed(allowed_points): + temp_map = [list(item) for item in SweeperAgent.loadMap('map.txt')] + + a_row = 0 + a_column = 0 + + for row in range(MAP_SIZE): + for column, pos in enumerate(temp_map[row]): + if pos == "." or pos == 'p' or pos == '>' or pos == '<' or pos == 'v' or pos == '^': + a_row = row + a_column = column + location = tuple([a_row, a_column]) + allowed_points.add(location) + + @staticmethod + def set_puddles(puddle_points): + temp_map = [list(item) for item in SweeperAgent.loadMap('map.txt')] + + a_row = 0 + a_column = 0 + + for row in range(MAP_SIZE): + for column, pos in enumerate(temp_map[row]): + if pos == "p" : + a_row = row + a_column = column + location = tuple([a_row, a_column]) + puddle_points.add(location) + + + @staticmethod + def get_goal(): + temp_map = [list(item) for item in SweeperAgent.loadMap('goal_map.txt')] + + a_row = 0 + a_column = 0 + + for row in range(MAP_SIZE): + for column, pos in enumerate(temp_map[row]): + if pos == '>' or pos == '<' or pos == 'v' or pos == '^': + a_row = row + a_column = column + return a_row, a_column + + + @staticmethod + def set_initial(initial): + temp_map = [list(item) for item in SweeperAgent.loadMap('map.txt')] + + a_row = 0 + a_column = 0 + + for row in range(MAP_SIZE): + for column, pos in enumerate(temp_map[row]): + if pos == '>' or pos == '<' or pos == 'v' or pos == '^': + a_row = row + a_column = column + location = tuple([a_row, a_column]) + initial.add(location) + + + + + @staticmethod + def set_orientation(): + temp_map = [list(item) for item in SweeperAgent.loadMap('map.txt')] + + orientation = "" + + for row in range(MAP_SIZE): + for column, pos in enumerate(temp_map[row]): + if pos == ">": + orientation = "RIGHT" + if pos == "<": + orientation = "LEFT" + if pos == "^": + orientation = "UP" + if pos == "v": + orientation = "DOWN" + + return orientation + + @staticmethod + def set_goal_orientation(): + temp_map = [list(item) for item in SweeperAgent.loadMap('goal_map.txt')] + + orientation = "" + + for row in range(MAP_SIZE): + for column, pos in enumerate(temp_map[row]): + if pos == ">": + orientation = "RIGHT" + if pos == "<": + orientation = "LEFT" + if pos == "^": + orientation = "UP" + if pos == "v": + orientation = "DOWN" + + return orientation + + + @staticmethod + def run(self): + self.orientation = SweeperAgent.set_orientation() + goal_orientation = SweeperAgent.set_goal_orientation() + #SweeperAgent.set_initial(self.initial) + #SweeperAgent.set_goal(self.goal) + SweeperAgent.set_allowed(self.allowed_points) + SweeperAgent.set_puddles(self.puddle_points) + + x, y = self.where_am_i() + x1, y1 = SweeperAgent.get_goal() + + agent_position = AgentPosition(x, y, self.orientation) + goal_position = AgentPosition(x1, y1, goal_orientation) + + self.plan_route(agent_position, goal_position, self.allowed_points, self.puddle_points) + + + + """print("allowed: ") + print("(row, column)") + print(sorted(self.allowed_points)) + print("puddles:") + print(sorted(self.puddle_points)) + print("initial:") + print(self.initial) + print("goal:") + print(self.goal) + print("orientation:") + print(self.orientation)""" + + + def plan_route(self, current, goals, allowed, puddles): + problem = PlanRoute(current, goals, allowed, puddles) + return SweeperAgent.astar_search(problem, problem.h).solution() + #return SweeperAgent.astar_search(problem, problem.h) + + + + + + """TODO""" + # liczenie kosztów + # + + @staticmethod + def loadMap(map_name=''): + maze = [] + map_folder = path.dirname(__file__) + with open(path.join(map_folder, map_name), 'rt') as f: + for line in f: + maze.append(line.rstrip('\n')) + + # print(maze) + return maze + + @staticmethod + def astar_search(problem, h=None): + """A* search is best-first graph search with f(n) = g(n)+h(n). + You need to specify the h function when you call astar_search, or + else in your Problem subclass.""" + # h = memoize(h or problem.h, 'h') + return SweeperAgent.best_first_graph_search(problem, lambda n: n.path_cost + h(n)) + #return best_first_graph_search(problem) + + @staticmethod + #def best_first_graph_search(problem, f, display=False): + def best_first_graph_search(problem, f, display=True): + """Search the nodes with the lowest f scores first. + You specify the function f(node) that you want to minimize; for example, + if f is a heuristic estimate to the goal, then we have greedy best + first search; if f is node.depth then we have breadth-first search. + There is a subtlety: the line "f = memoize(f, 'f')" means that the f + values will be cached on the nodes as they are computed. So after doing + a best first search you can examine the f values of the path returned.""" + # f = memoize(f, 'f') + + """TODO""" + # Zaimplementować klasę Node dla Astar + + history = [] + + node = Node(problem.initial) + frontier = PriorityQueue('min', f) + frontier.append(node) + explored = set() + while frontier: + node = frontier.pop() + if problem.goal_test(node.state): + if display: + print(len(explored), "paths have been expanded and", len(frontier), "paths remain in the frontier") + return node + explored.add(node.state) + for child in node.expand(problem): + if child.state not in explored and child not in frontier: + frontier.append(child) + elif child in frontier: + if f(child) < frontier[child]: + del frontier[child] + frontier.append(child) + return None + + + +class PriorityQueue: + """A Queue in which the minimum (or maximum) element (as determined by f and + order) is returned first. + If order is 'min', the item with minimum f(x) is + returned first; if order is 'max', then it is the item with maximum f(x). + Also supports dict-like lookup.""" + + def __init__(self, order='min', f=lambda x: x): + self.heap = [] + if order == 'min': + self.f = f + elif order == 'max': # now item with max f(x) + self.f = lambda x: -f(x) # will be popped first + else: + raise ValueError("Order must be either 'min' or 'max'.") + + def append(self, item): + """Insert item at its correct position.""" + heapq.heappush(self.heap, (self.f(item), item)) + + def extend(self, items): + """Insert each item in items at its correct position.""" + for item in items: + self.append(item) + + def pop(self): + """Pop and return the item (with min or max f(x) value) + depending on the order.""" + if self.heap: + return heapq.heappop(self.heap)[1] + else: + raise Exception('Trying to pop from empty PriorityQueue.') + + def __len__(self): + """Return current capacity of PriorityQueue.""" + return len(self.heap) + + def __contains__(self, key): + """Return True if the key is in PriorityQueue.""" + return any([item == key for _, item in self.heap]) + + def __getitem__(self, key): + """Returns the first value associated with key in PriorityQueue. + Raises KeyError if key is not present.""" + for value, item in self.heap: + if item == key: + return value + raise KeyError(str(key) + " is not in the priority queue") + + def __delitem__(self, key): + """Delete the first occurrence of key.""" + try: + del self.heap[[item == key for _, item in self.heap].index(True)] + except ValueError: + raise KeyError(str(key) + " is not in the priority queue") + heapq.heapify(self.heap) + + +class Test: + @staticmethod + def run(): + + allowed_points = set() + puddle_points = set() + + initial = set() + goal = set() + + orientation = SweeperAgent.set_orientation() + + SweeperAgent.set_initial(initial) + SweeperAgent.set_goal(goal) + + SweeperAgent.set_allowed(allowed_points) + SweeperAgent.set_puddles(puddle_points) + + + + print("allowed: ") + print("(row, column)") + print(sorted(allowed_points)) + print("puddles:") + print(sorted(puddle_points)) + print("initial:") + print(initial) + print("goal:") + print(goal) + print("orientation:") + print(orientation) \ No newline at end of file diff --git a/astar2_document.txt b/astar2_document.txt new file mode 100644 index 0000000..7f3ae8f --- /dev/null +++ b/astar2_document.txt @@ -0,0 +1,98 @@ + + +class PlanRoute + + actions(state) przyjmuje mape? state + zwraca możliwe akcje agenta + + result(state, action) mapa? state, action(string) + + tworzy listę możliwych ruchów w liście proposed_loc + sprawdza, czy współrzędne w proposed_loc znajdują się w zbiorze allowed + + ustawia kierunek agenta oraz nowe położenie na mapie + zwraca state + + goal_test(state) przyjmuje state + sprawdza czy stan docelowy zgadza się ze stanem obecnym + zwraca wartość True lub False + + path_cost(c, state1, action, state2) + ocenia nowy koszt po zmianie stanu + zwraca nowy koszt + + def h(node) funkcja heurystyki, przyjmuje objekt klasy node + + przypisuje zmiennym x i y wartość współrzędnych + za pomocą funkcji get_location() + + mamy xy dla stanu obecnego + mamy xy dla stanu docelowego + + zwraca ogległość + + +class Node + + expand(problem) przyjmuje klasę problem + + tworzy węzły potomne na podstawie możliwych akcji + + zwraca listę węzłów potomnych + + child_node(problem, action) przyjmuje problem oraz akcję + tworzy węzeł potomny na podstawie otzymanej akcji + + zwraca węzeł potomny + + +class AgentPosition + + get_location + zwraca dwie zmienne: X i Y + + set_location + ustawia zmienne: X i Y + + get_orientation: + zwraca kierunek + + set_orientation: + ustawia kierunek + + + +class SweeperAgent - najbardziej tajemnicza klasa, bo do końca nie wiadomo co ma robić + + where_am_i() - niby ma zwracać położenie agenta na planszy + + set_allowed(allowed_points) + ustawia listę dostępnych miejsc na mapie + + set_puddles(puddle_points) + ustawia listę obecnych kałuż + + set_goal(goal) + ustawia punkt docelowy + + set_initial(initial) + ustawia punkt początkowy + + set_orientation() + ustawia kierunek + + plan_route() - czarna magia A* (∩ ͝ ° ͜ʖ͡° )⊃━☆゚ + + load_map() - ładowanie mapy + + astar_search() a* + + +class PriorityQueue - jakaś kolejka priorytetowa + + + + + + + diff --git a/goal_map.txt b/goal_map.txt index f32dcbe..a02a693 100644 --- a/goal_map.txt +++ b/goal_map.txt @@ -1,7 +1,7 @@ ....... -###.... -....... -....... -...###. -...#^#. -....... \ No newline at end of file +###.ppp +....p.. +....p.p +...###p +...#^#p +......p \ No newline at end of file diff --git a/images/puddle.bmp b/images/puddle.bmp new file mode 100644 index 0000000..60f80d0 Binary files /dev/null and b/images/puddle.bmp differ diff --git a/images/robot2.bmp b/images/robot2.bmp new file mode 100644 index 0000000..619bf07 Binary files /dev/null and b/images/robot2.bmp differ diff --git a/main.py b/main.py index 5e1804e..48b1044 100644 --- a/main.py +++ b/main.py @@ -7,7 +7,7 @@ from grid import * from settings import * from sprites import * from graphsearch import * - +from astar2 import * class Game: @@ -32,6 +32,7 @@ class Game: self.all_sprites = pg.sprite.Group() self.walls = pg.sprite.Group() self.mines = pg.sprite.Group() + self.puddles = pg.sprite.Group() for row, tiles in enumerate(self.map_data): for col, tile in enumerate(tiles): if tile == '2': @@ -42,6 +43,8 @@ class Game: Grenade(self, col, row) if tile == "#": Wall(self, col, row) + if tile == 'p': + Puddle(self, col, row) if tile == '>': self.player = Player(self, col, row, Direction.Right.name) if tile == '^': @@ -49,7 +52,7 @@ class Game: if tile == '<': self.player = Player(self, col, row, Direction.Left.name) if tile == 'v': - self.player = Player(self, col, row. Direction.Down.name) + self.player = Player(self, col, row, Direction.Down.name) def run(self): @@ -105,6 +108,12 @@ class Game: player_moves = BFS.run() self.graph_move(player_moves) self.wentyl_bezpieczenstwa = 1 + if event.key == pg.K_F4 and self.wentyl_bezpieczenstwa == 0: + print("test1") + agent = SweeperAgent() + SweeperAgent.run(agent) + # Test.run() + def graph_move(self, moves): diff --git a/map.txt b/map.txt index 1bc40f2..d3d7564 100644 --- a/map.txt +++ b/map.txt @@ -1,7 +1,7 @@ .>..... -###.... -....... -....... -...###. -...#.#. -....... \ No newline at end of file +###.ppp +....p.. +....p.p +...###p +...#.#p +......p \ No newline at end of file diff --git a/sprites.py b/sprites.py index 2ca7817..38c55dc 100644 --- a/sprites.py +++ b/sprites.py @@ -11,8 +11,8 @@ class Player(pg.sprite.Sprite): pg.sprite.Sprite.__init__(self, self.groups) self.game = game #self.image = pg.Surface((TILESIZE, TILESIZE)) - self.image = pg.image.load('images/robot.bmp') - self.baseImage = pg.image.load('images/robot.bmp') + self.image = pg.image.load('images/robot2.bmp') + self.baseImage = pg.image.load('images/robot2.bmp') #self.image.fill(YELLOW) self.image = pg.transform.scale(self.image, (TILESIZE, TILESIZE)) self.baseImage = pg.transform.scale(self.image, (TILESIZE, TILESIZE)) @@ -272,4 +272,19 @@ class Wall(pg.sprite.Sprite): self.rect.x = self.x * TILESIZE self.rect.y = self.y * TILESIZE +class Puddle(pg.sprite.Sprite): + def __init__(self, game, x, y): + self.groups = game.all_sprites, game.puddles + pg.sprite.Sprite.__init__(self, self.groups) + self.game = game + self.image = pg.image.load('images/puddle.bmp') + self.image = pg.transform.scale(self.image, (TILESIZE, TILESIZE)) + self.rect = self.image.get_rect() + self.x = x + self.y = y + + def update(self): + self.rect.x = self.x * TILESIZE + self.rect.y = self.y * TILESIZE + \ No newline at end of file diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..985ccda --- /dev/null +++ b/todo.txt @@ -0,0 +1,270 @@ +todo: + + ________________ + |'-.--._ _________: + | / | __ __\ + | | _ | [\_\= [\_\ + | |.' '. \.........| + | ( <) ||: :|_ + \ '._.' | :.....: |_(o + '-\_ \ .------./ + _ \ ||.---.|| _ + / \ '-._|/\n~~\n' | \ + (| []=.--[===[()]===[) | + <\_/ \_______/ _.' /_/ + /// (_/_/ + |\\ [\\ + ||:| | I| + |::| | I| + ||:| | I| + ||:| : \: + |\:| \I| + :/\: ([]) + ([]) [| + || |\_ + _/_\_ [ -'-.__ + <] \> \_____.> + \__/ + + + __...------------._ + ,-' `-. + ,-' `. + ,' ,-`. + ; `-' `. + ; .-. \ + ; .-. `-' \ + ; `-' \ + ; `. + ; : + ; | + ; ; + ; ___ ; + ; ,-;-','.`.__ | + _..; ,-' ;`,'.`,'.--`. | + ///; ,-' `. ,-' ;` ;`,','_.--=: / + |'': ,' : ;` ;,;,,-'_.-._`. ,' IT'S A TRAP!!! + ' : ;_.-. `. :' ;;;'.ee. \| / + \.' _..-'/8o. `. : :! ' ':8888) || / + ||`-'' \\88o\ : : :! : :`""' ;;/ + || \"88o\; `. \ `. `. ;,' + /) ___ `."'/(--.._ `. `.`. `-..-' ;--. + \(.="""""==.. `'-' `.| `-`-..__.-' `. `. + | `"==.__ ) ) ; + | || `"=== ' .' .' + /\,,|||| | | \ .' .' + | |||'|' |'|' \| .' _.' \ + | |\' | | || || .' .' \ + ' | \ ' |' . ``-- `| || .' .' \ + ' | ' | . ``-.._ | ; .' .' `. + _.--,;`. . -- ...._,' .' .' `.__ + ,' ,'; `. . --..__..--'.' .' __/_\ + ,' ; ; | . --..__.._.' .' ,' `. + / ; : ; . -.. _.' _.' / ` + / : `-._ | . _.--' _.' | +/ `. `--....--'' _.' | + `._ _..-' | + `-..____...-'' | + | + | + + .-. + |_:_| + /(_Y_)\ +. ( \/M\/ ) + '. _.'-/'-'\-'._ + ': _/.--'[[[[]'--.\_ + ': /_' : |::"| : '.\ + ': // ./ |oUU| \.' :\ + ': _:'..' \_|___|_/ : :| + ':. .' |_[___]_| :.':\ + [::\ | : | | : ; : \ + '-' \/'.| |.' \ .;.' | + |\_ \ '-' : | + | \ \ .: : | | + | \ | '. : \ | + / \ :. .; | + / | | :__/ : \\ + | | | \: | \ | || + / \ : : |: / |__| /| + | : : :_/_| /'._\ '--|_\ + /___.-/_|-' \ \ + '-' + + +.-.__ \ .-. ___ __ +|_| '--.-.-( \/\;;\_\.-._______.-. +(-)___ \ \ .-\ \;;\( \ \ \ + Y '---._\_((Q)) \;;\\ .-\ __(_) + I __'-' / .--.((Q))---' \, + I ___.-: \| | \'-'_ \ + A .-' \ .-.\ \ \ \ '--.__ '\ + | |____.----((Q))\ \__|--\_ \ ' + ( ) '-' \_ : \-' '--.___\ + Y \ \ \ \(_) + I \ \ \ \, + I \ \ \ \ + A \ \ \ '\ + | \ \__| ' + \_:. \ + \ \ \ + \ \ \ + \_\_| + + .==. + ()''()-. + .---. ;--; / + .'_:___". _..'. __'. + |__ --==|'-''' \'...; + [ ] :[| |---\ + |__| I=[| .' '. + / / ____| : '._ + |-/.____.' | : : +snd /___\ /___\ '-'._----' + + + ___ |\________/) + [_,_]) \ / \| + /|=T=|] / __ __\ + |\ " // |_ 9 p ]\ + ||'-'/--. / /\ =| \|\ \ + /|| <\/> |\ | '._, @ @)<_) + | |\ | | \.__/(_;_) + | . H | | : '='| + | | _H__/ _| : | + \ '.__ \ / ; '; + __'-._(_}==.' : ; + (___| /-' | :. : + [.-' \ | \ \ ; : + .-' | | | | ": + / |==| \ \ / \_ + / [ | '._\_ -._ \ + / \__) __.- \ \ )\\ + / | /.' >>) + | \ |\ | + | .' '-. | \ / + | / / / / / + snd | / + + + ._,. + "..-..pf. + -L ..#' + .+_L ."]# + ,'j' .+.j` -'.__..,.,p. + _~ #..<..0. .J-.``..._f. + .7..#_.. _f. .....-..,`4' + ;` ,#j. T' .. ..J....,'.j` + .` .."^.,-0.,,,,yMMMMM,. ,-.J...+`.j@ + .'.`...' .yMMMMM0M@^=`""g.. .'..J..".'.jH + j' .'1` q'^)@@#"^".`"='BNg_...,]_)'...0- + .T ...I. j" .'..+,_.'3#MMM0MggCBf....F. + j/.+'.{..+ `^~'-^~~""""'"""?'"``'1` + .... .y.} `.._-:`_...jf + g-. .Lg' ..,..'-....,'. + .'. .Y^ .....',].._f + ......-f. .-,,.,.-:--&` + .`...'..`_J` + .~......'#' + '..,,.,_]` + .L..`..``. + + + + ,ooo888888888888888oooo, + o8888YYYYYY77iiiiooo8888888o + 8888YYYY77iiYY8888888888888888 + [88YYY77iiY88888888888888888888] + 88YY7iYY888888888888888888888888 + [88YYi 88888888888888888888888888] + i88Yo8888888888888888888888888888i + i] ^^^88888888^^^ o [i + oi8 i o8o i 8io + ,77788o ^^ ,oooo8888888ooo, ^ o88777, + 7777788888888888888888888888888888877777 + 77777888888888888888888888888888877777 + 77777788888888^7777777^8888888777777 + ,oooo888 ooo 88888778888^7777ooooo7777^8887788888 ,o88^^^^888oo + o8888777788[];78 88888888888888888888888888888888888887 7;8^ 888888888oo^88 + o888888iii788 ]; o 78888887788788888^;;^888878877888887 o7;[]88888888888888o + 88888877 ii78[]8;7o 7888878^ ^8788^;;;;;;^878^ ^878877 o7;8 ]878888888888888 + [88888888887888 87;7oo 777888o8888^;ii;;ii;^888o87777 oo7;7[]8778888888888888 + 88888888888888[]87;777oooooooooooooo888888oooooooooooo77;78]88877i78888888888 + o88888888888888 877;7877788777iiiiiii;;;;;iiiiiiiii77877i;78] 88877i;788888888 + 88^;iiii^88888 o87;78888888888888888888888888888888888887;778] 88877ii;7788888 +;;;iiiii7iiii^ 87;;888888888888888888888888888888888888887;778] 888777ii;78888 +;iiiii7iiiii7iiii77;i88888888888888888888i7888888888888888877;77i 888877777ii78 +iiiiiiiiiii7iiii7iii;;;i7778888888888888ii7788888888888777i;;;;iiii 88888888888 +i;iiiiiiiiiiii7iiiiiiiiiiiiiiiiiiiiiiiiii8877iiiiiiiiiiiiiiiiiii877 88888 +ii;;iiiiiiiiiiiiii;;;ii^^^;;;ii77777788888888888887777iii;; 77777 78 +77iii;;iiiiiiiiii;;;ii;;;;;;;;;^^^^8888888888888888888777ii;; ii7 ;i78 +^ii;8iiiiiiii ';;;;ii;;;;;;;;;;;;;;;;;;^^oo ooooo^^^88888888;;i7 7;788 +o ^;;^^88888^ 'i;;;;;;;;;;;;;;;;;;;;;;;;;;;^^^88oo^^^^888ii7 7;i788 +88ooooooooo ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 788oo^;; 7;i888 +887ii8788888 ;;;;;;;ii;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;^87 7;788 +887i8788888^ ;;;;;;;ii;;;;;;;oo;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;,,, ;;888 +87787888888 ;;;;;;;ii;;;;;;;888888oo;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;,,;i788 +87i8788888^ ';;;ii;;;;;;;8888878777ii8ooo;;;;;;;;;;;;;;;;;;;;;;;;;;i788 7 +77i8788888 ioo;;;;;;oo^^ooooo ^7i88^ooooo;;;;;;;;;;;;;;;;;;;;i7888 78 +7i87788888o 7;ii788887i7;7;788888ooooo7888888ooo;;;;;;;;;;;;;;oo ^^^ 78 +i; 7888888^ 8888^o;ii778877;7;7888887;;7;7788878;878;; ;;;;;;;i78888o ^ +i8 788888 [88888^^ ooo ^^^^^;;77888^^^^;;7787^^^^ ^^;;;; iiii;i78888888 +^8 7888^ [87888 87 ^877i;i8ooooooo8778oooooo888877ii; iiiiiiii788888888 + ^^^ [7i888 87;; ^8i;;i7888888888888888887888888 i7iiiiiii88888^^ + 87;88 o87;;;;o 87i;;;78888788888888888888^^ o 8ii7iiiiii;; + 87;i8 877;77888o ^877;;;i7888888888888^^ 7888 78iii7iii7iiii + ^87; 877;778888887o 877;;88888888888^ 7ii7888 788oiiiiiiiii + ^ 877;7 7888888887 877i;;8888887ii 87i78888 7888888888 + [87;;7 78888888887 87i;;888887i 87ii78888 7888888888] + 877;7 7788888888887 887i;887i^ 87ii788888 78888888888 + 87;i8 788888888888887 887ii;;^ 87ii7888888 78888888888 + [87;i8 7888888888888887 ^^^^ 87ii77888888 78888888888 + 87;;78 7888888888888887ii 87i78888888 778888888888 + 87;788 7888888888888887i] 87i78888888 788888888888 + [87;88 778888888888888887 7ii78888888 788888888888 + 87;;88 78888888888888887] ii778888888 78888888888] + 7;;788 7888888888888888] i7888888888 78888888888' + 7;;788 7888888888888888 'i788888888 78888888888 + 7;i788 788888888888888] 788888888 77888888888] + '7;788 778888888888888] [788888888 78888888888' + ';77888 78888888888888 8888888888 7888888888] + 778888 78888888888888 8888888888 7888888888] + 78888 7888888888888] [8888888888 7888888888 + 7888 788888888888] 88888888888 788888888] + 778 78888888888] ]888888888 778888888] + oooooo ^88888^ ^88888^^^^^^^^8888] + 87;78888ooooooo8o ,oooooo oo888oooooo + [877;i77888888888] [;78887i8888878i7888; + ^877;;ii7888ii788 ;i777;7788887787;778; + ^87777;;;iiii777 ;77^^^^^^^^^^^^^^^^;; + ^^^^^^^^^ii7] ^ o88888888877iiioo + 77777o [88777777iiiiii;;778 + 77777iii 8877iiiii;;;77888888] + 77iiii;8 [77ii;778 788888888888 + 7iii;;88 iii;78888 778888888888 + 77i;78888] ;;;;i88888 78888888888 + ,7;78888888 [;;i788888 7888888888] + i;788888888 ;i7888888 7888888888 + ;788888888] i77888888 788888888] + ';88888888' [77888888 788888888] + [[8ooo88] 78888888 788888888 + [88888] 78888888 788888888 + ^^^ [7888888 77888888] + 88888888 7888887 + 77888888 7888887 + ;i88888 788888i + ,;;78888 788877i7 + ,7;;i;777777i7i;;7 + 87778^^^ ^^^^87778 + ^^^^ o777777o ^^^ + o77777iiiiii7777o + 7777iiii88888iii777 + ;;;i7778888888877ii;; + Imperial Stormtrooper [i77888888^^^^8888877i] + (Standard Shock Trooper) 77888^oooo8888oooo^8887] + [788888888888888888888888] + 88888888888888888888888888 + ]8888888^iiiiiiiii^888888] + iiiiiiiiiiiiiiiiiiiiii + ^^^^^^^^^^^^^ +