Continuing a previous post on LinkedIn.
Example of ChatGPT implementation of HTN in C#.
I had to ask for it to complete the answer, which was truncated at first.
Prompts:
- "show a C# implementation of hierarchical task network"
- "the answer is incomplete"
Full response:
using System;
using System.Collections.Generic;
/*
* This code defines a domain in which the goal is to build a wall given some bricks and mortar.
* It also defines a set of tasks and methods that can be used to achieve this goal, and an HTN
* planner that uses these tasks and methods to find a plan to solve the problem.
*/
namespace HTNExample
{
// Define the domain and problem
class WorldState
{
public bool HasBrick { get; set; }
public bool HasMortar { get; set; }
public bool HasWall { get; set; }
}
class Problem
{
public WorldState InitialState { get; set; }
public WorldState GoalState { get; set; }
}
// Define the tasks and methods
abstract class Task
{
public abstract bool CanExecute(WorldState state);
public abstract void Execute(WorldState state);
}
class BuildWallTask : Task
{
public override bool CanExecute(WorldState state)
{
return state.HasBrick && state.HasMortar;
}
public override void Execute(WorldState state)
{
state.HasWall = true;
}
}
class GetBrickTask : Task
{
public override bool CanExecute(WorldState state)
{
return !state.HasBrick;
}
public override void Execute(WorldState state)
{
state.HasBrick = true;
}
}
class GetMortarTask : Task
{
public override bool CanExecute(WorldState state)
{
return !state.HasMortar;
}
public override void Execute(WorldState state)
{
state.HasMortar = true;
}
}
class Method : Task
{
public List<Task> Subtasks { get; set; }
public Method()
{
Subtasks = new List<Task>();
}
public override bool CanExecute(WorldState state)
{
foreach (var subtask in Subtasks)
{
if (!subtask.CanExecute(state))
{
return false;
}
}
return true;
}
public override void Execute(WorldState state)
{
foreach (var subtask in Subtasks)
{
subtask.Execute(state);
}
}
}
class GetBrickAndMortarMethod : Method
{
public GetBrickAndMortarMethod()
{
Subtasks.Add(new GetBrickTask());
Subtasks.Add(new GetMortarTask());
}
}
// Define the HTN planner
class HTNPlanner
{
public static List<Task> Plan(Problem problem)
{
var plan = new List<Task>();
var state = problem.InitialState;
while (!state.HasWall)
{
if (state.HasBrick && state.HasMortar)
{
plan.Add(new BuildWallTask());
}
else
{
plan.Add(new GetBrickAndMortarMethod());
}
state = problem.InitialState;
foreach (var task in plan)
{
task.Execute(state);
}
}
return plan;
}
}
// Test the HTN planner
class Program
{
static void Main(string[] args)
{
var problem = new Problem
{
InitialState = new WorldState { HasBrick = false, HasMortar = false, HasWall = false },
GoalState = new WorldState { HasBrick = true, HasMortar = true, HasWall = true }
};
var plan = HTNPlanner.Plan(problem);
foreach (var task in plan)
{
Console.WriteLine(task.GetType().Name);
}
}
}
}
I also asked for a second example, which I tampered with a bit, but the core answer remains:
using System;
using System.Collections.Generic;
/*
* A Hierarchical Task Network (HTN) is a planning representation that can be used to solve problems that
* involve tasks that have hierarchical structure and require ordering and decomposition. Here's one way
* you could implement an HTN in C#:
*
* Define the domain and problem: Start by defining the domain in which you want to solve problems
* using an HTN. This typically involves identifying the tasks that can be performed, the objects
* and concepts that are relevant to the domain, and the relationships between them. You should also
* define the problem you want to solve, which should include the initial state, the goal state, and the
* available actions that can be used to transform the initial state into the goal state.
*
* Implement the HTN planner: Next, you'll need to implement the HTN planner itself. This typically
* involves defining the HTN methods and operators that can be used to decompose high-level tasks
* into sequences of lower-level tasks. You'll also need to implement the planning algorithm that
* selects and executes these methods and operators in order to achieve the goal state.
*
* Test the HTN planner: Once you've implemented the HTN planner, you should test it to ensure that it's
* working correctly. This typically involves defining a set of test cases that cover a range of different
* domains and problems, and verifying that the planner is able to find a solution for each of these test cases.
*
* This example defines a domain with three locations (A, B, C), two object types (Ball, Box),
* and three tasks (GoToLocation, PickUpObject, PutDownObject). The HTN planner tries to find a plan to
* transform the initial state into the goal state by decomposing the GoToLocation task into subtasks.
*/
namespace HTNExample1 {
// Define the domain and problem
public class Domain {
public enum TaskType {
TransportObjectToLocation,
GoToLocation,
PickUpObject,
PutDownObject
}
public enum Location {
A,
B,
C
}
public enum ObjectType {
Ball,
Box
}
public class State {
public Location AgentLocation;
public Dictionary<ObjectType, Location> ObjectLocations;
public bool HasObject;
public ObjectType ObjectType;
}
public class Problem {
public State InitialState;
public State GoalState;
}
}
// Implement the HTN planner
public class HTNPlanner {
private Domain domain;
private Domain.Problem problem;
public List<Domain.TaskType> plan;
public HTNPlanner(Domain domain, Domain.Problem problem) {
this.domain = domain;
this.problem = problem;
this.plan = new List<Domain.TaskType>();
}
public bool Plan() {
// Check if the initial state is already the goal state
if (problem.InitialState.Equals(problem.GoalState)) {
return true;
}
// Define the top-level task and try to decompose it
Domain.TaskType topLevelTask = Domain.TaskType.TransportObjectToLocation;
return DecomposeTask(topLevelTask, problem.InitialState, problem.GoalState);
}
private bool DecomposeTask(Domain.TaskType task, Domain.State state, Domain.State goal) {
// Check if the given state is already the goal state
if (state.Equals(goal)) {
return true;
}
switch (task) {
case Domain.TaskType.TransportObjectToLocation:
// Decompose the GoToLocation task into subtasks
Domain.TaskType[] subtasks = {
Domain.TaskType.PickUpObject,
Domain.TaskType.GoToLocation,
Domain.TaskType.PutDownObject
};
foreach (Domain.TaskType subtask in subtasks) {
if (DecomposeTask(subtask, state, goal)) {
plan.Add(task);
return true;
}
}
break;
case Domain.TaskType.GoToLocation:
if (state.AgentLocation != goal.AgentLocation) {
state.AgentLocation = goal.AgentLocation;
return true;
}
else {
return false;
}
case Domain.TaskType.PickUpObject:
// Check if the agent can pick up the object in the current state
if (state.HasObject || state.ObjectLocations[state.ObjectType] != state.AgentLocation) {
return false;
}
// Update the state and add the task to the plan
state.HasObject = true;
plan.Add(task);
return true;
case Domain.TaskType.PutDownObject:
// Check if the agent has the object in the current state
if (!state.HasObject) {
return false;
}
// Update the state and add the task to the plan
// Update the state and add the task to the plan
state.HasObject = false;
state.ObjectLocations[state.ObjectType] = state.AgentLocation;
plan.Add(task);
return true;
default:
throw new ArgumentException("Invalid task type");
}
return false;
}
}
// Test the HTN planner
class Program
{
static void Main(string[] args)
{
// Define the domain
Domain domain = new Domain();
// Define the initial and goal states
Domain.State initialState = new Domain.State {
AgentLocation = Domain.Location.A,
ObjectLocations = new Dictionary<Domain.ObjectType, Domain.Location>
{
{ Domain.ObjectType.Ball, Domain.Location.A },
{ Domain.ObjectType.Box, Domain.Location.C }
},
HasObject = false,
ObjectType = Domain.ObjectType.Ball
};
Domain.State goalState = new Domain.State {
AgentLocation = Domain.Location.B,
ObjectLocations = new Dictionary<Domain.ObjectType, Domain.Location>
{
{ Domain.ObjectType.Ball, Domain.Location.B },
{ Domain.ObjectType.Box, Domain.Location.C }
},
HasObject = false,
ObjectType = Domain.ObjectType.Ball
};
Domain.Problem problem = new Domain.Problem {
InitialState = initialState,
GoalState = goalState
};
// Create an HTN planner and try to find a plan
HTNPlanner planner = new HTNPlanner(domain, problem);
if (planner.Plan()) {
Console.WriteLine("Found a plan:");
foreach (Domain.TaskType task in planner.plan) {
Console.WriteLine(task);
}
}
else {
Console.WriteLine("No plan found");
}
}
}
}
Top comments (0)