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.
212 lines
7.1 KiB
212 lines
7.1 KiB
import json
|
|
import re
|
|
import sys
|
|
from PyQt6.QtCore import QObject, pyqtSignal, QRunnable
|
|
import subprocess
|
|
import os
|
|
from db import db
|
|
|
|
from routes.pokemon_game_desc import PokemonGameDesc
|
|
from utility.convert_to_pddl import format_name, generate_pddl_problem
|
|
|
|
class SolvePDDLsWorkerSignals(QObject):
|
|
finished = pyqtSignal(list)
|
|
|
|
class SolvePDDLsWorker(QRunnable):
|
|
def __init__(self, data: PokemonGameDesc):
|
|
super().__init__()
|
|
self.signals = SolvePDDLsWorkerSignals()
|
|
self.data = data
|
|
|
|
def run(self):
|
|
try:
|
|
gathered_data = self.solve_PDDL(self.data)
|
|
self.signals.finished.emit(gathered_data)
|
|
except Exception as e:
|
|
print(f"Error gathering Pokémon home storage status: {e}")
|
|
|
|
def solve_PDDL(self, data: PokemonGameDesc, game_name: str = ""):
|
|
if game_name == "":
|
|
game_name = "Crystal"
|
|
|
|
route, _, _ = data.astar_search()
|
|
|
|
locations = set(route)
|
|
|
|
print("Unique locations visisted: ", locations)
|
|
|
|
output_file = "./temp/plan.json"
|
|
plan = {}
|
|
with open(output_file, 'r', encoding='utf-8') as f:
|
|
plan = json.load(f)
|
|
|
|
target = None
|
|
for game in plan:
|
|
if game["game_name"] == game_name:
|
|
target = game
|
|
break
|
|
|
|
if not target:
|
|
return []
|
|
|
|
# gather up all the pokemon needed for say crystal and find all the encounter routes/locations
|
|
needed_locations = set()
|
|
|
|
game_info = db.get_game_id_by_name(game_name)
|
|
|
|
for key in target["pokemon"]:
|
|
catch_stats = target["pokemon"][key]
|
|
rep = catch_stats["representative"]
|
|
rand = db.get_encounters(rep, "random")
|
|
static = db.get_encounters(rep, "static")
|
|
encounters = []
|
|
encounters.extend(rand)
|
|
encounters.extend(static)
|
|
|
|
for encounter in encounters:
|
|
if encounter["game_id"] != game_info["id"]:
|
|
continue
|
|
|
|
encounter_data = json.loads(encounter["data"])
|
|
needed_locations.add(encounter_data["location"].replace("*", ""))
|
|
|
|
# compare those to all the ones we visit in the generated route
|
|
missing_locations = needed_locations - locations
|
|
print("missing_locations:", missing_locations)
|
|
|
|
node_list = list(data.graph.nodes())
|
|
|
|
# add missing ones to the has_visited list and re-gen the problem, then run it again
|
|
nodes_to_visit = []
|
|
for loc in missing_locations:
|
|
if loc in node_list:
|
|
nodes_to_visit.append(loc)
|
|
|
|
print("Additional Nodes to Visit:", nodes_to_visit)
|
|
|
|
data.must_visit = data.must_visit | set(nodes_to_visit[0:2])
|
|
|
|
route, _, _ = data.astar_search()
|
|
|
|
ordered_dict = dict.fromkeys(route)
|
|
unique_list = list(ordered_dict)
|
|
|
|
return unique_list
|
|
|
|
def solve_PDDL_old(self, data: PokemonGameDesc, game_name: str = ""):
|
|
if game_name == "":
|
|
game_name = "Crystal"
|
|
|
|
plan_file_name = f'./{game_name.lower()}_sas_plan'
|
|
|
|
if os.path.exists(os.path.abspath(plan_file_name)) == False:
|
|
self.generate_sas_plan(data)
|
|
|
|
locations = set()
|
|
pattern = re.compile(r"\((?:move|fly)\s+(\w+)\s+(\w+)\)")
|
|
with open(plan_file_name, 'r') as f:
|
|
for line in f:
|
|
# Find all matches for move and fly actions
|
|
matches = pattern.findall(line)
|
|
for loc1, loc2 in matches:
|
|
# Add both locations to the set
|
|
locations.add(loc1)
|
|
locations.add(loc2)
|
|
|
|
print("Unique locations visisted: ", locations)
|
|
|
|
output_file = "./temp/plan.json"
|
|
plan = {}
|
|
with open(output_file, 'r', encoding='utf-8') as f:
|
|
plan = json.load(f)
|
|
|
|
target = None
|
|
for game in plan:
|
|
if game["game_name"] == game_name:
|
|
target = game
|
|
break
|
|
|
|
if not target:
|
|
return []
|
|
|
|
# gather up all the pokemon needed for say crystal and find all the encounter routes/locations
|
|
needed_locations = set()
|
|
|
|
game_info = db.get_game_id_by_name(game_name)
|
|
|
|
for key in target["pokemon"]:
|
|
catch_stats = target["pokemon"][key]
|
|
rep = catch_stats["representative"]
|
|
rand = db.get_encounters(rep, "random")
|
|
static = db.get_encounters(rep, "static")
|
|
encounters = []
|
|
encounters.extend(rand)
|
|
encounters.extend(static)
|
|
|
|
for encounter in encounters:
|
|
if encounter["game_id"] != game_info["id"]:
|
|
continue
|
|
|
|
encounter_data = json.loads(encounter["data"])
|
|
needed_locations.add(format_name(encounter_data["location"].replace("*", "")).lower())
|
|
|
|
# compare those to all the ones we visit in the generated route
|
|
missing_locations = needed_locations - locations
|
|
print("missing_locations:", missing_locations)
|
|
|
|
node_list = list(data.graph.nodes())
|
|
for i in range(len(node_list)):
|
|
node_list[i] = format_name(node_list[i])
|
|
|
|
# add missing ones to the has_visited list and re-gen the problem, then run it again
|
|
nodes_to_visit = []
|
|
for loc in missing_locations:
|
|
if loc in node_list:
|
|
nodes_to_visit.append(loc)
|
|
|
|
print("Additional Nodes to Visit:", nodes_to_visit)
|
|
|
|
data.has_visited.extend(nodes_to_visit)
|
|
|
|
generate_pddl_problem(data)
|
|
|
|
self.generate_sas_plan(data)
|
|
|
|
return []
|
|
|
|
def generate_sas_plan(self, data: PokemonGameDesc):
|
|
print("Starting fast-downward...")
|
|
try:
|
|
command_translate = [
|
|
'python',
|
|
os.path.abspath('./downward/builds/release/bin/translate/translate.py'),
|
|
os.path.abspath('./temp/pokemon_domain.pddl'),
|
|
os.path.abspath(f'./temp/{data.file_name}'),
|
|
'--sas-file',
|
|
'output.sas'
|
|
]
|
|
|
|
command_search = [
|
|
os.path.abspath('./downward/builds/release/bin/downward.exe'),
|
|
'--search',
|
|
'astar(hmax())',
|
|
'--internal-plan-file',
|
|
'sas_plan'
|
|
]
|
|
|
|
if os.path.exists(os.path.abspath('./output.sas')):
|
|
os.remove(os.path.abspath('./output.sas'))
|
|
|
|
if os.path.exists(os.path.abspath('./sas_plan')):
|
|
os.remove(os.path.abspath('./sas_plan'))
|
|
|
|
print("Command to be executed:", command_translate)
|
|
|
|
ret = subprocess.run(command_translate, check=True)
|
|
|
|
with open(f'./output.sas', 'r') as f:
|
|
print("Command to be executed:", command_translate)
|
|
ret = subprocess.run(command_search, check=True, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, stdin=f)
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"An error occurred: {e}")
|
|
print("fast-downward compelted")
|