Skip to content

Commit

Permalink
refactor gecom goap
Browse files Browse the repository at this point in the history
  • Loading branch information
svencc committed Sep 14, 2023
1 parent 0695be9 commit 518c817
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 140 deletions.
49 changes: 28 additions & 21 deletions src/main/java/lib/gecom/action/GeAction.java
Original file line number Diff line number Diff line change
@@ -1,42 +1,50 @@
package lib.gecom.action;

import lib.gecom.stuff.GeNullTarget;
import lib.gecom.GeTargetable;
import lombok.*;
import lombok.experimental.SuperBuilder;
import lib.gecom.stuff.GeNullTarget;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;

import java.util.HashMap;

@Getter
@SuperBuilder
@RequiredArgsConstructor
public abstract class GeAction {

@NonNull
private final String name;

@NonNull
@Builder.Default
private final Float cost = 1.0f;
private final HashMap<String, Integer> preconditions = new HashMap<>();

@NonNull
@Builder.Default
private final GeTargetable target = new GeNullTarget();
private final HashMap<String, Integer> effects = new HashMap<>();

@NonNull
@Builder.Default
private final Float duration = 0.0f;
private Float duration = 0.0f;

@NonNull
@Builder.Default
private final HashMap<String, Integer> preconditions = new HashMap<>();
private Float cost = 1.0f;

@NonNull
@Builder.Default
private final HashMap<String, Integer> afterEffects = new HashMap<>();
// @NonNull
// @Builder.Default
// private final GeWorldStates worldState = new GeWorldStates(); // required to calculate isAchievable!
@Getter
private GeTargetable target = new GeNullTarget();

@Setter
@Builder.Default
private boolean actionRunning = false;


public GeAction(@NonNull final String name) {
this.name = name;
}

public GeAction(
@NonNull final String name,
@NonNull final Float cost
) {
this.name = name;
this.cost = cost;
}

public boolean isAchievable() {
return true;
}
Expand All @@ -50,5 +58,4 @@ public boolean arePreconditionsMet(@NonNull final HashMap<String, Integer> state

public abstract boolean postPerform();


}
Original file line number Diff line number Diff line change
@@ -1,50 +1,56 @@
package lib.gecom.stuff;
package lib.gecom.agent;

import lib.gecom.action.GeAction;
import lib.gecom.plan.GePlan;
import lib.gecom.plan.GePlanner;
import lib.gecom.stuff.GeGoal;
import lombok.Getter;
import lombok.NonNull;
import org.springframework.lang.Nullable;

import java.util.*;

@Getter
public class GeAgent {

@Getter
@NonNull
private final List<GeAction> possibleActions = new ArrayList<>();

@NonNull
private final PriorityQueue<GeGoal> goals = new PriorityQueue<>();

@NonNull
private final PriorityQueue<GeSubgoal> prioritizedSubgoals = new PriorityQueue<>();
private final HashMap<String, Integer> agentsBelieves = new HashMap<>();

@NonNull
private final GePlanner planner; // Get Rid of Planner in Agent? Or assign one global Planner instance vie Constructor DI?
private final GePlanner planner;

@NonNull
private final Queue<GeAction> plan = new LinkedList<>();

@NonNull
private final Stack<GeAction> currentActionStack = new Stack<>();
private GeAction currentAction;
private GeSubgoal currentGoal;

private boolean isExecutingAction = false;
@Nullable
private GeAction currentAction;

public GeAgent(final List<GeAction> possibleActions) {
if (possibleActions.isEmpty()) {
this.possibleActions.addAll(possibleActions);
}
@Nullable
private GeGoal currentGoal;

planner = new GePlanner();
}
private boolean isExecutingAction = false;

public void addSubgoal(@NonNull final GeSubgoal subgoal) {
prioritizedSubgoals.add(subgoal);

public GeAgent(@NonNull final GePlanner planner) {
this.planner = planner;
}

// Agents seem to implement these methods (Unity; maybe this will be useful for us later)
public void Start() {
public void start() {
// This is where the agent is initially set up.
// This can include initializing variables or setting up components.
}

public void Update() {
public void update() {
// Here updates are performed for the agent in every frame.
// This can include moving the agent, checking for collisions, or other ongoing operations.

Expand Down Expand Up @@ -77,7 +83,7 @@ public void Update() {
// final GeWorldStates agentsBelieves = GeWorld.getInstance().getWorldStates();
final HashMap<String, Integer> agentsBelieves = new HashMap<>();
if (currentActionStack.isEmpty()) {
for (GeSubgoal subgoal : prioritizedSubgoals) {
for (GeGoal subgoal : goals) {
final Optional<GePlan> plan = planner.planCheapest(agentsBelieves, possibleActions, subgoal.getStatesToReach());
if (plan.isPresent()) {
currentActionStack.addAll(plan.get().getActions());
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/lib/gecom/plan/GePlanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ private boolean buildGraph(
for (final GeAction action : usableActions) {
if (action.arePreconditionsMet(parent.getState())) {
final HashMap<String, Integer> currentState = (HashMap<String, Integer>) parent.getState().clone(); // copy the state! (depp clone is not necessary because String and Integers are immutable)
for (final Map.Entry<String, Integer> effect : action.getAfterEffects().entrySet()) {
for (final Map.Entry<String, Integer> effect : action.getEffects().entrySet()) {
if (currentState.containsKey(effect.getKey())) {
currentState.put(effect.getKey(), effect.getValue());
}
Expand Down Expand Up @@ -135,12 +135,16 @@ private List<GeAction> subsetOfActions(

@Getter
private static class GePlanningNode {

@Nullable
public final GePlanningNode parent;

@NonNull
public final HashMap<String, Integer> state;

@Nullable
public final GeAction action;

@NonNull
public Float cost;

Expand Down
35 changes: 35 additions & 0 deletions src/main/java/lib/gecom/stuff/GeGoal.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package lib.gecom.stuff;

import lombok.*;

import java.util.HashMap;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class GeGoal implements Comparable<GeGoal> {

@NonNull
@Builder.Default
private final HashMap<String, Integer> statesToReach = new HashMap<>();

@Setter
@Builder.Default
public boolean intendedToRemoveAfterSatisfaction = true;

@Setter
@NonNull
@Builder.Default
private Integer priority = 0;


@Override
public int compareTo(@NonNull final GeGoal other) {
final Integer mine = this.priority;
final Integer theirs = other.priority;

return mine.compareTo(theirs);
}

}
46 changes: 0 additions & 46 deletions src/main/java/lib/gecom/stuff/GeSubgoal.java

This file was deleted.

26 changes: 26 additions & 0 deletions src/test/java/lib/gecom/TestAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package lib.gecom;

import lib.gecom.action.GeAction;
import lombok.NonNull;

public class TestAction extends GeAction {

public TestAction(@NonNull final String name) {
super(name);
}

public TestAction(@NonNull final String name, @NonNull final Float cost) {
super(name, cost);
}

@Override
public boolean prePerform() {
return false;
}

@Override
public boolean postPerform() {
return false;
}

}
42 changes: 42 additions & 0 deletions src/test/java/lib/gecom/agent/GeAgentTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package lib.gecom.agent;

import lib.gecom.TestAction;
import lib.gecom.action.GeAction;
import lib.gecom.plan.GePlanner;
import lib.gecom.stuff.GeGoal;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

class GeAgentTest {

@Test
public void test() {
// Arrange
final TestAction eat = new TestAction("eat");
eat.getPreconditions().put("hungry", 1);
eat.getEffects().put("hungry", 0);

final List<GeAction> listOfPossibleActions = List.of(eat);

final GeGoal getFull = GeGoal.builder().build();
getFull.getStatesToReach().put("hungry", 0);

final GePlanner gePlanner = new GePlanner();

final GeAgent agentToTest = new GeAgent(gePlanner);
agentToTest.getPossibleActions().add(eat);
agentToTest.getAgentsBelieves().put("hungry", 1);
agentToTest.getGoals().add(getFull);

// Act
agentToTest.start();
agentToTest.update();

// Assert
assertEquals(1, agentToTest.getAgentsBelieves().get("hungry"));
}

}
Loading

0 comments on commit 518c817

Please sign in to comment.