diff --git a/projects/adventure/adv.py b/projects/adventure/adv.py index 8bc540b5e..ab9bc9a2a 100644 --- a/projects/adventure/adv.py +++ b/projects/adventure/adv.py @@ -1,3 +1,8 @@ +import sys +sys.path.append('../graph') + +from util import Stack, Queue + from room import Room from player import Player from world import World @@ -8,12 +13,15 @@ # Load world world = World() +#construct a traversal graph +#do dft for finding all the possible room player can move +#do bfs for finding unexplored direction # You may uncomment the smaller graphs for development and testing purposes. -# map_file = "maps/test_line.txt" -# map_file = "maps/test_cross.txt" -# map_file = "maps/test_loop.txt" -# map_file = "maps/test_loop_fork.txt" +#map_file = "maps/test_line.txt" +#map_file = "maps/test_cross.txt" +#map_file = "maps/test_loop.txt" +#map_file = "maps/test_loop_fork.txt" map_file = "maps/main_maze.txt" # Loads the map into a dictionary @@ -23,19 +31,109 @@ # Print an ASCII map world.print_rooms() + player = Player(world.starting_room) +player.current_room = world.starting_room + + + +opposit_dic = {'n': 's', + 's': 'n', + 'e': 'w', + 'w': 'e' + } -# Fill this out with directions to walk -# traversal_path = ['n', 'n'] traversal_path = [] +def bfs(current_room): + """ + BFS for the unexplored room, then + Return the path to it + """ + #add the visited room + visited = set() + #rooms to check + q =[] + q.append((current_room, [])) + count = 0 + #create a visited vertex + while len(q)>0: + #dequeue the current room exist + (room, path) = q.pop(0) + if room in visited : + continue + else: + visited.add(room) + for direction in visited_room[room]: + if visited_room[room][direction] == '?': + return [path, direction] + elif visited_room[room][direction] is not None: + update_path = path.copy() + update_path.append(direction) + next_room = visited_room[room][direction] + q.append((next_room, update_path)) + return None +import random +def dft(unexplored_dir): + #create an empty stack and add the starting room exists directions + stack = Stack() + stack.push(unexplored_dir) + + #while stack is not empty + while stack.size() >0: + #pop the current room exits direction + current_exit = stack.pop() + move_dir =current_exit[-1] + # if this direction is not explored + if move_dir not in visited_room[player.current_room.id]: + continue + elif visited_room[player.current_room.id][move_dir] =='?': + previous_room = player.current_room.id + #move player in that direction + player.travel(move_dir) + # store the movement in the traversal path + traversal_path.append(move_dir) + # update the unexplored direction in the dictionary + visited_room[previous_room][move_dir] = player.current_room.id + opposite_value = opposit_dic[move_dir] + if player.current_room.id not in visited_room: + #if visited_room[player.current_room.id] + visited_room[player.current_room.id] = {opposite_value:previous_room} + else: + visited_room[player.current_room.id][opposite_value]= previous_room + # get all the neighbour room direction + for direction in player.current_room.get_exits(): + if direction not in visited_room[player.current_room.id]: + visited_room[player.current_room.id][direction]='?' + new_dir = [] + new_dir.append(direction) + stack.push(new_dir) + unexplored_dir = bfs(player.current_room.id) + if unexplored_dir !=None: + for direction in unexplored_dir[0]: + player.travel(direction) + traversal_path.append(direction) + dft([unexplored_dir[1]]) + +starting_dir = random.choice(player.current_room.get_exits()) + +visited_room ={player.current_room.id :{}} +for direction in player.current_room.get_exits(): + visited_room[player.current_room.id][direction] ='?' + +dft([starting_dir]) + + + +# Fill this out with directions to walk +#traversal_path = ['n', 'n'] + # TRAVERSAL TEST visited_rooms = set() player.current_room = world.starting_room visited_rooms.add(player.current_room) - for move in traversal_path: player.travel(move) visited_rooms.add(player.current_room) @@ -45,18 +143,36 @@ else: print("TESTS FAILED: INCOMPLETE TRAVERSAL") print(f"{len(room_graph) - len(visited_rooms)} unvisited rooms") - +# # queue = Queue() +# #create dic for visited vertex and path +# visited = {} # Note that this is a dictionary, not a set +# #enqueue the queue with the starting user_id as a path +# queue.enqueue([player.current_room]) +# #while queue is not empty +# while queue.size()>0: +# #dequeue the current path +# current_path = queue.dequeue() +# #get the current vertex from end of the path +# current_room = current_path[-1] +# if current_room not in visited: +# visited[current_room] = current_path +# #queue up all the neighbours as path +# for direction in player.current_room.get_exits(): + +# new_path = current_path.copy() +# new_path.append(direction) +# queue.enqueue(new_path) ####### # UNCOMMENT TO WALK AROUND ####### -player.current_room.print_room_description(player) -while True: - cmds = input("-> ").lower().split(" ") - if cmds[0] in ["n", "s", "e", "w"]: - player.travel(cmds[0], True) - elif cmds[0] == "q": - break - else: - print("I did not understand that command.") +# player.current_room.print_room_description(player) +# while True: +# cmds = input("-> ").lower().split(" ") +# if cmds[0] in ["n", "s", "e", "w"]: +# player.travel(cmds[0], True) +# elif cmds[0] == "q": +# break +# else: +# print("I did not understand that command.") diff --git a/projects/adventure/room.py b/projects/adventure/room.py index 83ed04089..1c2ac8410 100644 --- a/projects/adventure/room.py +++ b/projects/adventure/room.py @@ -57,3 +57,4 @@ def get_room_in_direction(self, direction): return None def get_coords(self): return [self.x, self.y] + diff --git a/projects/ancestor/ancestor.py b/projects/ancestor/ancestor.py index 3bd003098..2ae4a7404 100644 --- a/projects/ancestor/ancestor.py +++ b/projects/ancestor/ancestor.py @@ -1,3 +1,51 @@ +import sys +sys.path.append('../graph') + +from util import Stack, Queue + +def get_neighbours(ancestors, current_node): + neighbours =[] + for tuple_pair in ancestors: + if tuple_pair[1] == current_node: + #if tuple_pair[1] in neighbours: + neighbours.append(tuple_pair[0]) + if len(neighbours)>1: + return [min(neighbours)] + else: + return neighbours + + + def earliest_ancestor(ancestors, starting_node): - pass \ No newline at end of file + #use Bft to find the ancestor + #if the current node has no neighbour return -1 + if len(get_neighbours(ancestors, starting_node)) ==0 : + return -1 + #create a queue + queue = Queue() + #add start word to it + queue.enqueue([starting_node]) + #create a visited set + visited = [] + #while queue is not empty + while queue.size()>0: + #pop the current node off the queue + current_path = queue.dequeue() + current_node = current_path[-1] + #if word has not been visited + if current_node not in visited: + #add the current node to visited set + visited.append(current_node) + #add neighbours of the current node to the queue + for neighbours in get_neighbours(ancestors, current_node): + new_path = list(current_path) + new_path.append(neighbours) + queue.enqueue(new_path) + return visited[-1] + + +ancestors = [(1, 3), (2, 3), (3, 6), (5, 6), (5, 7), (4, 5), (4, 8), (8, 9), (11, 8), (10, 1)] +print(get_neighbours(ancestors, 8)) + +print(earliest_ancestor(ancestors, 8)) diff --git a/projects/graph/graph.py b/projects/graph/graph.py index 59fecae4b..92fa96c17 100644 --- a/projects/graph/graph.py +++ b/projects/graph/graph.py @@ -13,33 +13,89 @@ def add_vertex(self, vertex_id): """ Add a vertex to the graph. """ - pass # TODO + if vertex_id not in self.vertices: + self.vertices[vertex_id] = set () def add_edge(self, v1, v2): """ Add a directed edge to the graph. """ - pass # TODO + self.vertices[v1].add(v2) def get_neighbors(self, vertex_id): """ Get all neighbors (edges) of a vertex. """ - pass # TODO + return self.vertices[vertex_id] def bft(self, starting_vertex): """ Print each vertex in breadth-first order beginning from starting_vertex. """ - pass # TODO + #create an empty queue and enqueue with starting vertex + queue = Queue() + queue.enqueue({ + 'current_vertex' : starting_vertex, + 'edges': [starting_vertex] #value of that vertex + }) + #create a set of visited vertices + visited_vertices =set () + #while queue is not empty + while queue.size() >0: + #get current vertex (dequeue from queue) + current_obj= queue.dequeue() + current_edges = current_obj['edges'] + current_vertex = current_obj['current_vertex'] + #check current vertex is not in visited vertex list + if current_vertex not in visited_vertices: + # Mark as visited vertices + visited_vertices.add(current_vertex) + #get the neighbour of the current vertex + for neighbour_vertex in self.get_neighbors(current_vertex): + new_edges = list(current_edges) + new_edges.append(neighbour_vertex) + #enqueue the current vertex neighbour + queue.enqueue({ + 'current_vertex' : neighbour_vertex, + 'edges' : new_edges + }) + return visited_vertices + + + def dft(self, starting_vertex): """ Print each vertex in depth-first order beginning from starting_vertex. """ - pass # TODO + #create a empty stack and add the starting vertex + stack =Stack() + stack.push({ + 'current_vertex': starting_vertex, + 'path':[starting_vertex] + }) + #create a set of vistited vertices + visited_vertex = set() + #while stack is not empty + while stack.size()>0: + #pop the current vetex + current_obj = stack.pop() + current_vertex = current_obj['current_vertex'] + current_path = current_obj['path'] + if current_vertex not in visited_vertex: + visited_vertex.add(current_vertex) + #get the neighbours for the current vertex + for neighbour_vertex in self.get_neighbors(current_vertex): + new_path =list(current_path) + new_path.append(neighbour_vertex) + #push the neighbour in the stack + stack.push({ + 'current_vertex': neighbour_vertex, + 'path' : new_path + }) + return visited_vertex def dft_recursive(self, starting_vertex): """ @@ -56,7 +112,38 @@ def bfs(self, starting_vertex, destination_vertex): starting_vertex to destination_vertex in breath-first order. """ - pass # TODO + #create an empty queue and enqueue with current node neighbour + queue = Queue() + queue.enqueue({ + 'current_vertex': starting_vertex, + 'path' : [starting_vertex] + }) + # create a list of visited vetex + visited_vertex = set() + #while queue is not empty + while queue.size() >0: + #get a current obj path(dequeue it from queue) + current_obj = queue.dequeue() + current_vertex = current_obj['current_vertex'] + current_path = current_obj['path'] + #compare the current vertex with destination vertex + if current_vertex == destination_vertex: + return current_path + #check if the vertex in the visited_vetex list + if current_vertex not in visited_vertex: + #add th vertex in the visted vertex list + visited_vertex.add(current_vertex) + #get all the neighbours of the current_vertex + for neighbour_vertex in self.get_neighbors(current_vertex): + new_path = list(current_path) + new_path.append(neighbour_vertex) + # enqueu the neighbour in the queue + queue.enqueue({ + 'current_vertex': neighbour_vertex, + 'path': new_path + }) + + def dfs(self, starting_vertex, destination_vertex): """ @@ -64,7 +151,32 @@ def dfs(self, starting_vertex, destination_vertex): starting_vertex to destination_vertex in depth-first order. """ - pass # TODO + stack =Stack() + stack.push({ + 'current_vertex': starting_vertex, + 'path':[starting_vertex] + }) + #create a set of vistited vertices + visited_vertex = set() + #while stack is not empty + while stack.size()>0: + #pop the current vetex + current_obj = stack.pop() + current_vertex = current_obj['current_vertex'] + current_path = current_obj['path'] + if current_vertex == destination_vertex: + return current_path + if current_vertex not in visited_vertex: + visited_vertex.add(current_vertex) + #get the neighbours for the current vertex + for neighbour_vertex in self.get_neighbors(current_vertex): + new_path =list(current_path) + new_path.append(neighbour_vertex) + #push the neighbour in the stack + stack.push({ + 'current_vertex': neighbour_vertex, + 'path' : new_path + }) def dfs_recursive(self, starting_vertex, destination_vertex): """ @@ -118,7 +230,7 @@ def dfs_recursive(self, starting_vertex, destination_vertex): 1, 2, 4, 3, 7, 6, 5 1, 2, 4, 3, 7, 5, 6 ''' - graph.bft(1) + print(graph.bft(1)) ''' Valid DFT paths: @@ -127,8 +239,8 @@ def dfs_recursive(self, starting_vertex, destination_vertex): 1, 2, 4, 7, 6, 3, 5 1, 2, 4, 6, 3, 5, 7 ''' - graph.dft(1) - graph.dft_recursive(1) + print(graph.dft(1)) + #graph.dft_recursive(1) ''' Valid BFS path: @@ -142,4 +254,4 @@ def dfs_recursive(self, starting_vertex, destination_vertex): [1, 2, 4, 7, 6] ''' print(graph.dfs(1, 6)) - print(graph.dfs_recursive(1, 6)) + #print(graph.dfs_recursive(1, 6)) diff --git a/projects/social/social.py b/projects/social/social.py index 8609d8800..d27e85e1b 100644 --- a/projects/social/social.py +++ b/projects/social/social.py @@ -1,3 +1,9 @@ +import random +import sys +sys.path.append('../graph') + +from util import Stack, Queue + class User: def __init__(self, name): self.name = name @@ -45,8 +51,25 @@ def populate_graph(self, num_users, avg_friendships): # !!!! IMPLEMENT ME # Add users + for i in range(0, num_users): + self.add_user(f'User{i+1}') # Create friendships + #generate all the possible friendship + possible_friendship = [] + #generate all possible firend for every single user + for user_id in self.users: + for friend_id in range(user_id +1, self.last_id +1): + possible_friendship.append((user_id, friend_id)) + #randomly select x friendship + # x= num_users * avg_friendship //2 + #shuffle the array and pick x friendship from the front of it + random.shuffle(possible_friendship) + num_friendship = num_users * avg_friendships //2 + for i in range(0, num_friendship): + friendship = possible_friendship[i] + self.add_friendship(friendship[0], friendship[1]) + def get_all_social_paths(self, user_id): """ @@ -57,8 +80,28 @@ def get_all_social_paths(self, user_id): The key is the friend's ID and the value is the path. """ + #do the Bft for shortes path + #create a queue + queue = Queue() + #create dic for visited vertex and path visited = {} # Note that this is a dictionary, not a set - # !!!! IMPLEMENT ME + #enqueue the queue with the starting user_id as a path + queue.enqueue([user_id]) + #while queue is not empty + while queue.size()>0: + #dequeue the current path + current_path = queue.dequeue() + #get the current vertex from end of the path + current_vertex = current_path[-1] + if current_vertex not in visited: + visited[current_vertex] = current_path + #queue up all the neighbours as path + for neighbour in self.friendships[current_vertex]: + new_path = current_path.copy() + new_path.append(neighbour) + queue.enqueue(new_path) + + return visited