Browse Source

- First pass at a working Red/Blue route

rough-outline
Dan 1 year ago
parent
commit
c979c4bd82
  1. 316
      Pokemon_Red_Route_Planner.py
  2. 206
      Routes/Red_Blue_Route.py
  3. 0
      Routes/__init__.py
  4. 145
      red_blue_goal_path.py

316
Pokemon_Red_Route_Planner.py

@ -1,211 +1,159 @@
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 CERULEAN_CAVE, PALLET_TOWN, get_red_blue_route
class PlayerState:
def __init__(self):
self.visited_nodes = {}
self.conditions_met = set()
self.goals = set() # Tracks unmet conditions required for future traversal
def find_optimal_path(G, start_node, end_node):
# Priority queue elements: (total_cost, current_node, player_state, path)
queue = []
initial_state = PlayerState()
heapq.heappush(queue, (0, start_node, [start_node], initial_state))
visited_states = {}
while queue:
total_cost, current_node, path , player_state= heapq.heappop(queue)
# If end node is reached
if current_node == end_node:
return path
if current_node in player_state.visited_nodes:
player_state.visited_nodes[current_node] += 1
else:
player_state.visited_nodes[current_node] = 1
# Visit the current node and update the player's state
visit_node(current_node, G, player_state)
# Explore neighbors
for neighbor in G.neighbors(current_node):
edge_attrs = G[current_node][neighbor]
if can_traverse(edge_attrs, player_state):
visit_count = player_state.visited_nodes.get(neighbor, 0)
edge_weight = max(1, visit_count)
# Apply weight reduction if this neighbor helps meet a goal
if any(condition in player_state.goals for condition in player_state.conditions_met):
edge_weight = max(1, edge_weight - 1) # Reduce weight to incentivize this path
new_total_cost = total_cost + edge_weight
# Copy path, but keep player_state as is (state should persist across paths)
new_path = path + [neighbor]
heapq.heappush(queue, (new_total_cost, neighbor, new_path, deepcopy(player_state)))
else:
unmet_conditions = edge_attrs.get('condition', [])
for condition in unmet_conditions:
if condition not in player_state.conditions_met:
player_state.goals.add(condition)
return None # No path found
def can_traverse(edge_attrs, player_state: PlayerState):
conditions = edge_attrs.get('condition')
if not conditions:
return True
return any(condition in conditions for condition in player_state.conditions_met)
def visit_node(node_name, G, player_state: PlayerState):
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', [])
if all(cond in player_state.conditions_met for cond in required_conditions):
if condition not in player_state.conditions_met:
player_state.conditions_met.add(condition)
print(f"Condition '{condition}' granted upon visiting '{node_name}'.")
if condition in player_state.goals:
player_state.goals.remove(condition)
else:
print(f"Cannot obtain '{condition}' from '{node_name}' because required conditions are not met: {required_conditions}")
def get_available_moves(current_node, G, player_state):
available_moves = []
for neighbor in G.neighbors(current_node):
edge_attrs = G[current_node][neighbor]
if can_traverse(edge_attrs, player_state):
available_moves.append(neighbor)
return available_moves
PALLET_TOWN = 'Pallet Town'
VIRIDIAN_CITY = 'Viridian City'
VIRIDIAN_FOREST = 'Viridian Forest'
PEWTER_CITY = 'Pewter City'
MT_MOON = 'Mt. Moon'
CERULEAN_CITY = 'Cerulean City'
POWER_PLANT = 'Power Plant'
SAFFRON_CITY = 'Saffron City'
CELADON_CITY = 'Celadon City'
CERULEAN_CAVE = 'Cerulean Cave'
VERMILLION_CITY = 'Vermillion City'
BILLS_HOUSE = 'Bill\'s House'
FUCHSIA_CITY = 'Fuchsia City'
SS_ANNE = 'S.S. Anne'
CINNABAR_ISLAND = 'Cinnabar Island'
SEAFOAM_ISLANDS ='Seafoam Islands'
VICTORY_ROAD = 'Victory Road'
INDIGO_PLATEAU = 'Indigo Plateau'
ROCK_TUNNEL = 'Rock Tunnel'
UNDERGROUND_PATH = 'Underground Path'
UNDERGROUND_PASSAGE = 'Underground Passage'
DIGLETT_CAVE = 'Diglett Cave'
POKEMON_TOWER = 'Pokemon Tower'
LAVENDER_TOWN = 'Lavender Town'
BOULDER_BADGE = 'Boulder Badge'
CASCADE_BADGE = 'Cascade Badge'
THUNDER_BADGE = 'Thunder Badge'
RAINBOW_BADGE = 'Rainbow Badge'
MARSH_BADGE = 'Marsh Badge'
SOUL_BADGE = 'Soul Badge'
VOLCANO_BADGE = 'Volcano Badge'
EARTH_BADGE = 'Earth Badge'
BIKE = 'Bike'
BIKE_VOUCHER = 'Bike Voucer'
SS_ANNE_TICKET = 'S.S. Anne Ticket'
QUENCHED_THURST = 'Quenched Thrust'
POKE_FLUTE = 'Poke Flute'
SILPH_SCOPE = 'Silph Scope'
GIOVANNI_FIGHT = 'Giovanni Fight'
CHAMPION = 'Champion'
CUT = 'Cut'
SURF = 'Surf'
FLASH = 'Flash'
STRENGTH = 'Strength'
def main():
G = nx.DiGraph()
for i in range(1,25):
G.add_node(f'Route {i}', node_type='route')
G.nodes['Route 2']['grants_conditions'] = [
{'condition': FLASH, 'required_conditions': [CUT]}
]
G.add_node(PALLET_TOWN, node_type='location')
G.add_node(VIRIDIAN_CITY, node_type='location')
G.nodes[VIRIDIAN_CITY]['grants_conditions'] = [
{'condition': EARTH_BADGE, 'required_conditions': [GIOVANNI_FIGHT]}
]
G.add_node(VIRIDIAN_FOREST, node_type='location')
G.add_node(PEWTER_CITY, node_type='location')
G.nodes[PEWTER_CITY]['grants_conditions'] = [
{'condition': BOULDER_BADGE, 'required_conditions': []}
]
G.add_node(MT_MOON, node_type='location')
G.add_node(CERULEAN_CITY, node_type='location')
G.nodes[CERULEAN_CITY]['grants_conditions'] = [
{'condition': CASCADE_BADGE, 'required_conditions': []},
{'condition': BIKE, 'required_conditions': [BIKE_VOUCHER]},
]
G.add_node(BILLS_HOUSE, node_type='location')
G.nodes[BILLS_HOUSE]['grants_conditions'] = [
{'condition': SS_ANNE_TICKET, 'required_conditions': []}
]
G.add_node(POWER_PLANT, node_type='location')
G.add_node(SAFFRON_CITY, node_type='location')
G.nodes[SAFFRON_CITY]['grants_conditions'] = [
{'condition': MARSH_BADGE, 'required_conditions': []},
{'condition': GIOVANNI_FIGHT, 'required_conditions': []},
]
G.add_node(SS_ANNE, node_type='location')
G.nodes[SS_ANNE]['grants_conditions'] = [
{'condition': CUT, 'required_conditions': []}
]
G.add_node(CERULEAN_CAVE, node_type='location')
G.add_node(VERMILLION_CITY, node_type='location')
G.nodes[VERMILLION_CITY]['grants_conditions'] = [
{'condition': BIKE_VOUCHER, 'required_conditions': []},
{'condition': THUNDER_BADGE, 'required_conditions': [CUT]}
]
G.add_node(CELADON_CITY, node_type='location')
G.nodes[CELADON_CITY]['grants_conditions'] = [
{'condition': QUENCHED_THURST, 'required_conditions': []},
{'condition': RAINBOW_BADGE, 'required_conditions': []},
{'condition': SILPH_SCOPE, 'required_conditions': []}
]
G.add_node(FUCHSIA_CITY, node_type='location')
G.nodes[FUCHSIA_CITY]['grants_conditions'] = [
{'condition': SURF, 'required_conditions': []},
{'condition': STRENGTH, 'required_conditions': []},
{'condition': SOUL_BADGE, 'required_conditions': []},
]
G.add_node(CINNABAR_ISLAND, node_type='location')
G.nodes[SS_ANNE]['grants_conditions'] = [
{'condition': VOLCANO_BADGE, 'required_conditions': []}
]
G.add_node(SEAFOAM_ISLANDS, node_type='location')
G.add_node(VICTORY_ROAD, node_type='location')
G.add_node(INDIGO_PLATEAU, node_type='location')
G.nodes[INDIGO_PLATEAU]['grants_conditions'] = [
{'condition': CHAMPION, 'required_conditions': []}
]
G.add_node(ROCK_TUNNEL, node_type='location')
G.add_node(UNDERGROUND_PATH, node_type='location')
G.add_node(DIGLETT_CAVE, node_type='location')
G.add_node(POKEMON_TOWER, node_type='location')
G.nodes[POKEMON_TOWER]['grants_conditions'] = [
{'condition': POKE_FLUTE, 'required_conditions': []}
]
G.add_node(LAVENDER_TOWN, node_type='location')
G.add_node(UNDERGROUND_PASSAGE, node_type='location')
G.add_edge('Pallet Town', 'Route 1', condition=None)
G.add_edge('Pallet Town', 'Route 21', condition=None)
G.add_edge('Route 1', 'Viridian City', condition=None)
G.add_edge('Viridian City', 'Route 2', condition=None)
G.add_edge('Route 2', 'Viridian Forest', condition=None)
G.add_edge('Viridian Forest', 'Pewter City', condition=None)
G.add_edge('Pewter City', 'Route 3', condition=None)
G.add_edge('Route 3', 'Mt. Moon', condition=None)
G.add_edge('Mt. Moon', 'Route 4', condition=None)
G.add_edge('Route 4', 'Cerulean City', condition=None)
G.add_edge('Cerulean City', 'Route 24', condition=None)
G.add_edge('Cerulean City', 'Route 9', condition=[CUT])
G.add_edge('Cerulean City', 'Route 5', condition=None)
G.add_edge('Route 5', 'Saffron City', condition=[QUENCHED_THURST])
G.add_edge('Saffron City', 'Route 6', condition=[QUENCHED_THURST])
G.add_edge('Saffron City', 'Route 7', condition=[QUENCHED_THURST])
G.add_edge('Saffron City', 'Route 8', condition=[QUENCHED_THURST])
G.add_edge('Route 6', 'Vermillion City', condition=None)
G.add_edge('Vermillion City', 'Route 11', condition=None)
G.add_edge('Vermillion City', SS_ANNE, condition=[SS_ANNE_TICKET])
G.add_edge('Route 11', 'Route 12', condition=[POKE_FLUTE])
G.add_edge('Route 11', DIGLETT_CAVE, condition=None)
G.add_edge('Route 2', DIGLETT_CAVE, condition=[CUT])
G.add_edge('Route 12', 'Route 13', condition=None)
G.add_edge('Route 12', LAVENDER_TOWN, condition=None)
G.add_edge('Route 7', LAVENDER_TOWN, condition=None)
G.add_edge(LAVENDER_TOWN, 'Route 10', condition=None)
G.add_edge('Route 9', 'Rock Tunnel', condition=[FLASH])
G.add_edge('Route 10', 'Rock Tunnel', condition=[FLASH])
G.add_edge('Celadon City', 'Route 8', condition=None)
G.add_edge('Celadon City', 'Route 16', condition=None)
G.add_edge('Route 16', 'Route 17', condition=[POKE_FLUTE])
G.add_edge('Route 17', 'Route 18', condition=[BIKE])
G.add_edge('Route 18', 'Fuchsia City', condition=[BIKE])
G.add_edge('Fuchsia City','Route 19', condition=None)
G.add_edge('Fuchsia City','Route 15', condition=None)
G.add_edge('Fuchsia City','Safari Zone', condition=None)
G.add_edge('Route 19', 'Seafoam Islands', condition=[SURF])
G.add_edge('Seafoam Islands', 'Route 20', condition=[SURF])
G.add_edge('Route 20', 'Cinnabar Island', condition=[SURF])
G.add_edge('Route 21', 'Cinnabar Island', condition=[SURF])
G.add_edge('Route 22', 'Viridian City', condition=None)
G.add_edge('Route 22', 'Route 23', condition=[SURF])
G.add_edge('Route 23', 'Victory Road', condition=[BOULDER_BADGE, CASCADE_BADGE, THUNDER_BADGE, RAINBOW_BADGE, MARSH_BADGE, SOUL_BADGE, VOLCANO_BADGE, EARTH_BADGE])
G.add_edge('Victory Road', 'Indigo Plateau', condition=None)
G.add_edge('Route 12', 'Route 13', condition=None)
G.add_edge('Route 13', 'Route 14', condition=None)
G.add_edge('Route 14', 'Route 15', condition=None)
G.add_edge('Route 24', 'Cerulean Cave', condition=[SURF, CHAMPION])
G.add_edge('Route 10', 'Power Plant', condition=[SURF])
G.add_edge('Route 5', 'Underground Path', condition=None)
G.add_edge('Underground Path', 'Route 6', condition=None)
G.add_edge(LAVENDER_TOWN, POKEMON_TOWER, condition=[SILPH_SCOPE])
G.add_edge(UNDERGROUND_PASSAGE, 'Route 7', condition=None)
G.add_edge(UNDERGROUND_PASSAGE, 'Route 8', condition=None)
player_state = {
'visited_nodes': set(),
'conditions_met': set()
}
G = get_red_blue_route()
net = Network(notebook=True)
optimal_path = find_optimal_path(G, PALLET_TOWN, CERULEAN_CAVE)
if optimal_path is None:
return
# Create a set of edges in the optimal path for quick lookup
optimal_edges = set(zip(optimal_path, optimal_path[1:]))
# Add nodes to the network
for node, attrs in G.nodes(data=True):
net.add_node(
node,
label=node,
title=f"Type: {attrs}",
color='lightblue' if attrs == 'location' else 'lightgreen'
title=f"Type: {attrs['node_type']}",
color='lightblue' if attrs['node_type'] == 'location' else 'lightgreen'
)
# Add edges, highlighting those in the optimal path
for source, target, attrs in G.edges(data=True):
condition = attrs['condition']
edge_label = f"Condition: {condition}" if condition else "No condition"
edge_color = 'blue' if (source, target) in optimal_edges else 'gray'
net.add_edge(
source,
target,
title=edge_label,
label=edge_label,
color='red' if condition else 'gray'
color=edge_color
)
net.show('pokemon_map.html')
net.show('optimal_pokemon_map.html')
net2 = Network(notebook=True)
# Add nodes with special styling for conditional grants
for node, attrs in G.nodes(data=True):
color = 'lightblue'
title = f"Type: {attrs.get('node_type', 'Unknown')}"
if 'grants_condition' in attrs:
title += f"<br>Grants: {attrs['grants_condition']}"
if 'required_conditions' in attrs:
title += f" (Requires: {attrs['required_conditions']})"
color = 'orange' # Highlight nodes with conditional grants
else:
color = 'green' # Nodes that grant conditions without prerequisites
net2.add_node(node, label=node, title=title, color=color)
# Add edges
for source, target, attrs in G.edges(data=True):
condition = attrs.get('condition')
edge_label = f"Condition: {condition}" if condition else "No condition"
color = 'red' if condition else 'gray'
net2.add_edge(source, target, title=edge_label, label=edge_label, color=color)
net2.show('pokemon_map_with_conditions.html')
if __name__ == "__main__":

