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.
176 lines
6.6 KiB
176 lines
6.6 KiB
|
|
|
|
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)
|
|
|