diff --git a/src/SCClassicalPlanning.Documentation/Pages/lab/GoalSpaceExplorer.razor b/src/SCClassicalPlanning.Documentation/Pages/lab/GoalSpaceExplorer.razor index 6dc91a8..f738f0f 100644 --- a/src/SCClassicalPlanning.Documentation/Pages/lab/GoalSpaceExplorer.razor +++ b/src/SCClassicalPlanning.Documentation/Pages/lab/GoalSpaceExplorer.razor @@ -1,69 +1,195 @@ @page "/lab/goal-space-explorer" -@using SCClassicalPlanning -@using SCClassicalPlanning.ExampleDomains.AsCode; +@using SCClassicalPlanning; +@using SCClassicalPlanning.ExampleDomains.AsPDDL; @using SCClassicalPlanning.Planning.StateAndGoalSpace; +@using SCClassicalPlanning.ProblemCreation; +@using System.ComponentModel.DataAnnotations; -

Goal Space Explorer - Blocks World

- -

- Yes, this is ugly and raw. - The author is more of a back-end guy, for now. - Will likely improve on it gradually whenever the mood takes me. - Who knows, might even add some pretty graph visualisation stuff at some point. - Anyway, below is a list of all edges on the currently explored path from the end goal of the problem. - Explore an edge (adding it to the end of the current path) by clicking on the action to regress. - NB: so far, our treatment of goal spaces is not lifted - which can result in combinatorial explosion. And we don't yet prune unsatisifiable goals via invariants knowledge. - So goal space exploration isn't actually massively useful.. - It's interesting though, so there. - [Reset] -

- - + + if (parseError != null) + { + + } + else if (problem != null) + { +
    + @{ + RenderListItem(null, new GoalSpaceNode(problem, problem.Goal), path.First?.Value); + } + + @for (var n = path.First; n != null; n = n.Next) + { + RenderListItem(n, n.Value.To, n.Next?.Value); + } +
+ } +} @code { - private readonly LinkedList PathToCurrentNode = new(); + private static Dictionary> Presets = new() + { + ["[Empty]"] = () => new( + domainPddl: string.Empty, + problemPddl: string.Empty), + + ["Blocks World"] = () => new( + domainPddl: BlocksWorld.DomainPDDL, + problemPddl: BlocksWorld.ExampleProblemPDDL), + + ["Air Cargo"] = () => new( + domainPddl: AirCargo.DomainPDDL, + problemPddl: AirCargo.ExampleProblemPDDL), + }; - [Parameter] - public Problem Problem { get; set; } = BlocksWorld.ExampleProblem; + private FormData formData = Presets["Blocks World"].Invoke(); - public GoalSpaceNode RootNode => new(Problem, Problem.Goal); + private Exception? parseError = null; // TODO: should be done via form validation instead.. tidy me! + private Problem? problem = null; + private LinkedList path = new(); + + private void HandleFormSubmission(EditContext editContext) + { + try + { + problem = null; + parseError = null; + path.Clear(); + problem = PddlParser.ParseProblem(formData.ProblemPDDL, formData.DomainPDDL); + } + catch (Exception e) + { + parseError = e; + } + } - public void ExploreEdge(GoalSpaceEdge priorEdge, GoalSpaceEdge edge) + private void ExploreEdge(LinkedListNode? lastPathNode, GoalSpaceEdge edge) { - var currentLLNode = PathToCurrentNode.Find(priorEdge); - if (currentLLNode != null) + if (lastPathNode != null) { - while (currentLLNode.Next != null) + // huh, weird - i thought .net linked lists could just be chopped. + // turns out we have to remove nodes one at a time. + while (lastPathNode.Next != null) { - PathToCurrentNode.Remove(currentLLNode.Next); + path.Remove(lastPathNode.Next); } } + else + { + path.Clear(); + } + + path.AddLast(edge); + } + + private class FormData + { + public FormData(string domainPddl, string problemPddl) + { + this.DomainPDDL = domainPddl; + this.ProblemPDDL = problemPddl; + } + + public string DomainPDDL { get; set; } - PathToCurrentNode.AddLast(edge); + public string ProblemPDDL { get; set; } } }