import { onlineSolver, PddlExecutor } from "@unitn-asa/pddl-client";
import { generateDeliverooDomain, generateDeliverooProblem } from "./pddlTemplates.js";
import { MapStore } from "../models/mapStore.js";
import { ParcelsStore } from "../models/parcelsStore.js";
import { Me } from "../models/me.js";
import { ServerConfig } from "../models/serverConfig.js";
/**
*
* Builds a PddlExecutor instance with action handlers for MOVE, PICKUP, and DEPOSIT.
* @param {function} onMove - Function to call when MOVE action is executed.
* @param {function} onPickup - Function to call when PICKUP action is executed.
* @param {function} onDeposit - Function to call when DEPOSIT action is executed.
* @returns {PddlExecutor} - Configured PddlExecutor instance.
*
*/
function buildExecutor(onMove, onPickup, onDeposit) {
const executor = new PddlExecutor();
// 1) Handler for MOVE
// Signature: executor(agent, fromTile, toTile) <--- like in the PDDL domain
executor.addAction({
name: "MOVE", //we used move in the ppddl domain, but it wants MOVE here :/
// 3 params bacause the PDDL domain has 3 params
executor: (agent, fromTile, toTile) => {
// Example values:
// agent = "AGENT_0D4EA4"
// fromTile = "T_4_4"
// toTile = "T_5_4"
// extract numeric x/y from the destination tile string "T_5_4"
const [_, sx, sy] = toTile.split("_").map((v) => Number(v));
return onMove(sx, sy); // must return a Promise
},
});
// 2) Handler for PICKUP
// Signature: executor(agent, parcel, atTile)
executor.addAction({
name: "PICKUP",
// 3 params cuz the PDDL domain has 3 params
executor: (agent, parcel, atTile) => {
// Example values:
// agent = "AGENT_0D4EA4"
// parcel = "P13324"
// atTile = "T_0_6"
return onPickup(); // must return a Promise
},
});
// Handler for DEPOSIT
// Signature: executor(agent, parcel, base, atTile)
executor.addAction({
name: "DEPOSIT",
// 4 params cuz the PDDL domain has 4 params
executor: (agent, parcel, base, atTile) => {
// Example values:
// agent = "AGENT_0D4EA4"
// parcel = "P13324"
// base = "BASE_1_9"
// atTile = "T_1_9"
// Simply invoke onDeposit
return onDeposit(); // must return a Promise
},
});
return executor;
}
/**
*
* Generates a PDDL plan for the Deliveroo problem using the online solver.
* @param {MapStore} mapStore - The MapStore instance containing the current map state.
* @param {ParcelsStore} parcelsStore - The ParcelsStore instance containing the current parcels state.
* @param {Me} me - The current player instance.
* @param {ServerConfig} serverConfig - The server configuration instance.
* @returns {Promise<Array>} - A promise that resolves to the raw plan generated by the solver.
* @throws {Error} - Throws an error if the solver fails to generate a plan.
*
*/
export async function getPlan(mapStore, parcelsStore, me, serverConfig) {
const domainText = generateDeliverooDomain();
const problemText = generateDeliverooProblem(mapStore, parcelsStore, me, serverConfig);
const rawPlan = await onlineSolver(domainText, problemText);
return rawPlan;
}
/**
* Executes a PDDL plan using the provided action handlers.
* @param {Array} rawPlan - The raw plan generated by the PDDL solver.
* @param {function} onMove - Function to call when MOVE action is executed.
* @param {function} onPickup - Function to call when PICKUP action is executed.
* @param {function} onDeposit - Function to call when DEPOSIT action is executed.
* @returns {Promise<void>} - A promise that resolves when the plan execution is complete.
* @throws {Error} - Throws an error if the plan execution fails.
*/
export async function executePlan(rawPlan, onMove, onPickup, onDeposit) {
if (!Array.isArray(rawPlan) || rawPlan.length === 0) {
console.warn("executePlan: No actions to exec.");
return;
}
const pddlExecutor = buildExecutor(onMove, onPickup, onDeposit);
try {
await pddlExecutor.exec(rawPlan);
console.log("Plan execution completed successfully");
} catch (error) {
console.error("Error during plan execution:", error.message);
// Return a rejected promise instead of throwing an error to the main
return Promise.reject(error);
}
}