diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..056882c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "C:\\Users\\ryodenshi\\AppData\\Local\\Programs\\Python\\Python39\\python.exe" +} \ No newline at end of file diff --git a/goal_map.txt b/goal_map.txt index 7c2b326..f32dcbe 100644 --- a/goal_map.txt +++ b/goal_map.txt @@ -4,5 +4,4 @@ ....... ...###. ...#^#. -....... - +....... \ No newline at end of file diff --git a/graphsearch.py b/graphsearch.py index 7853694..11a9272 100644 --- a/graphsearch.py +++ b/graphsearch.py @@ -2,6 +2,7 @@ import sys from collections import deque from os import path import queue +import numpy from utils import * from settings import * @@ -13,7 +14,7 @@ class Problem: __init__, goal_test, and path_cost. Then you will create instances of your subclass and solve them with the various search functions.""" - def __init__(self, initial=[], goal=[]): + def __init__(self, initial, goal): """The constructor specifies the initial state, and possibly a goal state, if there is a unique goal. Your subclass's constructor can add other arguments.""" @@ -27,14 +28,14 @@ class Problem: iterator, rather than building them all at once.""" moves = [] - if self.turn_left(self, state): + if self.turn_left(state): moves.append('Left') - if self.turn_right(self, state): + if self.turn_right(state): moves.append('Right') - if self.move_forward(self, state): + if self.move_forward(state): moves.append('Forward') - print(moves) + #print(moves) return moves @@ -90,55 +91,65 @@ class Problem: return False def turn_me_or_move(self, state, do_it): - a_row = 0 - a_column = 0 + + 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(state[row]): + 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'): - state[a_row][a_column] = '^' + temp_map[a_row][a_column] = "^" if(do_it == 'Right'): - state[a_row][a_column] = 'v' + temp_map[a_row][a_column] = 'v' if(do_it == 'Forward'): - state[a_row][a_column] = '.' - state[a_row][a_column+1] = '>' + 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'): - state[a_row][a_column] = 'v' + temp_map[a_row][a_column] = 'v' if(do_it == 'Right'): - state[a_row][a_column] = '^' + temp_map[a_row][a_column] = '^' if(do_it == 'Forward'): - state[a_row][a_column] = '.' - state[a_row][a_column-1] = '<' - + 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'): - state[a_row][a_column] = '>' + temp_map[a_row][a_column] = '>' if(do_it == 'Right'): - state[a_row][a_column] = '<' + temp_map[a_row][a_column] = '<' if(do_it == 'Forward'): - state[a_row][a_column] = '.' - state[a_row+1][a_column] = 'v' + 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'): - state[a_row][a_column] = '<' + temp_map[a_row][a_column] = '<' if(do_it == 'Right'): - state[a_row][a_column] = '>' + temp_map[a_row][a_column] = '>' if(do_it == 'Forward'): - state[a_row][a_column] = '.' - state[a_row-1][a_column] = '^' - return state + temp_map[a_row][a_column] = '.' + temp_map[a_row-1][a_column] = '^' + return temp_map + return temp_map def result(self, state, action): """Return the state that results from executing the given @@ -153,17 +164,30 @@ class Problem: elif action == 'Forward': new_state = self.turn_me_or_move(state, 'Forward') - return new_state + super_new_state = tuple(map(tuple,new_state)) + + return super_new_state def goal_test(self, state): """Return True if the state is a goal. The default method compares the state to self.goal or checks for state in self.goal if it is a list, as specified in the constructor. Override this method if checking against a single self.goal is not enough.""" - if isinstance(self.goal, list): + + """if isinstance(self.goal, list): return is_in(state, self.goal) else: - return state == self.goal + return state == self.goal""" + + if self.goal == state: + return True + return False + + + + + + @@ -185,6 +209,9 @@ class Node: self.state = state self.parent = parent self.action = action + + def __repr__(self): + return "".format(self.state) def expand(self, problem): """List the nodes reachable in one step from this node.""" @@ -196,6 +223,16 @@ class Node: next_node = Node(next_state, self, action) 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) + class BFS: @@ -211,6 +248,8 @@ class BFS: if problem.goal_test(node.state): return node frontier = deque([node]) + final_child = node + history = [] explored = set() while frontier: node = frontier.popleft() @@ -218,8 +257,16 @@ class BFS: for child in node.expand(problem): if child.state not in explored and child not in frontier: if problem.goal_test(child.state): - return child + while(child.parent != None): + history.append(child.action) + child = child.parent + #return child + history.reverse() + #print(history) + return history frontier.append(child) + #BFS.print_node_state(child.state) + return None @staticmethod @@ -228,16 +275,26 @@ class BFS: map_folder = path.dirname(__file__) with open(path.join(map_folder, map_name), 'rt') as f: for line in f: - maze.append(line) + maze.append(line.rstrip('\n')) + + #print(maze) return maze @staticmethod def run(): - initial_map = BFS.loadMap('map.txt') - goal_map = BFS.loadMap('goal_map.txt') + initial_map = tuple(map(tuple,BFS.loadMap('map.txt'))) + goal_map = tuple(map(tuple,BFS.loadMap('goal_map.txt'))) problem = Problem(initial_map, goal_map) + #BFS.print_node_state(initial_map) + #BFS.print_node_state(goal_map) + result = BFS.breadth_first_graph_search(problem) print(result) - + #return result + #print(BFS.print_node_state(result)) + @staticmethod + def print_node_state(node_state): + print(numpy.matrix(node_state)) + \ No newline at end of file diff --git a/main.py b/main.py index a4ea4c5..46b2ff8 100644 --- a/main.py +++ b/main.py @@ -42,7 +42,13 @@ class Game: Grenade(self, col, row) if tile == "#": Wall(self, col, row) - if tile == 'A': + if tile == '>': + self.player = Player(self, col, row) + if tile == '^': + self.player = Player(self, col, row) + if tile == '<': + self.player = Player(self, col, row) + if tile == 'v': self.player = Player(self, col, row) diff --git a/map.txt b/map.txt index 567a813..1bc40f2 100644 --- a/map.txt +++ b/map.txt @@ -1,7 +1,7 @@ .>..... -#.#.... +###.... ....... ....... ...###. ...#.#. -....... +....... \ No newline at end of file