The first thing we'll do will be to create the walls in the domain bi initializing MAP[][]. To do this, we'll implement the following helper functions:
public static void generateMap(){ //Initializes the map two-dimensional array to be [13][13] MAP = new int[MAXX+1][MAXY+1]; //+1 to handle zero base frameMap(); setStandardWalls(); } public static void frameMap(){ for(int x = 0; x <= MAXX; x++){ for(int y = 0; y <= MAXY; y++){ if(x == 0 || x == MAXX || y == 0 || y == MAXY){ MAP[x][y] = 1; } else{ MAP[x][y] = 0; } } } } public static void setStandardWalls(){ horizontalWall(1, 1, 6); horizontalWall(3, 5, 6); horizontalWall(7, 8, 5); horizontalWall(10, 11, 5); verticalWall(1, 1, 6); verticalWall(3, 8, 6); verticalWall(10, 11, 6); } protected static void horizontalWall(int xi, int xf, int y){ for(int x = xi; x <= xf; x++){ MAP[x][y] = 1; } } protected static void verticalWall(int yi, int yf, int x){ for(int y = yi; y <= yf; y++){ MAP[x][y] = 1; } }
Rather than going through the tedious process of setting each cell in MAP[][], we will instead use frameMap() to create an outer perimeter of the map and horizontalWall() and verticalWall() to easily create large walls. These methods are in turn called by setStandardWalls() to create the titular "four room" setup. generateMap() will be used later.
In order for our agent to actually be able to do anything in our world, we must first define a subclass for each action that the agent will be able to perform. To that end, add the following methods:
public static void move(State s, int xd, int yd){ ObjectInstance agent = s.getObjectsOfTrueClass(CLASSAGENT).get(0); int ax = agent.getDiscValForAttribute(ATTX); int ay = agent.getDiscValForAttribute(ATTY); int nx = ax+xd; int ny = ay+yd; if(MAP[nx][ny] == 1){ nx = ax; ny = ay; } agent.setValue(ATTX, nx); agent.setValue(ATTY, ny); } public static class NorthAction extends Action{ public NorthAction(String name, Domain domain, String parameterClasses){ super(name, domain, parameterClasses); } protected State performActionHelper(State st, String[] params) { move(st, 0, 1); System.out.println("Action Performed: " + this.name); return st; } } public static class SouthAction extends Action{ public SouthAction(String name, Domain domain, String parameterClasses){ super(name, domain, parameterClasses); } protected State performActionHelper(State st, String[] params) { move(st, 0, -1); System.out.println("Action Performed: " + this.name); return st; } } public static class EastAction extends Action{ public EastAction(String name, Domain domain, String parameterClasses){ super(name, domain, parameterClasses); } protected State performActionHelper(State st, String[] params) { move(st, 1, 0); System.out.println("Action Performed: " + this.name); return st; } } public static class WestAction extends Action{ public WestAction(String name, Domain domain, String parameterClasses){ super(name, domain, parameterClasses); } protected State performActionHelper(State st, String[] params) { move(st, -1, 0); System.out.println("Action Performed: " + this.name); return st; } }
Actions are defined by their name, the domain they exist, and the parameters that they require. Because our actions take no parameters, we simply use the parent cosntructor of the generic Action class. The performActionHelper() method is what really concerns here; this is the method that performs the action and transforms the original state. In our case, however, we decide to outsource this functionality to the move() method as all four of our actions are nearly identical.
The move() method takes in three parameters: the original state and the x/y coordinates that we wish to move the agent to relative to its current position. It then gets the agent's current position, check to see if it is moving into a wall, and sets its position accordingly. Note the usage of the getObjectsOfTrueClass(), getDiscValForAttribute(), and setValue() methods as they are essential for implementing your own actions.
Next, we'll also define our sole propositional function: atGoal(). This is implemented almost exactly the same as our actions, with the sole difference that this time we actually use the parameters to get the positions of the agent and goal objects.
public static class AtGoalPF extends PropositionalFunction{ public AtGoalPF(String name, Domain domain, String[] parameterClasses) { super(name, domain, parameterClasses); } @Override public boolean isTrue(State st, String[] params) { ObjectInstance agent = st.getObject(params[0]); //get the agent coordinates int ax = agent.getDiscValForAttribute(ATTX); int ay = agent.getDiscValForAttribute(ATTY); ObjectInstance goal = st.getObject(params[1]); //get the goal coordinates int gx = goal.getDiscValForAttribute(ATTX); int gy = goal.getDiscValForAttribute(ATTY); if(ax == gx && ay == gy){ return true; } return false; } }