Compare commits
11 Commits
master
...
rough-outl
| Author | SHA1 | Date |
|---|---|---|
|
|
4509054f48 | 1 year ago |
|
|
f35cae4e59 | 1 year ago |
|
|
13d38b9860 | 1 year ago |
|
|
d873cfd069 | 1 year ago |
|
|
68c60ea300 | 1 year ago |
|
|
6d1f55cece | 1 year ago |
|
|
6196c2322e | 1 year ago |
|
|
239685d026 | 1 year ago |
|
|
c979c4bd82 | 1 year ago |
|
|
377deb5bb4 | 1 year ago |
|
|
231b9b45c0 | 1 year ago |
9 changed files with 1305 additions and 0 deletions
@ -0,0 +1,15 @@ |
|||
{ |
|||
// Use IntelliSense to learn about possible attributes. |
|||
// Hover to view descriptions of existing attributes. |
|||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 |
|||
"version": "0.2.0", |
|||
"configurations": [ |
|||
{ |
|||
"name": "Python Debugger: Current File", |
|||
"type": "debugpy", |
|||
"request": "launch", |
|||
"program": "${file}", |
|||
"console": "integratedTerminal" |
|||
} |
|||
] |
|||
} |
|||
@ -0,0 +1,163 @@ |
|||
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 |
|||
|
|||
|
|||
def main(): |
|||
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['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=edge_color |
|||
) |
|||
|
|||
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__": |
|||
try: |
|||
main() |
|||
finally: |
|||
pass |
|||
@ -0,0 +1,377 @@ |
|||
import networkx as nx |
|||
from networkx import Graph |
|||
|
|||
from Routes.pokemon_game_desc import PokemonGameDesc |
|||
|
|||
NEW_BARK_TOWN = 'New Bark Town' |
|||
CHERRYGROVE_CITY = 'Cherrygrove City' |
|||
VIOLET_CITY = 'Violet City' |
|||
SPROUT_TOWER = 'Sprout Tower' |
|||
RUINS_OF_ALPH = 'Ruins of Alph' |
|||
UNION_CAVE = 'Union Cave' |
|||
AZALEA_TOWN = 'Azalea Town' |
|||
SLOWPOKE_WELL = 'Slowpoke Well' |
|||
ILEX_FOREST = 'Ilex Forest' |
|||
GOLDENROD_CITY = 'Goldenrod City' |
|||
NATIONAL_PARK = 'National Park' |
|||
ECRUTEAK_CITY = 'Ecruteak City' |
|||
MOOMOO_FARM = 'MooMoo Farm' |
|||
OLIVINE_CITY = 'Olivine City' |
|||
CIANWOOD_CITY = 'Cianwood City' |
|||
MAHOGANY_TOWN = 'Mahogany Town' |
|||
LAKE_OF_RAGE = 'Lake of Rage' |
|||
TEAM_ROCKET_HQ = 'Team Rocket H.Q.' |
|||
ICE_PATH = 'Ice Path' |
|||
BLACKTHORN_CITY = 'Blackthorn City' |
|||
MT_MORTAR = 'Mt. Mortar' |
|||
TIN_TOWER = 'Tin Tower' |
|||
WHIRL_ISLANDS = 'Whirl Islands' |
|||
DARK_CAVE = 'Dark Cave' |
|||
VICTORY_ROAD = 'Victory Road' |
|||
INDIGO_PLATEAU = 'Indigo Plateau' |
|||
SS_AQUA = 'S.S. Aqua' |
|||
VERMILION_CITY = 'Vermilion City' |
|||
SAFFRON_CITY = 'Saffron City' |
|||
LAVENDER_TOWN = 'Lavender Town' |
|||
ROCK_TUNNEL = 'Rock Tunnel' |
|||
CERULEAN_CITY = 'Cerulean City' |
|||
CELADON_CITY = 'Celadon City' |
|||
FUCHSIA_CITY = 'Fuchsia City' |
|||
DIGLETTS_CAVE = "Diglett's Cave" |
|||
PEWTER_CITY = 'Pewter City' |
|||
MT_MOON = 'Mt. Moon' |
|||
VIRIDIAN_CITY = 'Viridian City' |
|||
PALLET_TOWN = 'Pallet Town' |
|||
CINNABAR_ISLAND = 'Cinnabar Island' |
|||
MT_SILVER = 'Mt. Silver' |
|||
SAFARI_ZONE = 'Safari Zone' |
|||
TOHJO_FALLS = 'Tohjo Falls' |
|||
POWER_PLANT = 'Power Plant' |
|||
LEAGUE_RECEPTION_GATE = 'League Reception Gate' |
|||
|
|||
CUT = 'Cut' |
|||
SURF = 'Surf' |
|||
FLASH = 'Flash' |
|||
STRENGTH = 'Strength' |
|||
ROCK_SMASH = 'Rock Smash' |
|||
WHIRLPOOL = 'Whirlpool' |
|||
WATERFALL = 'Waterfall' |
|||
|
|||
ZEPHYR_BADGE = 'Zephyr Badge' |
|||
HIVE_BADGE = 'Hive Badge' |
|||
PLAIN_BADGE = 'Plain Badge' |
|||
FOG_BADGE = 'Fog Badge' |
|||
STORM_BADGE = 'Storm Badge' |
|||
MINERAL_BADGE = 'Mineral Badge' |
|||
GLACIER_BADGE = 'Glacier Badge' |
|||
RISING_BADGE = 'Rising Badge' |
|||
|
|||
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' |
|||
|
|||
SQUIRTBOTTLE = 'Squirt bottle' |
|||
MEDICINE = 'Medicine' |
|||
CATCH_RED_GYRADOS = 'Catch Red Gryados' |
|||
ROCKET_DEAFEATED = 'Rocket Defeated' |
|||
PKMN_WING = 'Gold Silver Wing' |
|||
JOHTO_CHAMPION = 'Johto Champion' |
|||
S_S_TICKET = 'S.S. Ticket' |
|||
WOKE_SNORLAX = 'Woke Snorlax' |
|||
EXPN_CARD = 'Expn card' |
|||
POWER_RESTORED = 'Power restored' |
|||
MACHINE_PART = 'Machine Part' |
|||
CLEFAIRY_DOLL = 'Clefairy Doll' |
|||
RAIL_PASS = 'Rail Pass' |
|||
MISTY_FOUND = 'Misty Found' |
|||
FLUTE_CHANNEL = 'Flute Channel' |
|||
ROUTE_28_UNLOCKED = 'Rotue 28 Unlocked' |
|||
POWER_PLANT_VISITED = 'POWER_PLANT_VISITED' |
|||
|
|||
FLY = 'Fly' |
|||
FLY_OUT_OF_BATTLE = 'Fly out of battle' |
|||
|
|||
def get_gold_silver_desc() -> PokemonGameDesc: |
|||
desc: PokemonGameDesc = PokemonGameDesc() |
|||
desc.graph = get_gold_silver_route() |
|||
desc.game_name = "Gold_Silver" |
|||
desc.towns_and_cities = [NEW_BARK_TOWN, CHERRYGROVE_CITY, VIOLET_CITY, AZALEA_TOWN, GOLDENROD_CITY, ECRUTEAK_CITY, OLIVINE_CITY, CIANWOOD_CITY, MAHOGANY_TOWN, BLACKTHORN_CITY, PALLET_TOWN, VIRIDIAN_CITY, PEWTER_CITY, CERULEAN_CITY, SAFFRON_CITY, CELADON_CITY, VERMILION_CITY, FUCHSIA_CITY, CINNABAR_ISLAND] |
|||
desc.badges = [ZEPHYR_BADGE, HIVE_BADGE, PLAIN_BADGE, FOG_BADGE, STORM_BADGE, MINERAL_BADGE, GLACIER_BADGE, RISING_BADGE, BOULDER_BADGE, CASCADE_BADGE, THUNDER_BADGE, RAINBOW_BADGE, MARSH_BADGE, SOUL_BADGE, VOLCANO_BADGE, EARTH_BADGE] |
|||
desc.hms = [CUT, SURF, FLASH, STRENGTH, FLY, WATERFALL, WHIRLPOOL] |
|||
desc.additional_goals = [WOKE_SNORLAX] |
|||
#desc.must_visit = set([MT_MOON]) |
|||
desc.starting_town = NEW_BARK_TOWN |
|||
desc.end_goal = MT_SILVER |
|||
|
|||
desc.one_way_routes.append("Route_29 -> Route_46") |
|||
|
|||
return desc |
|||
|
|||
def get_gold_silver_route() -> Graph: |
|||
G = nx.Graph() |
|||
|
|||
for i in range(1,46): |
|||
G.add_node(f'Route {i}', node_type='route') |
|||
|
|||
G.add_node(NEW_BARK_TOWN, node_type='location') |
|||
G.add_node(CHERRYGROVE_CITY, node_type='location') |
|||
G.add_node(VIOLET_CITY, node_type='location') |
|||
G.add_node(SPROUT_TOWER, node_type='location') |
|||
G.add_node(RUINS_OF_ALPH, node_type='location') |
|||
G.add_node(UNION_CAVE, node_type='location') |
|||
G.add_node(AZALEA_TOWN, node_type='location') |
|||
G.add_node(SLOWPOKE_WELL, node_type='location') |
|||
G.add_node(ILEX_FOREST, node_type='location') |
|||
G.add_node(GOLDENROD_CITY, node_type='location') |
|||
G.add_node(NATIONAL_PARK, node_type='location') |
|||
G.add_node(ECRUTEAK_CITY, node_type='location') |
|||
G.add_node(MOOMOO_FARM, node_type='location') |
|||
G.add_node(OLIVINE_CITY, node_type='location') |
|||
G.add_node(CIANWOOD_CITY, node_type='location') |
|||
G.add_node(MAHOGANY_TOWN, node_type='location') |
|||
G.add_node(LAKE_OF_RAGE, node_type='location') |
|||
G.add_node(TEAM_ROCKET_HQ, node_type='location') |
|||
G.add_node(ICE_PATH, node_type='location') |
|||
G.add_node(BLACKTHORN_CITY, node_type='location') |
|||
G.add_node(MT_MORTAR, node_type='location') |
|||
G.add_node(TIN_TOWER, node_type='location') |
|||
G.add_node(WHIRL_ISLANDS, node_type='location') |
|||
G.add_node(DARK_CAVE, node_type='location') |
|||
G.add_node(VICTORY_ROAD, node_type='location') |
|||
G.add_node(INDIGO_PLATEAU, node_type='location') |
|||
G.add_node(SS_AQUA, node_type='location') |
|||
G.add_node(VERMILION_CITY, node_type='location') |
|||
G.add_node(SAFFRON_CITY, node_type='location') |
|||
G.add_node(LAVENDER_TOWN, node_type='location') |
|||
G.add_node(ROCK_TUNNEL, node_type='location') |
|||
G.add_node(CERULEAN_CITY, node_type='location') |
|||
G.add_node(CELADON_CITY, node_type='location') |
|||
G.add_node(FUCHSIA_CITY, node_type='location') |
|||
G.add_node(DIGLETTS_CAVE, node_type='location') |
|||
G.add_node(PEWTER_CITY, node_type='location') |
|||
G.add_node(MT_MOON, node_type='location') |
|||
G.add_node(VIRIDIAN_CITY, node_type='location') |
|||
G.add_node(PALLET_TOWN, node_type='location') |
|||
G.add_node(CINNABAR_ISLAND, node_type='location') |
|||
G.add_node(MT_SILVER, node_type='location') |
|||
G.add_node(SAFARI_ZONE, node_type='location') |
|||
G.add_node(TOHJO_FALLS, node_type='location') |
|||
G.add_node(POWER_PLANT, node_type='location') |
|||
|
|||
G.add_edge(NEW_BARK_TOWN, 'Route 29', condition=None) |
|||
G.add_edge(CHERRYGROVE_CITY, 'Route 29', condition=None) |
|||
G.add_edge(CHERRYGROVE_CITY, 'Route 30', condition=None) |
|||
G.add_edge('Route 31', 'Route 30', condition=None) |
|||
G.add_edge('Route 30', DARK_CAVE, condition=None) |
|||
G.add_edge('Route 31', VIOLET_CITY, condition=None) |
|||
G.add_edge(VIOLET_CITY, 'Route 32', condition=None) |
|||
G.add_edge('Route 32', RUINS_OF_ALPH, condition=None) |
|||
G.add_edge('Route 32', UNION_CAVE, condition=None) |
|||
G.add_edge(UNION_CAVE, 'Route 33', condition=None) |
|||
G.add_edge(UNION_CAVE, RUINS_OF_ALPH, condition=None) |
|||
G.add_edge('Route 33', AZALEA_TOWN, condition=None) |
|||
G.add_edge(AZALEA_TOWN, ILEX_FOREST, condition=None) |
|||
G.add_edge(ILEX_FOREST, 'Route 34', condition=None) |
|||
G.add_edge(GOLDENROD_CITY, 'Route 34', condition=None) |
|||
G.add_edge(GOLDENROD_CITY, 'Route 35', condition=None) |
|||
G.add_edge(NATIONAL_PARK, 'Route 35', condition=None) |
|||
G.add_edge(NATIONAL_PARK, 'Route 36', condition=[SQUIRTBOTTLE]) |
|||
G.add_edge(VIOLET_CITY, 'Route 36', condition=None) |
|||
G.add_edge('Route 37', 'Route 36', condition=[SQUIRTBOTTLE]) |
|||
G.add_edge('Route 37', ECRUTEAK_CITY, condition=None) |
|||
G.add_edge('Route 38', ECRUTEAK_CITY, condition=None) |
|||
G.add_edge('Route 38', 'Route 39', condition=None) |
|||
G.add_edge('Route 39', OLIVINE_CITY, condition=None) |
|||
G.add_edge('Route 40', OLIVINE_CITY, condition=[SURF]) |
|||
G.add_edge(OLIVINE_CITY, SS_AQUA, condition=[S_S_TICKET]) |
|||
G.add_edge('Route 40', 'Route 41', condition=[SURF]) |
|||
G.add_edge('Route 40', WHIRL_ISLANDS, condition=[SURF, WHIRLPOOL]) |
|||
G.add_edge('Route 41', WHIRL_ISLANDS, condition=[SURF, WHIRLPOOL]) |
|||
G.add_edge('Route 41', CIANWOOD_CITY, condition=[SURF]) |
|||
G.add_edge('Route 47', CIANWOOD_CITY, condition=None) |
|||
G.add_edge('Route 47', 'Route 48', condition=None) |
|||
G.add_edge('Route 47', SAFARI_ZONE, condition=None) |
|||
G.add_edge('Route 42', ECRUTEAK_CITY, condition=None) |
|||
G.add_edge('Route 42', MT_MORTAR, condition=[SURF, WATERFALL]) |
|||
G.add_edge('Route 42', MAHOGANY_TOWN, condition=[SURF]) |
|||
G.add_edge('Route 43', MAHOGANY_TOWN, condition=None) |
|||
G.add_edge('Route 43', LAKE_OF_RAGE, condition=None) |
|||
G.add_edge('Route 44', MAHOGANY_TOWN, condition=[ROCKET_DEAFEATED]) |
|||
G.add_edge(TEAM_ROCKET_HQ, MAHOGANY_TOWN, condition=[CATCH_RED_GYRADOS]) |
|||
G.add_edge('Route 44', ICE_PATH, condition=[STRENGTH]) |
|||
G.add_edge(BLACKTHORN_CITY, ICE_PATH, condition=[STRENGTH]) |
|||
G.add_edge('Route 45', BLACKTHORN_CITY, condition=None) |
|||
G.add_edge('Route 45', DARK_CAVE, condition=[SURF]) |
|||
G.add_edge('Route 45', 'Route 46', condition=None) |
|||
G.add_edge('Route 46', 'Route 29', condition=None) |
|||
G.add_edge('Route 46', DARK_CAVE, condition=[ROCK_SMASH]) |
|||
G.add_edge('Route 27', NEW_BARK_TOWN, condition=[SURF, WATERFALL, WHIRLPOOL]) |
|||
G.add_edge('Route 26', 'Route 27', condition=None) |
|||
|
|||
G.add_edge(LEAGUE_RECEPTION_GATE, 'Route 26', condition=None) |
|||
G.add_edge(LEAGUE_RECEPTION_GATE, 'Route 28', condition=[ROUTE_28_UNLOCKED]) |
|||
G.add_edge(LEAGUE_RECEPTION_GATE, 'Route 22', condition=[WOKE_SNORLAX]) |
|||
G.add_edge(LEAGUE_RECEPTION_GATE, 'Route 23', condition=None) |
|||
|
|||
G.add_edge('Route 28', MT_SILVER, condition=None) |
|||
G.add_edge('Route 23', VICTORY_ROAD, condition=[ZEPHYR_BADGE, HIVE_BADGE, PLAIN_BADGE, FOG_BADGE, STORM_BADGE, MINERAL_BADGE, GLACIER_BADGE, RISING_BADGE]) |
|||
|
|||
G.add_edge(SS_AQUA, VERMILION_CITY, condition=None) |
|||
G.add_edge(SAFFRON_CITY, GOLDENROD_CITY, condition=[POWER_RESTORED, RAIL_PASS]) |
|||
G.add_edge(DIGLETTS_CAVE, 'Route 11', condition=[WOKE_SNORLAX]) |
|||
|
|||
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=None) |
|||
G.add_edge(SAFFRON_CITY, 'Route 6', condition=None) |
|||
G.add_edge(SAFFRON_CITY, 'Route 7', condition=None) |
|||
G.add_edge(SAFFRON_CITY, 'Route 8', condition=None) |
|||
G.add_edge('Route 6', VERMILION_CITY, condition=None) |
|||
G.add_edge(VERMILION_CITY, 'Route 11', condition=None) |
|||
G.add_edge('Route 11', 'Route 12', condition=None) |
|||
G.add_edge('Route 11', DIGLETTS_CAVE, condition=None) |
|||
G.add_edge('Route 2', DIGLETTS_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=None) |
|||
G.add_edge('Route 17', 'Route 18', condition=None) |
|||
G.add_edge('Route 18', FUCHSIA_CITY, condition=None) |
|||
G.add_edge(FUCHSIA_CITY,'Route 19', condition=None) |
|||
G.add_edge(FUCHSIA_CITY,'Route 15', 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(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', 'Route 25', 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.nodes[NEW_BARK_TOWN]['grants_conditions'] = [ |
|||
{'condition': S_S_TICKET, 'required_conditions': [JOHTO_CHAMPION]} |
|||
] |
|||
G.nodes[VIOLET_CITY]['grants_conditions'] = [ |
|||
{'condition': ZEPHYR_BADGE, 'required_conditions': []} |
|||
] |
|||
G.nodes[AZALEA_TOWN]['grants_conditions'] = [ |
|||
{'condition': HIVE_BADGE, 'required_conditions': []} |
|||
] |
|||
G.nodes[ILEX_FOREST]['grants_conditions'] = [ |
|||
{'condition': CUT, 'required_conditions': []} |
|||
] |
|||
G.nodes[GOLDENROD_CITY]['grants_conditions'] = [ |
|||
{'condition': PLAIN_BADGE, 'required_conditions': []}, |
|||
{'condition': SQUIRTBOTTLE, 'required_conditions': []}, |
|||
{'condition': PKMN_WING, 'required_conditions': [GLACIER_BADGE]}, |
|||
] |
|||
G.nodes[ECRUTEAK_CITY]['grants_conditions'] = [ |
|||
{'condition': SURF, 'required_conditions': []}, |
|||
{'condition': FOG_BADGE, 'required_conditions': []} |
|||
] |
|||
G.nodes['Route 36']['grants_conditions'] = [ |
|||
{'condition': ROCK_SMASH, 'required_conditions': [SQUIRTBOTTLE]} |
|||
] |
|||
G.nodes[OLIVINE_CITY]['grants_conditions'] = [ |
|||
{'condition': MINERAL_BADGE, 'required_conditions': [MEDICINE]}, |
|||
{'condition': STRENGTH, 'required_conditions': []}, |
|||
] |
|||
G.nodes[CIANWOOD_CITY]['grants_conditions'] = [ |
|||
{'condition': STORM_BADGE, 'required_conditions': []}, |
|||
{'condition': MEDICINE, 'required_conditions': []}, |
|||
{'condition': FLY, 'required_conditions': [STORM_BADGE]}, |
|||
{'condition': FLY_OUT_OF_BATTLE, 'required_conditions': [STORM_BADGE]}, |
|||
] |
|||
G.nodes[MAHOGANY_TOWN]['grants_conditions'] = [ |
|||
{'condition': GLACIER_BADGE, 'required_conditions': [ROCKET_DEAFEATED]} |
|||
] |
|||
G.nodes[TEAM_ROCKET_HQ]['grants_conditions'] = [ |
|||
{'condition': ROCKET_DEAFEATED, 'required_conditions': []}, |
|||
{'condition': WHIRLPOOL, 'required_conditions': []} |
|||
] |
|||
G.nodes[LAKE_OF_RAGE]['grants_conditions'] = [ |
|||
{'condition': CATCH_RED_GYRADOS, 'required_conditions': []} |
|||
] |
|||
G.nodes[ICE_PATH]['grants_conditions'] = [ |
|||
{'condition': WATERFALL, 'required_conditions': []} |
|||
] |
|||
G.nodes[BLACKTHORN_CITY]['grants_conditions'] = [ |
|||
{'condition': RISING_BADGE, 'required_conditions': []} |
|||
] |
|||
G.nodes[INDIGO_PLATEAU]['grants_conditions'] = [ |
|||
{'condition': JOHTO_CHAMPION, 'required_conditions': []} |
|||
] |
|||
G.nodes[VERMILION_CITY]['grants_conditions'] = [ |
|||
{'condition': THUNDER_BADGE, 'required_conditions': []}, |
|||
{'condition': FLUTE_CHANNEL, 'required_conditions': [EXPN_CARD]}, |
|||
{'condition': CLEFAIRY_DOLL, 'required_conditions': [POWER_RESTORED]}, |
|||
] |
|||
G.nodes[SAFFRON_CITY]['grants_conditions'] = [ |
|||
{'condition': MARSH_BADGE, 'required_conditions': []}, |
|||
{'condition': RAIL_PASS, 'required_conditions': [CLEFAIRY_DOLL]}, |
|||
] |
|||
G.nodes[LAVENDER_TOWN]['grants_conditions'] = [ |
|||
{'condition': EXPN_CARD, 'required_conditions': [POWER_RESTORED]} |
|||
] |
|||
G.nodes[POWER_PLANT]['grants_conditions'] = [ |
|||
{'condition': POWER_PLANT_VISITED, 'required_conditions': []}, |
|||
{'condition': POWER_RESTORED, 'required_conditions': [MACHINE_PART]} |
|||
] |
|||
G.nodes[CERULEAN_CITY]['grants_conditions'] = [ |
|||
{'condition': CASCADE_BADGE, 'required_conditions': [MISTY_FOUND]}, |
|||
{'condition': MACHINE_PART, 'required_conditions': [POWER_PLANT_VISITED]} |
|||
] |
|||
G.nodes['Route 25']['grants_conditions'] = [ |
|||
{'condition': MISTY_FOUND, 'required_conditions': []} |
|||
] |
|||
G.nodes[CELADON_CITY]['grants_conditions'] = [ |
|||
{'condition': RAINBOW_BADGE, 'required_conditions': []} |
|||
] |
|||
G.nodes[FUCHSIA_CITY]['grants_conditions'] = [ |
|||
{'condition': SOUL_BADGE, 'required_conditions': []} |
|||
] |
|||
G.nodes['Route 11']['grants_conditions'] = [ |
|||
{'condition': WOKE_SNORLAX, 'required_conditions': [FLUTE_CHANNEL]} |
|||
] |
|||
G.nodes[PEWTER_CITY]['grants_conditions'] = [ |
|||
{'condition': BOULDER_BADGE, 'required_conditions': []}, |
|||
{'condition': PKMN_WING, 'required_conditions': []}, |
|||
] |
|||
G.nodes[VIRIDIAN_CITY]['grants_conditions'] = [ |
|||
{'condition': EARTH_BADGE, 'required_conditions': [VOLCANO_BADGE]}, |
|||
] |
|||
G.nodes[PALLET_TOWN]['grants_conditions'] = [ |
|||
{'condition': ROUTE_28_UNLOCKED, 'required_conditions': [BOULDER_BADGE, CASCADE_BADGE, THUNDER_BADGE, RAINBOW_BADGE, MARSH_BADGE, SOUL_BADGE, VOLCANO_BADGE, EARTH_BADGE]}, |
|||
] |
|||
G.nodes[CINNABAR_ISLAND]['grants_conditions'] = [ |
|||
{'condition': VOLCANO_BADGE, 'required_conditions': []}, |
|||
] |
|||
|
|||
return G |
|||
@ -0,0 +1,228 @@ |
|||
import networkx as nx |
|||
from networkx import Graph |
|||
|
|||
from Routes.pokemon_game_desc import PokemonGameDesc |
|||
|
|||
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' |
|||
FLY = 'Fly' |
|||
|
|||
FLY_OUT_OF_BATTLE = 'Fly out of battle' |
|||
|
|||
def get_red_blue_desc() -> PokemonGameDesc: |
|||
desc: PokemonGameDesc = PokemonGameDesc() |
|||
desc.graph = get_red_blue_route() |
|||
desc.game_name = "Red_Blue" |
|||
desc.towns_and_cities = [PALLET_TOWN, VIRIDIAN_CITY, PEWTER_CITY, CERULEAN_CITY, SAFFRON_CITY, CELADON_CITY, VERMILLION_CITY, FUCHSIA_CITY, CINNABAR_ISLAND] |
|||
desc.badges = [BOULDER_BADGE, CASCADE_BADGE, THUNDER_BADGE, RAINBOW_BADGE, MARSH_BADGE, SOUL_BADGE, VOLCANO_BADGE, EARTH_BADGE] |
|||
desc.hms = [CUT, SURF, FLASH, STRENGTH, FLY] |
|||
desc.starting_town = PALLET_TOWN |
|||
desc.end_goal = CERULEAN_CAVE |
|||
|
|||
return desc |
|||
|
|||
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.nodes['Route 16']['grants_conditions'] = [ |
|||
{'condition': FLY, '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]}, |
|||
{'condition': FLY_OUT_OF_BATTLE, '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,0 +1,152 @@ |
|||
import heapq |
|||
import networkx as nx |
|||
from typing import List, Set |
|||
|
|||
FLY_OUT_OF_BATTLE = 'Fly out of battle' |
|||
|
|||
class State: |
|||
def __init__(self, location, conditions, cost, path, visited_required_nodes): |
|||
self.location = location |
|||
self.conditions = conditions # A frozenset of conditions |
|||
self.cost = cost |
|||
self.path = path # List of locations visited in order |
|||
self.visited_required_nodes = visited_required_nodes # A frozenset of required nodes visited |
|||
|
|||
def __lt__(self, other): |
|||
return self.cost < other.cost # For priority queue |
|||
|
|||
def heuristic(state, goal_conditions, required_nodes): |
|||
# Since we don't have actual distances, we can use the number of badges remaining as the heuristic |
|||
remaining_conditions = goal_conditions - state.conditions |
|||
remaining_nodes = required_nodes - state.visited_required_nodes |
|||
return len(remaining_conditions) + len(remaining_nodes) |
|||
|
|||
def is_goal_state(state, goal_location, goals, required_nodes): |
|||
return ( |
|||
state.location == goal_location and |
|||
goals.issubset(state.conditions) and |
|||
required_nodes.issubset(state.visited_required_nodes) |
|||
) |
|||
|
|||
class PokemonGameDesc: |
|||
def __init__(self): |
|||
self.game_name: str = "" |
|||
self.towns_and_cities: Set[str] = set() |
|||
self.badges: Set[str] = set() |
|||
self.items: Set[str] = set() |
|||
self.hms: Set[str] = set() |
|||
self.starting_town: str |
|||
self.end_goal: str |
|||
self.flying_badge: str |
|||
self.additional_goals: List[str] = [] |
|||
self.one_way_routes: List[str] = [] |
|||
self.must_visit: Set[str] = set() |
|||
self.graph: nx.Graph = nx.Graph() |
|||
|
|||
def astar_search(self): |
|||
from collections import deque |
|||
|
|||
self.goals = set(self.badges + self.additional_goals) |
|||
|
|||
# Priority queue for open states |
|||
open_list = [] |
|||
heapq.heappush(open_list, (0, State( |
|||
location=self.starting_town, |
|||
conditions=frozenset(), # Start with no conditions |
|||
cost=0, |
|||
path=[self.starting_town], |
|||
visited_required_nodes=frozenset([self.starting_town]) if self.starting_town in self.must_visit else frozenset() |
|||
))) |
|||
|
|||
# Closed set to keep track of visited states |
|||
closed_set = {} |
|||
|
|||
while open_list: |
|||
_, current_state = heapq.heappop(open_list) |
|||
|
|||
# Check if we've reached the goal location with all required conditions |
|||
if is_goal_state(current_state, self.end_goal, self.goals, self.must_visit): |
|||
return current_state.path, current_state.cost, current_state.conditions |
|||
|
|||
# Check if we've already visited this state with equal or better conditions |
|||
state_key = (current_state.location, current_state.conditions, current_state.visited_required_nodes) |
|||
if state_key in closed_set and closed_set[state_key] <= current_state.cost: |
|||
continue # Skip this state |
|||
|
|||
closed_set[state_key] = current_state.cost |
|||
|
|||
# Expand neighbors via normal moves |
|||
for neighbor in self.graph.neighbors(current_state.location): |
|||
edge_data = self.graph.get_edge_data(current_state.location, neighbor) |
|||
edge_condition = edge_data.get('condition', []) |
|||
|
|||
if edge_condition is None: |
|||
edge_requires = set() |
|||
else: |
|||
edge_requires = set(edge_condition) |
|||
|
|||
# Check if we have the required conditions to traverse this edge |
|||
if not edge_requires.issubset(current_state.conditions): |
|||
continue # Can't traverse this edge |
|||
|
|||
# Update conditions based on grants at the neighbor node |
|||
neighbor_data = self.graph.nodes[neighbor] |
|||
new_conditions = set(current_state.conditions) |
|||
|
|||
# Check if the neighbor grants any conditions |
|||
grants = neighbor_data.get('grants_conditions', []) |
|||
for grant in grants: |
|||
required_for_grant = set(grant.get('required_conditions', [])) |
|||
if required_for_grant.issubset(new_conditions): |
|||
# We can acquire the condition |
|||
new_conditions.add(grant['condition']) |
|||
|
|||
# Update visited required nodes |
|||
new_visited_required_nodes = set(current_state.visited_required_nodes) |
|||
if neighbor in self.must_visit: |
|||
new_visited_required_nodes.add(neighbor) |
|||
|
|||
new_state = State( |
|||
location=neighbor, |
|||
conditions=frozenset(new_conditions), |
|||
cost=current_state.cost + 1, # Assuming uniform cost; adjust if needed |
|||
path=current_state.path + [neighbor], |
|||
visited_required_nodes=frozenset(new_visited_required_nodes) |
|||
) |
|||
|
|||
estimated_total_cost = new_state.cost + heuristic(new_state, self.goals, self.must_visit) |
|||
|
|||
heapq.heappush(open_list, (estimated_total_cost, new_state)) |
|||
|
|||
# Expand neighbors via FLY if applicable |
|||
if FLY_OUT_OF_BATTLE in current_state.conditions and current_state.location in self.towns_and_cities: |
|||
for fly_target in self.towns_and_cities: |
|||
if fly_target != current_state.location and fly_target in current_state.path: |
|||
# You can fly to this location |
|||
new_conditions = set(current_state.conditions) |
|||
neighbor_data = self.graph.nodes[fly_target] |
|||
grants = neighbor_data.get('grants_conditions', []) |
|||
for grant in grants: |
|||
required_for_grant = set(grant.get('required_conditions', [])) |
|||
if required_for_grant.issubset(new_conditions): |
|||
new_conditions.add(grant['condition']) |
|||
|
|||
# Update visited required nodes |
|||
new_visited_required_nodes = set(current_state.visited_required_nodes) |
|||
if fly_target in self.must_visit: |
|||
new_visited_required_nodes.add(fly_target) |
|||
|
|||
fly_state = State( |
|||
location=fly_target, |
|||
conditions=frozenset(new_conditions), |
|||
cost=current_state.cost + 1, # Adjust cost if flying is different |
|||
path=current_state.path + [fly_target], |
|||
visited_required_nodes=frozenset(new_visited_required_nodes) |
|||
) |
|||
estimated_total_cost = fly_state.cost + heuristic(fly_state, self.goals, self.must_visit) |
|||
heapq.heappush(open_list, (estimated_total_cost, fly_state)) |
|||
|
|||
return None # No path found |
|||
|
|||
|
|||
__all__ = ["PokemonGameDesc"] |
|||
@ -0,0 +1,176 @@ |
|||
|
|||
|
|||
from Routes.pokemon_game_desc import PokemonGameDesc |
|||
|
|||
|
|||
def format_name(name): |
|||
return name.replace(' ', '_').replace('.', '').replace("'", '') |
|||
|
|||
def generate_pddl_domain(): |
|||
# Define the types, predicates, and action as shown above |
|||
domain_pddl = """ |
|||
(define (domain pokemon) |
|||
(:requirements :strips :typing :equality :quantified-preconditions :conditional-effects :negative-preconditions) |
|||
(:types |
|||
location |
|||
condition |
|||
) |
|||
(:predicates |
|||
(at ?loc - location) |
|||
(connected ?from ?to - location) |
|||
(has ?cond - condition) |
|||
(grants ?loc - location ?cond - condition) |
|||
(requires ?from ?to - location ?cond - condition) |
|||
(requires_grant ?loc - location ?cond - condition ?req - condition) |
|||
(visited ?loc - location) |
|||
(is_town_or_city ?loc - location) |
|||
) |
|||
(:action move |
|||
:parameters (?from ?to - location) |
|||
:precondition (and |
|||
(at ?from) |
|||
(connected ?from ?to) |
|||
; Remove (not (visited ?to)) if re-visiting is allowed |
|||
; Universal preconditions for required conditions |
|||
(forall (?cond - condition) |
|||
(imply (requires ?from ?to ?cond) (has ?cond)) |
|||
) |
|||
) |
|||
:effect (and |
|||
(at ?to) |
|||
(not (at ?from)) |
|||
(visited ?to) |
|||
) |
|||
) |
|||
(:action acquire |
|||
:parameters (?loc - location ?cond - condition) |
|||
:precondition (and |
|||
(at ?loc) |
|||
(grants ?loc ?cond) |
|||
(not (has ?cond)) |
|||
; Universal preconditions for required grants |
|||
(forall (?req - condition) |
|||
(imply (requires_grant ?loc ?cond ?req) (has ?req)) |
|||
) |
|||
) |
|||
:effect (and |
|||
(has ?cond) |
|||
) |
|||
) |
|||
(:action fly |
|||
:parameters (?from ?to - location) |
|||
:precondition (and |
|||
(at ?from) |
|||
(has Fly) |
|||
(has Fly_out_of_battle) |
|||
(visited ?to) |
|||
(is_town_or_city ?to) |
|||
(not (at ?to)) ; Prevents flying to the current location |
|||
) |
|||
:effect (and |
|||
(at ?to) |
|||
(not (at ?from)) |
|||
) |
|||
) |
|||
) |
|||
""" |
|||
with open('pokemon_domain.pddl', 'w') as f: |
|||
f.write(domain_pddl) |
|||
|
|||
def generate_pddl_problem(desc: PokemonGameDesc): |
|||
# Extract objects, init, and goal |
|||
locations = set() |
|||
conditions = set() |
|||
connections = [] |
|||
grants = [] |
|||
requirements = [] |
|||
requires_grant = [] |
|||
|
|||
# Gather conditions from node grants and edge requirements |
|||
for node, attrs in desc.graph.nodes(data=True): |
|||
node_formatted = format_name(node) |
|||
locations.add(node_formatted) |
|||
grants_conditions = attrs.get('grants_conditions', []) |
|||
for grant in grants_conditions: |
|||
condition = format_name(grant['condition']) |
|||
conditions.add(condition) |
|||
grants.append((node_formatted, condition)) |
|||
required_conditions = grant.get('required_conditions', []) |
|||
for req in required_conditions: |
|||
req_condition = format_name(req) |
|||
conditions.add(req_condition) |
|||
requires_grant.append((node_formatted, condition, req_condition)) |
|||
|
|||
for u, v, attrs in desc.graph.edges(data=True): |
|||
u_formatted = format_name(u) |
|||
v_formatted = format_name(v) |
|||
locations.update([u_formatted, v_formatted]) |
|||
# Add both directions for bidirectional movement |
|||
if f'{u_formatted} -> {v_formatted}' not in desc.one_way_routes: |
|||
connections.append((u_formatted, v_formatted)) |
|||
if f'{v_formatted} -> {u_formatted}' not in desc.one_way_routes: |
|||
connections.append((v_formatted, u_formatted)) # Add reverse connection |
|||
|
|||
edge_condition = attrs.get('condition') |
|||
if edge_condition: |
|||
if isinstance(edge_condition, list): |
|||
for cond in edge_condition: |
|||
cond_formatted = format_name(cond) |
|||
conditions.add(cond_formatted) |
|||
requirements.append((u_formatted, v_formatted, cond_formatted)) |
|||
requirements.append((v_formatted, u_formatted, cond_formatted)) # Reverse |
|||
else: |
|||
cond_formatted = format_name(edge_condition) |
|||
conditions.add(cond_formatted) |
|||
requirements.append((u_formatted, v_formatted, cond_formatted)) |
|||
requirements.append((v_formatted, u_formatted, cond_formatted)) # Reverse |
|||
|
|||
conditions.add(format_name('Fly')) |
|||
conditions.add(format_name('Fly out of battle')) |
|||
|
|||
formatted_towns_and_cities = [format_name(town) for town in desc.towns_and_cities] |
|||
|
|||
# Prepare the PDDL problem file content |
|||
problem_pddl = "(define (problem pokemon_problem)\n" |
|||
problem_pddl += " (:domain pokemon)\n" |
|||
|
|||
# Objects |
|||
problem_pddl += " (:objects\n" |
|||
problem_pddl += " " + " ".join(sorted(locations)) + " - location\n" |
|||
problem_pddl += " " + " ".join(sorted(conditions)) + " - condition\n" |
|||
problem_pddl += " )\n" |
|||
|
|||
# Initial state |
|||
problem_pddl += " (:init\n" |
|||
problem_pddl += f" (at {format_name(desc.starting_town)})\n" |
|||
for u, v in connections: |
|||
problem_pddl += f" (connected {u} {v})\n" |
|||
for loc, cond in grants: |
|||
problem_pddl += f" (grants {loc} {cond})\n" |
|||
for u, v, cond in requirements: |
|||
problem_pddl += f" (requires {u} {v} {cond})\n" |
|||
for loc, cond, req in requires_grant: |
|||
problem_pddl += f" (requires_grant {loc} {cond} {req})\n" |
|||
for town in formatted_towns_and_cities: |
|||
problem_pddl += f" (is_town_or_city {town})\n" |
|||
problem_pddl += " )\n" |
|||
|
|||
# Goal state |
|||
badges = desc.badges |
|||
additional_conditions = desc.additional_goals |
|||
visited = desc.must_visit |
|||
problem_pddl += " (:goal\n" |
|||
problem_pddl += " (and\n" |
|||
problem_pddl += f" (at {format_name(desc.end_goal)})\n" |
|||
for badge in badges: |
|||
problem_pddl += f" (has {format_name(badge)})\n" |
|||
for cond in additional_conditions: |
|||
problem_pddl += f" (has {format_name(cond)})\n" |
|||
for location in visited: |
|||
problem_pddl += f" (visited {format_name(location)})\n" |
|||
problem_pddl += " )\n" |
|||
problem_pddl += " )\n" |
|||
problem_pddl += ")\n" |
|||
|
|||
with open(f'pokemon_problem_{desc.game_name}.pddl', 'w') as f: |
|||
f.write(problem_pddl) |
|||
@ -0,0 +1,193 @@ |
|||
import networkx as nx |
|||
from networkx import Graph |
|||
from pyvis.network import Network |
|||
import heapq |
|||
from copy import deepcopy |
|||
|
|||
from Routes.Gold_Silver_Route import CATCH_RED_GYRADOS, FOG_BADGE, GLACIER_BADGE, HIVE_BADGE, JOHTO_CHAMPION, MEDICINE, MINERAL_BADGE, NEW_BARK_TOWN, PLAIN_BADGE, RISING_BADGE, ROCK_SMASH, ROCKET_DEAFEATED, SS_AQUA, ZEPHYR_BADGE, get_gold_silver_desc, get_gold_silver_route |
|||
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_desc, get_red_blue_route |
|||
from convert_to_pddl import generate_pddl_domain, generate_pddl_problem |
|||
|
|||
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, 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() |
|||
|
|||
# Extract goal type and target |
|||
goal_type, target = goal |
|||
|
|||
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_type == "condition" and target 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 |
|||
elif goal_type == "node" and current_node == target: |
|||
# 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 = [ |
|||
("condition", BOULDER_BADGE), |
|||
("condition", CASCADE_BADGE), |
|||
("condition", SS_ANNE_TICKET), |
|||
("condition", CUT), |
|||
("condition", THUNDER_BADGE), |
|||
("condition", FLASH), |
|||
("condition", SILPH_SCOPE), |
|||
("condition", RAINBOW_BADGE), |
|||
("condition", QUENCHED_THURST), |
|||
("condition", POKE_FLUTE), |
|||
("condition", GIOVANNI_FIGHT), |
|||
("condition", MARSH_BADGE), |
|||
("condition", SOUL_BADGE), |
|||
("condition", VOLCANO_BADGE), |
|||
("condition", ARCTICUNO), |
|||
("condition", ZAPDOS), |
|||
("condition", MOLTRES), |
|||
("condition", CHAMPION), |
|||
("condition", 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.") |
|||
|
|||
G = get_gold_silver_route() |
|||
|
|||
goals = [ |
|||
("condition",ZEPHYR_BADGE), |
|||
("condition",HIVE_BADGE), |
|||
("condition",CUT), |
|||
("condition",PLAIN_BADGE), |
|||
("condition",FOG_BADGE), |
|||
("condition",ROCK_SMASH), |
|||
("condition",MEDICINE), |
|||
("condition",MINERAL_BADGE), |
|||
("condition",CATCH_RED_GYRADOS), |
|||
("condition",ROCKET_DEAFEATED), |
|||
("condition",GLACIER_BADGE), |
|||
("condition",RISING_BADGE), |
|||
("condition",JOHTO_CHAMPION), |
|||
("node",SS_AQUA) |
|||
] |
|||
|
|||
optimal_path = find_optimal_path_with_goals(G, NEW_BARK_TOWN, SS_AQUA, goals) |
|||
|
|||
if optimal_path: |
|||
print("Optimal Path:", " -> ".join(optimal_path)) |
|||
else: |
|||
print("No path found to fulfill all goals.") |
|||
""" |
|||
|
|||
generate_pddl_domain() |
|||
red_blue = get_red_blue_desc() |
|||
gold_silver = get_gold_silver_desc() |
|||
|
|||
path, _, _ = red_blue.astar_search() |
|||
print(path) |
|||
path, _, _ = gold_silver.astar_search() |
|||
print(path) |
|||
|
|||
#generate_pddl_problem(red_blue) |
|||
#generate_pddl_problem(gold_silver) |
|||
Loading…
Reference in new issue