diff --git a/main_A_star.py b/main_A_star.py index 0501b15..fd4c51f 100644 --- a/main_A_star.py +++ b/main_A_star.py @@ -2,7 +2,7 @@ import sys import heapq # Initialize cost, heuristic, map, visited nodes, and parent tracking arrays -min_costs = [[100]*9 for _ in range(9)] # Initialize minimum cost array with a high value (100) +min_costs = [[10000]*9 for _ in range(9)] # Initialize minimum cost array with a high value (10000) hs = [[0]*9 for _ in range(9)] # Heuristic array for A* (Manhattan distance) astar_map = [['.']*9 for _ in range(9)] # Initial unexplored map with '.' visited_nodes = [[False]*9 for _ in range(9)] # Track visited nodes @@ -17,7 +17,7 @@ goal_x, goal_y = int(input_list[0]), int(input_list[1]) # Keymaker’s coordina for i in range(9): for j in range(9): hs[j][i] = abs(j - goal_y) + abs(i - goal_x) # Calculate heuristic distance - min_costs[j][i] = 100 # Set initial high cost for all cells + min_costs[j][i] = 10000 # Set initial high cost for all cells min_costs[0][0] = 0 # Starting position (0,0) cost is zero @@ -77,7 +77,7 @@ while len(priority_queue) != 0: astar_map[neighbor_y][neighbor_x] = neighbor_char # Update map # Check if the goal is reached and output the result -if min_costs[goal_y][goal_x] != 100: +if min_costs[goal_y][goal_x] != 10000: print(f"e {min_costs[goal_y][goal_x]}") # Output shortest path length else: - print("e -1") # Output -1 if unsolvable + print("e -1") # Output -1 if unsolvable. diff --git a/main_A_star_testing.py b/main_A_star_testing.py index 5e01ab1..4f32219 100644 --- a/main_A_star_testing.py +++ b/main_A_star_testing.py @@ -1,91 +1,164 @@ -import sys import heapq +import time + + + +def get_percepted_cells(position:tuple): + cells = [] + for x in range(position[0]- perception_radius, position[0] + perception_radius + 1): + for y in range(position[1]- perception_radius, position[1] + perception_radius + 1): + if (x,y) != position: + cells.append((x,y)) + return cells + +failed_tests = 0 +passed_tests = 0 + +total_time = 0 +average_time = 0 test_number = 0 with open("20k_testset.txt", "r") as file: lines = file.readlines() - #print(lines) -current_line = lines[0] -while(test_number < 10): - local_line_number = 0 - for line_number in range(14): - local_line_number += 1 - current_line += lines[test_number * 14 + local_line_number] - print(current_line) - test_number += 1 - print(test_number) -min_costs = [[100]*9 for temp in range(9)] -hs = [[0]*9 for temp in range(9)] -astar_map = [['.']*9 for temp in range(9)] -visited_nodes = [[False]*9 for temp in range(9)] -node_parents = [[None]*9 for temp in range(9)] + + + + + + +line_number = 0 +while(test_number < 1000): + #time.sleep(.5) + start_time = time.time() + current_test_lines = [] + for local_line_number in range(14): + current_line = lines[line_number] + current_test_lines.append(current_line) + line_number += 1 + + # Initialize cost, heuristic, map, visited nodes, and parent tracking arrays + min_costs = [[10000]*9 for _ in range(9)] # Initialize minimum cost array with a high value (10000) + hs = [[0]*9 for _ in range(9)] # Heuristic array for A* (Manhattan distance) + astar_map = [['.']*9 for _ in range(9)] # Initial unexplored map with '.' + visited_nodes = [[False]*9 for _ in range(9)] # Track visited nodes + node_parents = [[None]*9 for _ in range(9)] # Track path parents for backtracking + + # Input: perception radius and Keymaker position + perception_radius = int(current_test_lines[1][0]) # 1 or 2 for Neo’s perception variant + goal_x, goal_y = int(current_test_lines[2][1]), int(current_test_lines[2][4]) # Keymaker’s coordinates + + # Set up heuristic values (Manhattan distance) and initial costs for A* + for i in range(9): + for j in range(9): + hs[j][i] = abs(j - goal_y) + abs(i - goal_x) # Calculate heuristic distance + min_costs[j][i] = 10000 # Set initial high cost for all cells + + min_costs[0][0] = 0 # Starting position (0,0) cost is zero + + # Priority queue for A* with starting point at (0,0) + priority_queue = [] + heapq.heappush(priority_queue, (min_costs[0][0] + hs[0][0], 0, 0)) # Push initial cell to queue + + + + + + + #for line in current_test_lines: + #print(line[:-1]) + + test_map_matrix = current_test_lines[3:12] + + #for line in test_map_matrix: + #print(line[:-1]) + + -perception_radius = int(input()) -input_list = input().split() -goal_x, goal_y = int(input_list[0]), int(input_list[1]) - -for i in range(9): - for j in range(9): - hs[j][i] = abs(j - goal_y) + abs(i - goal_x) - min_costs[j][i] = 100 - -min_costs[0][0] = 0 - -priority_queue = [] -heapq.heappush(priority_queue, (min_costs[0][0] + hs[0][0], 0, 0)) - -while len(priority_queue) != 0: - temp, current_x, current_y = heapq.heappop(priority_queue) - if visited_nodes[current_y][current_x]: - continue - visited_nodes[current_y][current_x] = True - - parent_node = node_parents[current_y][current_x] - path_to_current = [] - path_to_current.append((current_x, current_y)) - while parent_node is not None: - path_to_current.append(parent_node) - parent_node = node_parents[parent_node[1]][parent_node[0]] - - for i in reversed(range(len(path_to_current))): - print(f"m {path_to_current[i][0]} {path_to_current[i][1]}") - neighbor_count = int(input()) - for temp in range(neighbor_count): - input_data = input().split() - neighbor_x_str, neighbor_y_str, neighbor_char = input_data[0], input_data[1], input_data[2] - neighbor_x = int(neighbor_x_str) - neighbor_y = int(neighbor_y_str) - neighbor_char = neighbor_char[0] - astar_map[neighbor_y][neighbor_x] = neighbor_char - - for dx, dy in [(1, 0), (0, 1), (-1, 0), (0, -1)]: - neighbor_x = current_x + dx - neighbor_y = current_y + dy - if 0 <= neighbor_x < 9 and 0 <= neighbor_y < 9 and not visited_nodes[neighbor_y][neighbor_x] and astar_map[neighbor_y][neighbor_x] not in ('P', 'A', 'S'): - if min_costs[neighbor_y][neighbor_x] > min_costs[current_y][current_x] + 1: - node_parents[neighbor_y][neighbor_x] = (current_x, current_y) - min_costs[neighbor_y][neighbor_x] = min_costs[current_y][current_x] + 1 - heapq.heappush(priority_queue, (min_costs[neighbor_y][neighbor_x] + hs[neighbor_y][neighbor_x], neighbor_x, neighbor_y)) - - for i in range(len(path_to_current)): - print(f"m {path_to_current[i][0]} {path_to_current[i][1]}") - neighbor_count = int(input()) - for temp in range(neighbor_count): - input_data = input().split() - neighbor_x_str, neighbor_y_str, neighbor_char = input_data[0], input_data[1], input_data[2] - neighbor_x = int(neighbor_x_str) - neighbor_y = int(neighbor_y_str) - neighbor_char = neighbor_char[0] - astar_map[neighbor_y][neighbor_x] = neighbor_char - -if min_costs[goal_y][goal_x] != 100: - print(f"e {min_costs[goal_y][goal_x]}") -else: - print("e -1") + + + + + - + # Main A* loop + while len(priority_queue) != 0: + # Extract node with lowest f = g + h value + temp, current_x, current_y = heapq.heappop(priority_queue) + if visited_nodes[current_y][current_x]: + continue + visited_nodes[current_y][current_x] = True # Mark node as visited + + # Backtrack to get the path to current node + parent_node = node_parents[current_y][current_x] + path_to_current = [(current_x, current_y)] + while parent_node is not None: + path_to_current.append(parent_node) + parent_node = node_parents[parent_node[1]][parent_node[0]] + + # Execute path, querying for perception data + for i in reversed(range(len(path_to_current))): + #print(f"m {path_to_current[i][0]} {path_to_current[i][1]}") + for x in range(len(test_map_matrix)): + for y in range(len(test_map_matrix)): + if (x,y) in get_percepted_cells((current_x, current_y)) and test_map_matrix[x][y] != ".": + astar_map[x][y] = test_map_matrix[x][y] + + # Explore neighboring cells + for dx, dy in [(1, 0), (0, 1), (-1, 0), (0, -1)]: # Move in four directions + neighbor_x = current_x + dx + neighbor_y = current_y + dy + # Check boundaries and if cell is unexplored and safe + if 0 <= neighbor_x < 9 and 0 <= neighbor_y < 9 and not visited_nodes[neighbor_y][neighbor_x] and astar_map[neighbor_y][neighbor_x] not in ('P', 'A', 'S'): + # Update cost if a better path is found + if min_costs[neighbor_y][neighbor_x] > min_costs[current_y][current_x] + 1: + node_parents[neighbor_y][neighbor_x] = (current_x, current_y) + min_costs[neighbor_y][neighbor_x] = min_costs[current_y][current_x] + 1 + # Add node to priority queue with updated f = g + h value + heapq.heappush(priority_queue, (min_costs[neighbor_y][neighbor_x] + hs[neighbor_y][neighbor_x], neighbor_x, neighbor_y)) + + # Repeat path execution to keep querying + for i in range(len(path_to_current)): + #print(f"m {path_to_current[i][0]} {path_to_current[i][1]}") + for x in range(len(test_map_matrix)): + for y in range(len(test_map_matrix)): + if (x,y) in get_percepted_cells((current_x, current_y)) and test_map_matrix[x][y] != ".": + astar_map[x][y] = test_map_matrix[x][y] + + # Check if the goal is reached and output the result + if min_costs[goal_y][goal_x] != 10000: + print(f"e {min_costs[goal_y][goal_x]}") # Output shortest path length + #time.sleep(1) + passed_tests += 1 + test_number += 1 + end_time = time.time() + test_time = end_time - start_time + total_time += test_time + else: + print("e -1") # Output -1 if unsolvable. + #time.sleep(1) + failed_tests += 1 + test_number += 1 + end_time = time.time() + test_time = end_time - start_time + total_time += 0 # we don't consider failed tests in statistics + +average_time = total_time / passed_tests + +print("-------RESULTS-------") +print(f"passed tests: {passed_tests}") +print(f"failed tests: {failed_tests}") +print(f"total time: {total_time}") +print(f"average time: {average_time}") +''' +FOR 1000 tests +-------RESULTS------- +passed tests: 995 +failed tests: 5 +total time: 184.33025455474854 +average time: 0.1852565372409533 +''' \ No newline at end of file diff --git a/main_Backtracking.py b/main_Backtracking.py index cc1147c..96bc899 100644 --- a/main_Backtracking.py +++ b/main_Backtracking.py @@ -1,54 +1,77 @@ -map_grid = [] -minDists = [] -keymaker = [] +# Initialize global variables for the map grid and minimum distances +grid_map = [] +min_distances = [] + def main(): - global map_grid, minDists - map_grid = [['.' for _ in range(9)] for _ in range(9)] - minDists = [[100 for _ in range(9)] for _ in range(9)] - - n = int(input()) - position_input = input().split() + global grid_map, min_distances + # Create a 9x9 grid map filled with '.' + grid_map = [['.' for temp in range(9)] for temp in range(9)] + # Create a minimum distance grid with initial values set to "infinity" (10000) + min_distances = [[10000 for temp in range(9)] for temp in range(9)] - x = (int)(position_input[0]) - y = (int)(position_input[1]) + # Read perception variant + variant = int(input()) + # Read Keymaker's position + position_input = input().split() + keymaker_x = int(position_input[0]) + keymaker_y = int(position_input[1]) - minDists[0][0] = 0 - findShortestPath(0, 0) - if minDists[y][x] == 100: - print("e -1") + # Set the starting position (0, 0) with a minimum distance of 0 + min_distances[0][0] = 0 + # Start the recursive pathfinding search from the starting position + find_path(0, 0) + + # Output the result based on the minimum distance to the Keymaker's position + if min_distances[keymaker_y][keymaker_x] == 10000: + print("e -1") # If no path is found, output -1 else: - print("e " + str(minDists[y][x])) + print("e " + str(min_distances[keymaker_y][keymaker_x])) # Output the shortest path length -def exploreMap(x, y): +def observe(x, y): + # Sends a move command and receives information on perceived cells around position (x, y) print(f"m {x} {y}") - n = int(input()) - for _ in range(n): - inpt = input().split() - posX, posY, character = inpt[0], inpt[1], inpt[2] - posX = int(posX) - posY = int(posY) - character = character[0] - map_grid[posY][posX] = character - + num_items = int(input()) # Number of items perceived in the vicinity + for temp in range(num_items): + # Process each perceived item with coordinates and type + item_info = input().split() + item_x, item_y, item_type = item_info[0], item_info[1], item_info[2] + item_x = int(item_x) + item_y = int(item_y) + item_type = item_type[0] + # Update the grid map with the perceived item at the given position + grid_map[item_y][item_x] = item_type -def findShortestPath(x, y): - exploreMap(x, y) - if x + 1 < 9 and map_grid[y][x + 1] not in ('P', 'A', 'S') and minDists[y][x + 1] > minDists[y][x] + 1: - minDists[y][x + 1] = minDists[y][x] + 1 - findShortestPath(x + 1, y) - exploreMap(x, y) - if x - 1 >= 0 and map_grid[y][x - 1] not in ('P', 'A', 'S') and minDists[y][x - 1] > minDists[y][x] + 1: - minDists[y][x - 1] = minDists[y][x] + 1 - findShortestPath(x - 1, y) - exploreMap(x, y) - if y + 1 < 9 and map_grid[y + 1][x] not in ('P', 'A', 'S') and minDists[y + 1][x] > minDists[y][x] + 1: - minDists[y + 1][x] = minDists[y][x] + 1 - findShortestPath(x, y + 1) - exploreMap(x, y) - if y - 1 >= 0 and map_grid[y - 1][x] not in ('P', 'A', 'S') and minDists[y - 1][x] > minDists[y][x] + 1: - minDists[y - 1][x] = minDists[y][x] + 1 - findShortestPath(x, y - 1) - exploreMap(x, y) +def find_path(x, y): + # Explore surroundings from the current position (x, y) + observe(x, y) + + # Try moving right if within bounds, the cell is safe, and the new distance is shorter + if x + 1 < 9 and grid_map[y][x + 1] not in ('P', 'A', 'S') and min_distances[y][x + 1] > min_distances[y][x] + 1: + min_distances[y][x + 1] = min_distances[y][x] + 1 + find_path(x + 1, y) # Recursive call to explore the new position + + observe(x, y) # Explore again after returning + + # Try moving left with similar conditions + if x - 1 >= 0 and grid_map[y][x - 1] not in ('P', 'A', 'S') and min_distances[y][x - 1] > min_distances[y][x] + 1: + min_distances[y][x - 1] = min_distances[y][x] + 1 + find_path(x - 1, y) + + observe(x, y) # Explore again after returning + + # Try moving down + if y + 1 < 9 and grid_map[y + 1][x] not in ('P', 'A', 'S') and min_distances[y + 1][x] > min_distances[y][x] + 1: + min_distances[y + 1][x] = min_distances[y][x] + 1 + find_path(x, y + 1) + + observe(x, y) # Explore again after returning + + # Try moving up + if y - 1 >= 0 and grid_map[y - 1][x] not in ('P', 'A', 'S') and min_distances[y - 1][x] > min_distances[y][x] + 1: + min_distances[y - 1][x] = min_distances[y][x] + 1 + find_path(x, y - 1) + + observe(x, y) # Final exploration after checking all directions. if __name__ == "__main__": main() diff --git a/main_Backtracking_testing.py b/main_Backtracking_testing.py new file mode 100644 index 0000000..3c3e775 --- /dev/null +++ b/main_Backtracking_testing.py @@ -0,0 +1,111 @@ +# Initialize global variables for the map grid and minimum distances +import time + +def get_percepted_cells(position:tuple): + cells = [] + for x in range(position[0]- perception_radius, position[0] + perception_radius + 1): + for y in range(position[1]- perception_radius, position[1] + perception_radius + 1): + if (x,y) != position: + cells.append((x,y)) + return cells + +failed_tests = 0 +passed_tests = 0 + +total_time = 0 +average_time = 0 + +test_number = 0 +with open("20k_testset.txt", "r") as file: + lines = file.readlines() + + + + + + + +line_number = 0 +while(test_number < 1000): + #time.sleep(.5) + start_time = time.time() + current_test_lines = [] + for local_line_number in range(14): + current_line = lines[line_number] + current_test_lines.append(current_line) + line_number += 1 + + + + + + grid_map = [] + min_distances = [] + + def main(): + global grid_map, min_distances + # Create a 9x9 grid map filled with '.' + grid_map = [['.' for temp in range(9)] for temp in range(9)] + # Create a minimum distance grid with initial values set to "infinity" (10000) + min_distances = [[10000 for temp in range(9)] for temp in range(9)] + + # Read perception variant + perception_radius = int(current_test_lines[1][0]) + # Read Keymaker's position + keymaker_x = int(current_test_lines[2][1]) + keymaker_y = int(current_test_lines[2][4]) + + # Set the starting position (0, 0) with a minimum distance of 0 + min_distances[0][0] = 0 + # Start the recursive pathfinding search from the starting position + find_path(0, 0) + + # Output the result based on the minimum distance to the Keymaker's position + if min_distances[keymaker_y][keymaker_x] == 10000: + print("e -1") # If no path is found, output -1 + else: + print("e " + str(min_distances[keymaker_y][keymaker_x])) # Output the shortest path length + + def observe(x, y): + # Sends a move command and receives information on perceived cells around position (x, y) + print(f"m {x} {y}") + for x_temp in range(len(test_map_matrix)): + for y_temp in range(len(test_map_matrix)): + if (x,y) in get_percepted_cells((x, y)) and test_map_matrix[x_temp][y_temp] != ".": + grid_map[x][y] = test_map_matrix[x][y] + + def find_path(x, y): + # Explore surroundings from the current position (x, y) + observe(x, y) + + # Try moving right if within bounds, the cell is safe, and the new distance is shorter + if x + 1 < 9 and grid_map[y][x + 1] not in ('P', 'A', 'S') and min_distances[y][x + 1] > min_distances[y][x] + 1: + min_distances[y][x + 1] = min_distances[y][x] + 1 + find_path(x + 1, y) # Recursive call to explore the new position + + observe(x, y) # Explore again after returning + + # Try moving left with similar conditions + if x - 1 >= 0 and grid_map[y][x - 1] not in ('P', 'A', 'S') and min_distances[y][x - 1] > min_distances[y][x] + 1: + min_distances[y][x - 1] = min_distances[y][x] + 1 + find_path(x - 1, y) + + observe(x, y) # Explore again after returning + + # Try moving down + if y + 1 < 9 and grid_map[y + 1][x] not in ('P', 'A', 'S') and min_distances[y + 1][x] > min_distances[y][x] + 1: + min_distances[y + 1][x] = min_distances[y][x] + 1 + find_path(x, y + 1) + + observe(x, y) # Explore again after returning + + # Try moving up + if y - 1 >= 0 and grid_map[y - 1][x] not in ('P', 'A', 'S') and min_distances[y - 1][x] > min_distances[y][x] + 1: + min_distances[y - 1][x] = min_distances[y][x] + 1 + find_path(x, y - 1) + + observe(x, y) # Final exploration after checking all directions. + + if __name__ == "__main__": + main() + test_map_matrix = current_test_lines[3:12]