Skip to content

Commit

Permalink
example
Browse files Browse the repository at this point in the history
  • Loading branch information
kelindar committed Nov 11, 2023
1 parent 44a131b commit efcde2d
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 0 deletions.
95 changes: 95 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,101 @@

4. **Heuristic Search**: The library uses heuristic search (A\*) to efficiently explore possible plans.

## Quick Start

This guide will walk you through implementing a simple AI using the GOAP (Goal-Oriented Action Planning) library. We'll create a scenario where an AI character must manage hunger and tiredness while gathering food. Our AI character starts with high hunger and no food. The goal is to accumulate food (`food>80`) while managing hunger and tiredness.

### Step 1: Initialize States

Start by defining the initial state (`init`) and the goal (`goal`):

```go
init := goap.StateOf("hunger=80", "!food", "!tired")
goal := goap.StateOf("food>80")
```

- `init` represents the AI's starting condition: hunger at 80, no food, and not tired.
- `goal` is the desired state where the AI has more than 80 units of food.

### Step 2: Define Actions

Define the actions the AI can perform: `eat`, `forage`, and `sleep`. Each action has prerequisites and outcomes. First, we need to implement the `Action` interface. For simplicity, we create a generic action:

```go
// NewAction creates a new action from the given name, require and outcome.
func NewAction(name, require, outcome string) *Action {
return &Action{
name: name,
require: goap.StateOf(strings.Split(require, ",")...),
outcome: goap.StateOf(strings.Split(outcome, ",")...),
}
}

// Action represents a single action that can be performed by the agent.
type Action struct {
name string
cost int
require *goap.State
outcome *goap.State
}

// Simulate simulates the action and returns the required and outcome states.
func (a *Action) Simulate(current *goap.State) (*goap.State, *goap.State) {
return a.require, a.outcome
}

// Cost returns the cost of the action.
func (a *Action) Cost() float32 {
return 1
}
```

Next, we can define a list of actions that the AI can perform (`eat`, `forage`, and `sleep`).

```go
actions := []goap.Action{
NewAction("eat", "food>0", "hunger-50,food-5"),
NewAction("forage", "tired<50", "tired+20,food+10,hunger+5"),
NewAction("sleep", "tired>30", "tired-30"),
}
```

- `eat`: Can be performed if `food>0`. Reduces hunger by 50 and food by 5.
- `forage`: Possible when `tired<50`. Increases tiredness by 20, food by 10, and hunger by 5.
- `sleep`: Executable if `tired>30`. Reduces tiredness by 30.

### Step 3: Generate the Plan

Generate a plan to reach the goal from the initial state using the defined actions.

```go
plan, err := goap.Plan(init, goal, actions)
if err != nil {
panic(err)
}
```

The output will be a sequence of actions that the AI character needs to perform to achieve its goal. Here's an example:

```text
1. forage
2. forage
3. forage
4. sleep
5. forage
6. sleep
7. forage
8. forage
9. sleep
10. forage
11. sleep
12. forage
13. eat
14. forage
```

This sequence represents the AI's decision-making process, balancing foraging for food, eating to reduce hunger, and sleeping to manage tiredness.

## License

This library is licensed under the MIT license. See the [LICENSE](https://github.com/kelindar/goap/LICENSE) file in the project root for more details.
Expand Down
60 changes: 60 additions & 0 deletions example/forage/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main

import (
"fmt"
"strings"

"github.com/kelindar/goap"
)

func main() {
init := goap.StateOf("hunger=80", "!food", "!tired")
goal := goap.StateOf("food>80")

actions := []goap.Action{
NewAction("eat", "food>0", "hunger-50,food-5"),
NewAction("forage", "tired<50", "tired+20,food+10,hunger+5"),
NewAction("sleep", "tired>30", "tired-30"),
}

plan, err := goap.Plan(init, goal, actions)
if err != nil {
panic(err)
}

for i, action := range plan {
fmt.Printf("%2d. %s\n", i+1, action.(*Action).String())
}
}

// NewAction creates a new action from the given name, require and outcome.
func NewAction(name, require, outcome string) *Action {
return &Action{
name: name,
require: goap.StateOf(strings.Split(require, ",")...),
outcome: goap.StateOf(strings.Split(outcome, ",")...),
}
}

// Action represents a single action that can be performed by the agent.
type Action struct {
name string
cost int
require *goap.State
outcome *goap.State
}

// Simulate simulates the action and returns the required and outcome states.
func (a *Action) Simulate(current *goap.State) (*goap.State, *goap.State) {
return a.require, a.outcome
}

// Cost returns the cost of the action.
func (a *Action) Cost() float32 {
return 1
}

// String returns the name of the action.
func (a *Action) String() string {
return a.name
}

0 comments on commit efcde2d

Please sign in to comment.