From 68c60ea300ae4aaaa16c4cd9f8a992ea59166b1f Mon Sep 17 00:00:00 2001 From: Quildra Date: Wed, 27 Nov 2024 19:32:34 +0000 Subject: [PATCH] - Add fly and make it more generic --- Routes/Red_Blue_Route.py | 24 ++++++++++++++++++++- Routes/pokemon_game_desc.py | 17 +++++++++++++++ convert_to_pddl.py | 42 ++++++++++++++++++++++++++++++------- red_blue_goal_path.py | 7 +++++-- 4 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 Routes/pokemon_game_desc.py diff --git a/Routes/Red_Blue_Route.py b/Routes/Red_Blue_Route.py index 763eb47..8cd7c7b 100644 --- a/Routes/Red_Blue_Route.py +++ b/Routes/Red_Blue_Route.py @@ -1,6 +1,8 @@ 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' @@ -52,6 +54,21 @@ 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() @@ -63,6 +80,10 @@ def get_red_blue_route() -> Graph: {'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'] = [ @@ -103,7 +124,8 @@ def get_red_blue_route() -> Graph: 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': 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'] = [ diff --git a/Routes/pokemon_game_desc.py b/Routes/pokemon_game_desc.py new file mode 100644 index 0000000..b62e345 --- /dev/null +++ b/Routes/pokemon_game_desc.py @@ -0,0 +1,17 @@ +import networkx as nx +from typing import List, Set + +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.graph: nx.Graph = nx.Graph() + +__all__ = ["PokemonGameDesc"] diff --git a/convert_to_pddl.py b/convert_to_pddl.py index 5b856f0..e25a58b 100644 --- a/convert_to_pddl.py +++ b/convert_to_pddl.py @@ -1,3 +1,8 @@ + + +from Routes.pokemon_game_desc import PokemonGameDesc + + def format_name(name): return name.replace(' ', '_').replace('.', '').replace("'", '') @@ -5,7 +10,7 @@ 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) + (:requirements :strips :typing :equality :quantified-preconditions :conditional-effects :negative-preconditions) (:types location condition @@ -18,6 +23,7 @@ def generate_pddl_domain(): (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) @@ -51,12 +57,27 @@ def generate_pddl_domain(): (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(G): +def generate_pddl_problem(desc: PokemonGameDesc): # Extract objects, init, and goal locations = set() conditions = set() @@ -66,7 +87,7 @@ def generate_pddl_problem(G): requires_grant = [] # Gather conditions from node grants and edge requirements - for node, attrs in G.nodes(data=True): + for node, attrs in desc.graph.nodes(data=True): node_formatted = format_name(node) locations.add(node_formatted) grants_conditions = attrs.get('grants_conditions', []) @@ -80,7 +101,7 @@ def generate_pddl_problem(G): conditions.add(req_condition) requires_grant.append((node_formatted, condition, req_condition)) - for u, v, attrs in G.edges(data=True): + 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]) @@ -102,6 +123,11 @@ def generate_pddl_problem(G): 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" @@ -114,7 +140,7 @@ def generate_pddl_problem(G): # Initial state problem_pddl += " (:init\n" - problem_pddl += f" (at {format_name('New Bark Town')})\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: @@ -123,13 +149,15 @@ def generate_pddl_problem(G): 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 = ['Zephyr Badge', 'Hive Badge', 'Plain Badge', 'Fog Badge', 'Storm Badge', 'Mineral Badge', 'Glacier Badge', 'Rising Badge'] + badges = desc.badges problem_pddl += " (:goal\n" problem_pddl += " (and\n" - problem_pddl += f" (at {format_name('Indigo Plateau')})\n" + problem_pddl += f" (at {format_name(desc.end_goal)})\n" for badge in badges: problem_pddl += f" (has {format_name(badge)})\n" problem_pddl += " )\n" diff --git a/red_blue_goal_path.py b/red_blue_goal_path.py index 21d0d86..ae03c5a 100644 --- a/red_blue_goal_path.py +++ b/red_blue_goal_path.py @@ -5,7 +5,7 @@ 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_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_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: @@ -180,4 +180,7 @@ if __name__ == "__main__": print("No path found to fulfill all goals.") generate_pddl_domain() - generate_pddl_problem(G) + + red_blue = get_red_blue_desc() + + generate_pddl_problem(red_blue)