I am currently exploring how Jason deals with a synchronized environment in which one agent must wait till others perform an action. Besides, when all agents have done, env needs to save info to environment models as well. From the document, Jason exposes a way via TimeSteppedEnvironment
.
My problem is, at reasoningCycle
(class LocalAgArch
), there is an error where an agent can't get percepts. Error message is below, I am not sure what I missed to let requests
not be null
.
[test1] *** ERROR in the transition system (sense). Circumstance:
E =[+!start[source(self)], +kqml::clear_source_self([],[])[hide_in_mind_inspector,source(self)]]
I =[]
A =null
MB=[]
RP=null
AP=null
SE=null
SO=null
SI=null
AI=null
AE=null
PA={}
PI={}
FA=[].
Creating a new C!
java.lang.NullPointerException: Cannot enter synchronized block because "this.requests" is null
at jason.environment.TimeSteppedEnvironment.getPercepts(TimeSteppedEnvironment.java:303)
at jason.infra.local.LocalAgArch.perceive(LocalAgArch.java:330)
at jason.asSemantics.TransitionSystem.sense(TransitionSystem.java:1673)
at jason.infra.local.LocalAgArch.sense(LocalAgArch.java:213)
at jason.infra.local.LocalAgArch.reasoningCycle(LocalAgArch.java:250)
at jason.infra.local.LocalAgArch.run(LocalAgArch.java:273)
at java.base/java.lang.Thread.run(Thread.java:833)
For details, I share some code snippets below. FYI, I borrowed code from Jason's Miners-II example, then simplified it.
MAS2J project
MAS test {
environment: env.MARLEnv(1000) // timeout in milliseconds
agents: test_agent #3;
}
ASL code
!start.
/* Plans */
+!start : true <-
move("down");
!start.
My env is a grid 5x5
public class SwitchEnvV1 extends TimeSteppedEnvironment {
public static final int GRID_SIZE = 5;
private EnvModel model = null;
private EnvView view = null;
public SwitchEnvV1(){
setOverActionsPolicy(OverActionsPolicy.queue);
}
@Override
public void init(String[] args) {
model = new EnvModel();
model.setAgPos(0, 0, 0);
model.setAgPos(1, GRID_SIZE-1, GRID_SIZE-1);
view = new EnvView(model);
model.setView(view);
clearPercepts(); // clear the percepts of the agents
}
@Override
public boolean executeAction(String ag, Structure action) {
return model.dummy_act(ag, action);
}
class EnvModel extends GridWorldModel { //GridWorldModel from Jason
private EnvModel() {
super(GRID_SIZE, GRID_SIZE, 2);
}
synchronized public boolean dummy_act(String agId, Structure action){
// synchronized as I want to update mode
System.out.println("["+agId+"] doing: "+action);
return true;
}
}
class EnvView extends GridWorldView { //GridWorldView from Jason
@Serial
private static final long serialVersionUID = 1L;
public EnvView(EnvModel model) {
super(model, "SwitchEnvV1", 600);
defaultFont = new Font("Arial", Font.BOLD, 18);
setVisible(true);
repaint();
}
}
}
In class SwicthEnvV1
, the method init
is incorrectly overwritten because in its parent, TimeSteppedEnvironment
, request
is created inside. Hence, SwicthEnvV1
should mimic the same thing.
A safer solution is to create a constructor at the child class, then init model and view inside it. For example
public SwitchEnvV1(){
// use queue policy when an agent tries more than one action in the same cycle,
setOverActionsPolicy(OverActionsPolicy.queue);
model = new EnvModel();
model.setAgPos(0, 0, 0);
model.setAgPos(1, GRID_SIZE-1, GRID_SIZE-1);
view = new EnvView(model);
model.setView(view);
clearPercepts(); // clear the percepts of the agents
}