You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
5.2 KiB

import networkx as nx
from networkx import Graph
from pyvis.network import Network
import heapq
from copy import deepcopy
from Routes.Red_Blue_Route import ARCTICUNO, BOULDER_BADGE, CASCADE_BADGE, CERULEAN_CAVE, CHAMPION, CUT, FLASH, GIOVANNI_FIGHT, MARSH_BADGE, MEWTWO, MOLTRES, PALLET_TOWN, POKE_FLUTE, QUENCHED_THURST, RAINBOW_BADGE, SILPH_SCOPE, SOUL_BADGE, SS_ANNE_TICKET, THUNDER_BADGE, VOLCANO_BADGE, ZAPDOS, get_red_blue_route
class PlayerState:
def __init__(self):
self.visited_nodes = set() # Keeps track of nodes visited
self.conditions_met = set() # Tracks conditions the player has acquired
def has_condition(self, condition):
return condition in self.conditions_met
def add_condition(self, condition):
self.conditions_met.add(condition)
def find_path_to_goal(G, start_node, goal_condition, player_state):
# Priority queue elements: (total_cost, current_node, path, state)
queue = []
initial_state = deepcopy(player_state)
heapq.heappush(queue, (0, start_node, [start_node], initial_state))
visited = set()
while queue:
total_cost, current_node, path, state = heapq.heappop(queue)
if current_node in visited:
continue
visited.add(current_node)
# Visit the current node and update the player's state if needed
new_state = deepcopy(state)
visit_node(current_node, G, new_state)
# Check if the goal condition is met
if goal_condition in new_state.conditions_met:
# Commit the updated state to the player state
player_state.visited_nodes = new_state.visited_nodes
player_state.conditions_met = new_state.conditions_met
return path
# Explore neighbors
for neighbor in G.neighbors(current_node):
edge_attrs = G[current_node][neighbor]
if can_traverse(edge_attrs, new_state):
edge_weight = edge_attrs.get('weight', 1)
new_total_cost = total_cost + edge_weight
new_path = path + [neighbor]
heapq.heappush(queue, (new_total_cost, neighbor, new_path, new_state))
return None # No path found to the goal
def find_optimal_path_with_goals(G, start_node, end_node, goals):
current_node = start_node
full_path = [start_node] # Start with the starting node in the path
player_state = PlayerState()
# Iterate through each goal to find paths in succession
for goal in goals:
path_to_goal = find_path_to_goal(G, current_node, goal, player_state)
if path_to_goal is None:
print(f"Failed to find a path to the goal: {goal}")
return None
# Extend the full path with all nodes in path_to_goal
# Avoid repeating the current_node, so exclude the first node
full_path.extend(path_to_goal[1:])
# Update current node to the goal's location
current_node = path_to_goal[-1]
# Finally, find the path to the end node
#path_to_end = find_path_to_goal(G, current_node, None, player_state)
#if path_to_end is None:
# print("Failed to find a path to the end node.")
# return None
# Extend the full path with all nodes in path_to_end, excluding the first node to avoid repetition
#full_path.extend(path_to_end[1:])
return full_path
def visit_node(node_name, G, player_state: PlayerState):
# Add the current node to the visited set
player_state.visited_nodes.add(node_name)
# Grant conditions or items found at this node
node_attrs = G.nodes[node_name]
grants_conditions = node_attrs.get('grants_conditions', [])
for grant in grants_conditions:
condition = grant['condition']
required_conditions = grant.get('required_conditions', [])
# Only add conditions if requirements are met
if all(cond in player_state.conditions_met for cond in required_conditions):
if not player_state.has_condition(condition):
player_state.add_condition(condition)
print(f"Condition '{condition}' granted upon visiting '{node_name}'.")
def can_traverse(edge_attrs, player_state: PlayerState):
# Check if the player meets all the conditions required to traverse this edge
conditions = edge_attrs.get('condition')
if not conditions:
return True
return all(condition in player_state.conditions_met for condition in conditions)
# Example usage
if __name__ == "__main__":
G = get_red_blue_route()
# Define the ordered goals that the player must acquire
goals = [
BOULDER_BADGE,
CASCADE_BADGE,
SS_ANNE_TICKET,
CUT,
THUNDER_BADGE,
FLASH,
SILPH_SCOPE,
RAINBOW_BADGE,
QUENCHED_THURST,
POKE_FLUTE,
GIOVANNI_FIGHT,
MARSH_BADGE,
SOUL_BADGE,
VOLCANO_BADGE,
ARCTICUNO,
ZAPDOS,
MOLTRES,
CHAMPION,
MEWTWO
]
# Find the optimal path while fulfilling goals in succession
optimal_path = find_optimal_path_with_goals(G, PALLET_TOWN, CERULEAN_CAVE, goals)
if optimal_path:
print("Optimal Path:", " -> ".join(optimal_path))
else:
print("No path found to fulfill all goals.")