Git Product home page Git Product logo

planningai's Introduction

PlanningAI

Goal Oriented Action Planning C#/.NET Library

This library provides a basic implementation of GOAP with a bit of a utility system thrown on top.

Build Status nuget_version_badge

Basics

Goal oriented action planning enables agents to plan a sequence of actions to satisfy a specific goal. The plan of actions is chosen depending on the state of the world at the time of planning and the desired goal state.

The state of the world - or DomainState as it is called in this project - is basically just a set of variables. The planner will search through the tree of possible actions to find an optimal solution to bring this state in line with the desired goal state.

Usage

You can use the system including the agents or just the planning on its own.

The following examples show a basic scenario in which we want an agent to find a way to fill their belly.

State

To start planning we need a representation of the current world state and the desired end state.

var currentState = DomainState.Empty
    .Set("isHungry", true)
    .Set("isAt", "Woods")
    .Set("hasMoney", true);

var goalState = DomainState.Empty
    .Set("isHungry", false);

The DomainState objects are immutable but use a fluent API for easy composition.

Actions

Next, we need a definition of what the available actions for an agent are. You can implement your own actions based on IDomainAction or use one of the provided base classes.

Actions define their preconditions and effects:

public class OrderFoodAction : DomainActionBase
{
    // ...
    public OrderFoodAction() 
    {
        Preconditions.Add("isAt", "Tavern");
        Preconditions.Add("hasMoney", true);
        Effects.Add("hasMoney", false);
        Effects.Add("hasFood", true);
    }
}

You can use constructor parameters to define more generic actions:

public class GoToAction : DomainActionBase
{
    private readonly string _target;
        
    public override string ActionName => "Go To " + _target;
    public GoToAction(string target)
    {
        _target = target;
        Effects.Add("isAt", target);
    }
}

Planner

We create a planner and give it the current state, the goal state and all available actions:

// ...
var planner = PlannerFactory.CreatePlanner();
var actions = new List<IDomainAction>
{
    new GoToAction("Tavern"),
    new GoToAction("Woods"),
    new OrderFoodAction(),
    new EatFoodAction()
};

var actionSet = new ActionSet(actions);
var result = planner.GetPlan(currentState, goalState, actionSet);

if(result.Success)
{
    foreach(var action in result.Plan)
    {
        Console.WriteLine(action); // Go To Tavern, Order Food, Eat Food
    }
}

Debugging the planning

Description coming soon.

Goals

As mentioned before: If you only need planning, you don't need to define goals.

Goals are a way to determine what actions the planner of an agent should search for. They allow to inject state into the world when they are activated and they determine the goal state that must be reached to fulfill them.

class FindFoodGoal : AgentGoalBase
{
    public override string GoalName => nameof(FindFoodGoal);
    public override void OnActivation(ref DomainState currentState, ref DomainState goalState)
    {
        currentState = currentState.Set("isHungry", true);
        goalState = DomainState.Empty.Set("isHungry", false);
    }
}

In this example we determine that the agent is now hungry and that this goal will be satisfied if this is no longer the case.

Executable Actions

Before taking a closer look at agents, we need to "beef up" one of our previous actions to show how an action can interact with the agent.

public interface ICanEat
{
    void Eat();
}

public class OrderFoodAction : AsyncExecutableActionBase
{
    public override string ActionName => "Order Food";
    private readonly ICanEat _eater;
    
    public OrderFoodAction(ICanEat eater) 
    {
        _eater = eater;
        
        Preconditions.Add("isAt", "Tavern");
        Preconditions.Add("hasMoney", true);
        Effects.Add("hasMoney", false);
        Effects.Add("hasFood", true);
    }
    
    public override Task<bool> ExecuteAsync(DomainState currentState, CancellationToken token)
    {
        _eater.Eat();
        return Task.FromResult(true);
    }
}

Instead of just using DomainActionBase as base type we choose an AsyncExecutableActionBase. This allows us to define the code that will be run once the agent executes the action.

Agents

A simple way to implement an agent is to inherit from the Agent class. In the following example we have an Agent with ever increasing hunger - I'm sure you can relate.

The agent has two goals. It can either idle or find food. The winning goal is determined by evaluating Considerations attached to the goals.

internal class HungryAgent : Agent, ICanEat
{
    private float _hungerLevel;
    public void Eat() => _hungerLevel = 0;

    public void OnTick()
    {
        _hungerLevel = Math.Min(1, _hungerLevel + 0.01f);
    }

    public HungryAgent(IPlanner planner) : base(planner)
    {
        var justIdle = Consideration.FromFunc(() => 0.5f, "Idle");
        var idleGoal = AddGoal<IdleGoal>(1, justIdle);
        AddAction(new IdleAction(TimeSpan.FromSeconds(5)));

        var isHungry = Consideration.FromFunc(() => _hungerLevel, "Hunger");
        var foodGoal = AddGoal<FindFoodGoal>(1, isHungry);
        AddAction(new OrderFoodAction(this));
    }
}

As long as the hunger level is low the agent will idle - but as soon as the hunger grows too big, it will order something to eat.

Agent / Action interaction

How you want to wire up the interactions between the agents and the actions is up to you. In this example we used an interface and constructor injection. This allows you to unit test actions. Other alternatives can include callbacks / events or overwriting the Agent classes virtual methods that are provied for these scenarios.

Binding actions to goals

One of the limiting factors of GOAP is the amount of actions that need to be evaluated. For this reason and to allow certain actions not to be planned for certain goals you can bind actions to goals.

// Instead of:
AddAction(new OrderFoodAction(this));

// We can create a bindable action and bind it to the goal
var orderFood = AddBindableAction(new OrderFoodAction(this));
orderFood.BindTo(foodGoal);

Dependencies

The current implementation of DomainStatedepends on System.Collections.Immutable.ImmutableDictionary<,>. I'd like to drop this dependency further down the line for easier deployment and better performance.

Why use this implementation?

There are (a lot of) other implementations of GOAP out there. Many of them will offer more features and better integration for certain use cases. This implementation provides a regressive planner, which I personally haven't found in other .NET based solutions. If you want or need to explore deep and wide, searching from the goal state can give a significant performance advantage.

Send me a message if you know of other implementations that do it this way - I would love to take a look :)

planningai's People

Contributors

rubenwe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

planningai's Issues

Question: I want to develop application for student study planning

Hello @rubenwe

I want to develop student study planning application where student will select course =>subjects => chapters => topics (each one has some difficulty level set by teacher and approximate time to complete study for that topic).

student will have option to select exam date and number of revision he/she needs to complete.

planning library should propose best plan considering holidays and other festival consideration and study time (per day in hours).

We also want to track the progress for student whether he/she is following plan or not (this can be done by mobile app which will report daily study completion)

if there is delay then subsequent changes to plan and other measures such as reducing revisions in study plan for the student.

will this library help me achieve certain parts of above requirements?, if so, please guide me in right direction

Questions not issues

Thank you for making this available. I have a few questions and am not sure where else to ask them:

  • Dictionary<string, object> is definitely convenient during prototyping, but are there any memory or speed downsides to working with strings instead of, for instance, enums?
  • Is it possible for a precondition to use less_than or greater_than?
  • Is it possible for an effect to increment or decrement a value?
  • Have you tried this system in any projects?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.