206
Routes/Red_Blue_Route.py

@ -0,0 +1,206 @@
import networkx as nx
from networkx import Graph
PALLET_TOWN = 'Pallet Town'
VIRIDIAN_CITY = 'Viridian City'
VIRIDIAN_FOREST = 'Viridian Forest'
PEWTER_CITY = 'Pewter City'
MT_MOON = 'Mt. Moon'
CERULEAN_CITY = 'Cerulean City'
POWER_PLANT = 'Power Plant'
SAFFRON_CITY = 'Saffron City'
CELADON_CITY = 'Celadon City'
CERULEAN_CAVE = 'Cerulean Cave'
VERMILLION_CITY = 'Vermillion City'
BILLS_HOUSE = 'Bill\'s House'
FUCHSIA_CITY = 'Fuchsia City'
SS_ANNE = 'S.S. Anne'
CINNABAR_ISLAND = 'Cinnabar Island'
SEAFOAM_ISLANDS ='Seafoam Islands'
VICTORY_ROAD = 'Victory Road'
INDIGO_PLATEAU = 'Indigo Plateau'
ROCK_TUNNEL = 'Rock Tunnel'
UNDERGROUND_PATH = 'Underground Path'
UNDERGROUND_PASSAGE = 'Underground Passage'
DIGLETT_CAVE = 'Diglett Cave'
POKEMON_TOWER = 'Pokemon Tower'
LAVENDER_TOWN = 'Lavender Town'
BOULDER_BADGE = 'Boulder Badge'
CASCADE_BADGE = 'Cascade Badge'
THUNDER_BADGE = 'Thunder Badge'
RAINBOW_BADGE = 'Rainbow Badge'
MARSH_BADGE = 'Marsh Badge'
SOUL_BADGE = 'Soul Badge'
VOLCANO_BADGE = 'Volcano Badge'
EARTH_BADGE = 'Earth Badge'
BIKE = 'Bike'
BIKE_VOUCHER = 'Bike Voucer'
SS_ANNE_TICKET = 'S.S. Anne Ticket'
QUENCHED_THURST = 'Quenched Thrust'
POKE_FLUTE = 'Poke Flute'
SILPH_SCOPE = 'Silph Scope'
GIOVANNI_FIGHT = 'Giovanni Fight'
CHAMPION = 'Champion'
MEWTWO = 'Mewtwo'
ARCTICUNO = 'Arcticuno'
ZAPDOS = 'Zapdos'
MOLTRES = 'Moltres'
CUT = 'Cut'
SURF = 'Surf'
FLASH = 'Flash'
STRENGTH = 'Strength'
def get_red_blue_route() -> Graph:
G = nx.Graph()
for i in range(1,25):
G.add_node(f'Route {i}', node_type='route')
G.nodes['Route 2']['grants_conditions'] = [
{'condition': FLASH, 'required_conditions': [CUT]}
]
G.add_node(PALLET_TOWN, node_type='location')
G.add_node(VIRIDIAN_CITY, node_type='location')
G.nodes[VIRIDIAN_CITY]['grants_conditions'] = [
{'condition': EARTH_BADGE, 'required_conditions': [GIOVANNI_FIGHT]}
]
G.add_node(VIRIDIAN_FOREST, node_type='location')
G.add_node(PEWTER_CITY, node_type='location')
G.nodes[PEWTER_CITY]['grants_conditions'] = [
{'condition': BOULDER_BADGE, 'required_conditions': []}
]
G.add_node(MT_MOON, node_type='location')
G.add_node(CERULEAN_CITY, node_type='location')
G.nodes[CERULEAN_CITY]['grants_conditions'] = [
{'condition': CASCADE_BADGE, 'required_conditions': []},
{'condition': BIKE, 'required_conditions': [BIKE_VOUCHER]},
]
G.add_node(BILLS_HOUSE, node_type='location')
G.nodes[BILLS_HOUSE]['grants_conditions'] = [
{'condition': SS_ANNE_TICKET, 'required_conditions': []}
]
G.add_node(POWER_PLANT, node_type='location')
G.nodes[POWER_PLANT]['grants_conditions'] = [
{'condition': ZAPDOS, 'required_conditions': []}
]
G.add_node(SAFFRON_CITY, node_type='location')
G.nodes[SAFFRON_CITY]['grants_conditions'] = [
{'condition': MARSH_BADGE, 'required_conditions': []},
{'condition': GIOVANNI_FIGHT, 'required_conditions': []},
]
G.add_node(SS_ANNE, node_type='location')
G.nodes[SS_ANNE]['grants_conditions'] = [
{'condition': CUT, 'required_conditions': []}
]
G.add_node(CERULEAN_CAVE, node_type='location')
G.nodes[CERULEAN_CAVE]['grants_conditions'] = [
{'condition': MEWTWO, 'required_conditions': []}
]
G.add_node(VERMILLION_CITY, node_type='location')
G.nodes[VERMILLION_CITY]['grants_conditions'] = [
{'condition': BIKE_VOUCHER, 'required_conditions': []},
{'condition': THUNDER_BADGE, 'required_conditions': [CUT]}
]
G.add_node(CELADON_CITY, node_type='location')
G.nodes[CELADON_CITY]['grants_conditions'] = [
{'condition': QUENCHED_THURST, 'required_conditions': []},
{'condition': RAINBOW_BADGE, 'required_conditions': []},
{'condition': SILPH_SCOPE, 'required_conditions': []}
]
G.add_node(FUCHSIA_CITY, node_type='location')
G.nodes[FUCHSIA_CITY]['grants_conditions'] = [
{'condition': SURF, 'required_conditions': []},
{'condition': STRENGTH, 'required_conditions': []},
{'condition': SOUL_BADGE, 'required_conditions': []},
]
G.add_node(CINNABAR_ISLAND, node_type='location')
G.nodes[CINNABAR_ISLAND]['grants_conditions'] = [
{'condition': VOLCANO_BADGE, 'required_conditions': []}
]
G.add_node(SEAFOAM_ISLANDS, node_type='location')
G.nodes[SEAFOAM_ISLANDS]['grants_conditions'] = [
{'condition': ARCTICUNO, 'required_conditions': []}
]
G.add_node(VICTORY_ROAD, node_type='location')
G.nodes[VICTORY_ROAD]['grants_conditions'] = [
{'condition': MOLTRES, 'required_conditions': []}
]
G.add_node(INDIGO_PLATEAU, node_type='location')
G.nodes[INDIGO_PLATEAU]['grants_conditions'] = [
{'condition': CHAMPION, 'required_conditions': []}
]
G.add_node(ROCK_TUNNEL, node_type='location')
G.add_node(UNDERGROUND_PATH, node_type='location')
G.add_node(DIGLETT_CAVE, node_type='location')
G.add_node(POKEMON_TOWER, node_type='location')
G.nodes[POKEMON_TOWER]['grants_conditions'] = [
{'condition': POKE_FLUTE, 'required_conditions': []}
]
G.add_node(LAVENDER_TOWN, node_type='location')
G.add_node(UNDERGROUND_PASSAGE, node_type='location')
G.add_edge('Pallet Town', 'Route 1', condition=None)
G.add_edge('Pallet Town', 'Route 21', condition=[SURF])
G.add_edge('Route 1', 'Viridian City', condition=None)
G.add_edge('Viridian City', 'Route 2', condition=None)
G.add_edge('Route 2', 'Viridian Forest', condition=None)
G.add_edge('Route 2', 'Route 3', condition=[CUT])
G.add_edge('Viridian Forest', 'Pewter City', condition=None)
G.add_edge('Pewter City', 'Route 3', condition=None)
G.add_edge('Route 3', 'Mt. Moon', condition=None)
G.add_edge('Mt. Moon', 'Route 4', condition=None)
G.add_edge('Route 4', 'Cerulean City', condition=None)
G.add_edge('Cerulean City', 'Route 24', condition=None)
G.add_edge('Cerulean City', 'Route 9', condition=[CUT])
G.add_edge('Cerulean City', 'Route 5', condition=None)
G.add_edge('Route 5', 'Saffron City', condition=[QUENCHED_THURST])
G.add_edge('Saffron City', 'Route 6', condition=[QUENCHED_THURST])
G.add_edge('Saffron City', 'Route 7', condition=[QUENCHED_THURST])
G.add_edge('Saffron City', 'Route 8', condition=[QUENCHED_THURST])
G.add_edge('Route 6', 'Vermillion City', condition=None)
G.add_edge('Vermillion City', 'Route 11', condition=None)
G.add_edge('Vermillion City', SS_ANNE, condition=[SS_ANNE_TICKET])
G.add_edge('Route 11', 'Route 12', condition=[POKE_FLUTE])
G.add_edge('Route 11', DIGLETT_CAVE, condition=None)
G.add_edge('Route 2', DIGLETT_CAVE, condition=[CUT])
G.add_edge('Route 12', 'Route 13', condition=None)
G.add_edge('Route 12', LAVENDER_TOWN, condition=None)
G.add_edge('Route 7', LAVENDER_TOWN, condition=None)
G.add_edge(LAVENDER_TOWN, 'Route 10', condition=None)
G.add_edge('Route 9', 'Rock Tunnel', condition=[FLASH])
G.add_edge('Route 10', 'Rock Tunnel', condition=[FLASH])
G.add_edge('Celadon City', 'Route 8', condition=None)
G.add_edge('Celadon City', 'Route 16', condition=None)
G.add_edge('Route 16', 'Route 17', condition=[POKE_FLUTE])
G.add_edge('Route 17', 'Route 18', condition=[BIKE])
G.add_edge('Route 18', 'Fuchsia City', condition=[BIKE])
G.add_edge('Fuchsia City','Route 19', condition=None)
G.add_edge('Fuchsia City','Route 15', condition=None)
G.add_edge('Fuchsia City','Safari Zone', condition=None)
G.add_edge('Route 19', 'Seafoam Islands', condition=[SURF])
G.add_edge('Seafoam Islands', 'Route 20', condition=[SURF])
G.add_edge('Route 20', 'Cinnabar Island', condition=[SURF])
G.add_edge('Route 21', 'Cinnabar Island', condition=[SURF])
G.add_edge('Route 22', 'Viridian City', condition=None)
G.add_edge('Route 22', 'Route 23', condition=[SURF])
G.add_edge('Route 23', 'Victory Road', condition=[BOULDER_BADGE, CASCADE_BADGE, THUNDER_BADGE, RAINBOW_BADGE, MARSH_BADGE, SOUL_BADGE, VOLCANO_BADGE, EARTH_BADGE])
G.add_edge('Victory Road', 'Indigo Plateau', condition=None)
G.add_edge('Route 12', 'Route 13', condition=None)
G.add_edge('Route 13', 'Route 14', condition=None)
G.add_edge('Route 14', 'Route 15', condition=None)
G.add_edge('Route 24', 'Cerulean Cave', condition=[SURF, CHAMPION])
G.add_edge('Route 24', 'Route 25', condition=None)
G.add_edge('Route 25', BILLS_HOUSE, condition=None)
G.add_edge('Route 10', 'Power Plant', condition=[SURF])
G.add_edge('Route 5', 'Underground Path', condition=None)
G.add_edge('Underground Path', 'Route 6', condition=None)
G.add_edge(LAVENDER_TOWN, POKEMON_TOWER, condition=[SILPH_SCOPE])
G.add_edge(UNDERGROUND_PASSAGE, 'Route 7', condition=None)
G.add_edge(UNDERGROUND_PASSAGE, 'Route 8', condition=None)
return G

0
Routes/__init__.py

145
red_blue_goal_path.py

@ -0,0 +1,145 @@
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.")
Loading…
Cancel
Save