--- /dev/null
+/**
+ ** A path finder implementation that uses the AStar heuristic based algorithm
+ ** to determine a path.
+ ** New changes for our purposes
+ **/
+public class AStarPathFinder {
+
+ /** The set of nodes that have been searched through */
+ private Vector closed;
+
+ /** The set of nodes that we do not yet consider fully searched */
+ private SortedList open;
+
+ /** The map being searched */
+ global GameMap[][] land;
+
+ /** The maximum depth of search we're willing to accept before giving up */
+ private int maxSearchDistance;
+
+ /** The complete set of nodes across the map */
+ private Node[][] nodes;
+
+ /** True if we allow diagonal movement */
+ private boolean allowDiagMovement;
+
+ /** Map size where we are searching */
+ private int rows, columns;
+
+ /**
+ ** Create a path finder with the default heuristic - closest to target.
+ **
+ ** @param land The map to be searched
+ ** @param maxSearchDistance The maximum depth we'll search before giving up
+ ** @param allowDiagMovement True if the search should try diagonal movement
+ **/
+ public AStarPathFinder(GameMap[][] land, int maxSearchDistance, boolean allowDiagMovement, int rows, int columns) {
+ this.land = land;
+ this.maxSearchDistance = maxSearchDistance;
+ this.allowDiagMovement = allowDiagMovement;
+ closed = new Vector();
+ open = new SortedList();
+
+ nodes = new Node[rows][columns];
+ for (int x=0;x<rows;x++) {
+ for (int y=0;y<columns;y++) {
+ nodes[x][y] = new Node(x,y);
+ }
+ }
+ this.rows = rows;
+ this.columns = columns;
+ }
+
+ /**
+ ** A description of an implementation that can find a path from one
+ ** location on a tile map to another based on information provided
+ ** by that tile map.
+ **
+ ** Find a path from the starting location to the target
+ ** location avoiding blockages and attempting to honour costs
+ ** provided by the land.
+ **
+ ** @return The path found from start to end, or null if no path can be found.
+ **/
+
+ public Path findPath(Player gamer) {
+ int tx = gamer.getGoalX();
+ int ty = gamer.getGoalY();
+ int sx = gamer.getX();
+ int sy = gamer.getY();
+
+ int type = gamer.kind();
+
+ // easy first check, if the destination is blocked, we can't get there
+
+ if(type == 1) { //1 => PLANTER
+ if(land[tx][ty].hasTree() || land[tx][ty].hasRock()) {
+ return null;
+ }
+ } else { //LUMBERJACK
+ if((!land[tx][ty].hasTree()) || land[tx][ty].hasRock()) {
+ return null;
+ }
+ }
+
+ // initial state for A*. The closed group is empty. Only the starting
+ // tile is in the open list
+ nodes[sx][sy].cost = 0;
+ nodes[sx][sy].depth = 0;
+ closed.clear();
+ open.clear();
+ open.add(nodes[sx][sy]);
+
+ nodes[tx][ty].parent = null;
+
+ // while we haven't exceeded our max search depth
+ int maxDepth = 0;
+ while ((maxDepth < maxSearchDistance) && (open.size() != 0)) {
+ // pull out the first node in our open list, this is determined to
+ // be the most likely to be the next step based on our heuristic
+
+ Node current = getFirstInOpen();
+
+ if (current == nodes[tx][ty]) {
+ break;
+ }
+
+ removeFromOpen(current);
+ addToClosed(current);
+
+ // search through all the neighbours of the current node evaluating
+ // them as next steps
+
+ for (int x=-1;x<2;x++) {
+ for (int y=-1;y<2;y++) {
+ // not a neighbour, its the current tile
+
+ if ((x == 0) && (y == 0)) {
+ continue;
+ }
+
+ // if we're not allowing diagonal movement then only
+ // one of x or y can be set
+
+ if (!allowDiagMovement) {
+ if ((x != 0) && (y != 0)) {
+ continue;
+ }
+ }
+
+ // determine the location of the neighbour and evaluate it
+
+ int xp = x + current.x;
+ int yp = y + current.y;
+
+ if (isValidLocation(gamer,sx,sy,xp,yp)) {
+ // the cost to get to this node is cost the current plus the movement
+ // cost to reach this node. Note that the heursitic value is only used
+ // in the sorted open list
+
+ int nextStepCost = current.cost + getMovementCost(current.x, current.y, xp, yp);
+ Node neighbour = nodes[xp][yp];
+
+ // if the new cost we've determined for this node is lower than
+ // it has been previously makes sure the node has
+ // determined that there might have been a better path to get to
+ // this node so it needs to be re-evaluated
+
+ if (nextStepCost < neighbour.cost) {
+ if (inOpenList(neighbour)) {
+ removeFromOpen(neighbour);
+ }
+ if (inClosedList(neighbour)) {
+ removeFromClosed(neighbour);
+ }
+ }
+
+ // if the node hasn't already been processed and discarded then
+ // reset it's cost to our current cost and add it as a next possible
+ // step (i.e. to the open list)
+ if (!inOpenList(neighbour) && !(inClosedList(neighbour))) {
+ neighbour.cost = nextStepCost;
+ neighbour.heuristic = getHeuristicCost(xp, yp, tx, ty);
+ maxDepth = Math.max(maxDepth, neighbour.setParent(current));
+ addToOpen(neighbour);
+ }
+ }
+ }
+ }
+ }
+
+ // since we'e've run out of search
+ // there was no path. Just return null
+ if (nodes[tx][ty].parent == null) {
+ return null;
+ }
+
+ // At this point we've definitely found a path so we can uses the parent
+ // references of the nodes to find out way from the target location back
+ // to the start recording the nodes on the way.
+
+ Path path = new Path();
+ Node target = nodes[tx][ty];
+ while (target != nodes[sx][sy]) {
+ path.prependStep(target.x, target.y);
+ target = target.parent;
+ }
+
+ // thats it, we have our path
+ return path;
+ }
+
+ /**
+ ** Check if a given location is valid for the supplied gamer
+ **
+ ** @param gamer The Player moving in the map
+ ** @param sx The starting x coordinate
+ ** @param sy The starting y coordinate
+ ** @param xp The x coordinate of the location to check
+ ** @param yp The y coordinate of the location to check
+ ** @return True if the location is valid for the given gamer
+ **/
+
+
+ public boolean isValidLocation(Player gamer, int sx, int sy, int xp, int yp) {
+ boolean invalid = (xp <= 0) || (yp <= 0) || (xp >= rows-1) || (yp >= columns-1);
+
+ if ((!invalid) && ((sx != xp) || (sy != yp))) {
+ if(gamer.kind() == 1) { //1=> PLANTER
+ if (land[xp][yp].hasTree() || land[xp][yp].hasRock()) {
+ invalid = true;
+ }
+ } else { //LUMBERJACK
+ if (land[xp][yp].hasRock()) {
+ invalid = true;
+ }
+ }
+ }
+ return !invalid;
+ }
+
+ /**
+ ** Get the first element from the open list. This is the next
+ ** one to be searched.
+ **
+ ** @return The first element in the open list
+ **/
+ protected Node getFirstInOpen() {
+ Node n = (Node) open.first();
+ return n;
+ }
+
+ /**
+ ** Remove a node from the open list
+ **
+ ** @param node The node to remove from the open list
+ **/
+ protected void removeFromOpen(Node node) {
+ open.remove(node);
+ }
+
+ /**
+ ** Add a node to the closed list
+ **
+ ** @param node The node to add to the closed list
+ **/
+ protected void addToClosed(Node node) {
+ closed.addElement(node);
+ }
+
+ /**
+ ** Remove a node from the closed list
+ **
+ ** @param node The node to remove from the closed list
+ **/
+ protected void removeFromClosed(Node node) {
+ closed.remove(node);
+ }
+
+ /**
+ ** Check if the node supplied is in the closed list
+ **
+ ** @param node The node to search for
+ ** @return True if the node specified is in the closed list
+ **/
+ protected boolean inClosedList(Node node) {
+ return closed.contains(node);
+ }
+
+ /**
+ ** Check if a node is in the open list
+ **
+ ** @param node The node to check for
+ ** @return True if the node given is in the open list
+ **/
+ protected boolean inOpenList(Node node) {
+ return open.contains(node);
+ }
+
+ /**
+ ** Add a node to the open list
+ **
+ ** @param node The node to be added to the open list
+ **/
+ protected void addToOpen(Node node) {
+ open.add(node);
+ }
+
+ /**
+ ** Get the cost to move through a given location
+ **
+ ** @param x The x coordinate of the tile whose cost is being determined
+ ** @param y The y coordiante of the tile whose cost is being determined
+ ** @param xp The x coordinate of the neighbor target location
+ ** @param yp The y coordinate of the neighbor target location
+ ** @return The cost of movement through the given tile
+ **/
+ public int getMovementCost(int x, int y, int xp, int yp) {
+ if (Math.abs(xp - x) == 1 && Math.abs(yp - y) == 1) {
+ return 14;
+ }
+ return 10;
+ }
+
+ /**
+ *
+ * Get the cost of moving through the given tile. This can be used to
+ ** make certain areas more desirable.
+ **
+ ** @param xp The x coordinate of the tile we're moving from
+ ** @param yp The y coordinate of the tile we're moving from
+ ** @param tx The x coordinate of the tile we're moving to
+ ** @param ty The y coordinate of the tile we're moving to
+ ** @return The relative cost of moving across the given tile
+ **/
+ public int getHeuristicCost(int xp, int yp, int tx, int ty) {
+ int heur = (Math.abs(tx - xp) + Math.abs(ty - yp)) * 10;
+ return heur;
+ }
+
+ /**
+ * Used only for debugging by printing the list element's
+ * x and y coordinates
+ **/
+
+ public void debugClosedList() {
+ for(int i=0; i<closed.size(); i++) {
+ Node n = (Node) closed.elementAt(i);
+ System.print("Element "+i+": n.getX()= "+n.getX()+" n.getY()= "+n.getY()+ "\n");
+ }
+ System.printString("\n");
+ }
+}
--- /dev/null
+public class Barrier extends Thread {
+ threadinfo[] tinfo;
+ int numthreads;
+
+ public Barrier(int n, threadinfo[] tinfo) {
+ numthreads=n;
+ this.tinfo=tinfo;
+ }
+
+ /**
+ ** Update the age of all trees in a given map
+ ** @param land The map to be searched
+ ** @param maxage The maxage of a tree
+ ** @param rows The number of rows in the map
+ ** @param cols The number of columns in the map
+ **/
+ public void updateAge(GameMap[][] land, int maxage, int rows, int cols) {
+ int countTrees = 0;
+ for(int i = 0; i<rows; i++) {
+ for(int j = 0; j<cols; j++) {
+ if(land[i][j].tree != null) {
+ if(land[i][j].tree.getage() > maxage) {
+ land[i][j].tree = null;
+ } else {
+ land[i][j].tree.incrementage();
+ }
+ countTrees++;
+ }
+ }
+ }
+ /* Debugging-> System.println("Tree count= "+countTrees); */
+ }
+
+ public static void enterBarrier(int threadid, threadinfo[] tinfo, int numthreads) {
+ int x;
+ atomic {
+ tinfo[threadid].counter++;
+ x = tinfo[threadid].counter;
+ }
+
+ for(int i=0; i<numthreads; i++) {
+ if(threadid == i) {
+ continue;
+ }
+ boolean check = false;
+ atomic {
+ if(tinfo[i].counter >= tinfo[threadid].counter) {
+ check = true;
+ }
+ }
+ if(!check) {
+ int status = Thread.getStatus(i);
+ if(status==-1) {//Thread is dead
+ System.out.println("DEBUG -> Dead\n");
+ continue;
+ }
+ int y;
+ atomic {
+ y=tinfo[i].counter;
+ }
+
+ //System.out.println("i= " + i + " i's count= " + y + " threadid= " + threadid + " mycount= " + x);
+
+ while(y!=x) {
+ //Wait for 100 microseconds
+ sleep(100);
+ atomic {
+ y = tinfo[i].counter;
+ }
+ }
+ }
+ }
+ return;
+ }
+}
+
+public class threadinfo {
+ int counter;
+ int id;
+ public threadinfo() {
+ counter = 0;
+ }
+}
+
--- /dev/null
+/**
+ ** The main Map that is shared across machines
+ ** The description for the data we're pathfinding over. This provides the contract
+ ** between the data being searched (i.e. the in game map) and the path finding
+ ** generic tools
+ **/
+
+public class GameMap {
+ private TreeType tree;
+ private RockType rock;
+
+ public GameMap() {
+ tree = null;
+ rock = null;
+ }
+
+ public boolean hasTree() {
+ if (tree != null) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean hasRock() {
+ if (rock != null) {
+ return true;
+ }
+ return false;
+ }
+
+ public void putTree(TreeType t) {
+ tree = t;
+ }
+
+ public void putRock(RockType r) {
+ rock = r;
+ }
+
+ public void cutTree() {
+ tree = null;
+ }
+
+ public boolean isEmpty() {
+ if (tree == null && rock == null) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ ** Only for Debugging by printing the map
+ ** Called after every round
+ **/
+ public void print() {
+ if (tree != null) {
+ System.print("T ");
+ return;
+ }
+ if (rock != null) {
+ System.print("o ");
+ return;
+ }
+ System.print(". ");
+ }
+}
--- /dev/null
+/**
+ ** Saves the X and Y coordinates of a single tile in a Map
+ **/
+
+public class Goal {
+ private int locX;
+ private int locY;
+
+ public Goal() {
+ locX = 0;
+ locY = 0;
+ }
+
+ public Goal(int x, int y) {
+ locX = x;
+ locY = y;
+ }
+
+ public void setXY(int x, int y) {
+ locX = x;
+ locY = y;
+ }
+
+ public int getX() {
+ return locX;
+ }
+
+ public int getY() {
+ return locY;
+ }
+}
--- /dev/null
+/**
+ ** A single node in the search graph
+ ** Has same dimensions as the Map where we are searching
+ **/
+private class Node {
+ /** The x coordinate of the node */
+ private int x;
+ /** The y coordinate of the node */
+ private int y;
+ /** The path cost for this node */
+ private int cost;
+ /** The parent of this node, how we reached it in the search */
+ private Node parent;
+ /** The heuristic cost of this node */
+ private int heuristic;
+ /** The search depth of this node */
+ private int depth;
+
+ /**
+ **Create a new node
+ **
+ ** @param x The x coordinate of the node
+ ** @param y The y coordinate of the node
+ **/
+ public Node(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ ** Set the parent of this node
+ **
+ ** @param parent The parent node which lead us to this node
+ ** @return The depth we have no reached in searching
+ **/
+ public int setParent(Node parent) {
+ depth = parent.depth + 1;
+ this.parent = parent;
+
+ return depth;
+ }
+
+ /**
+ ** compareTo(Object)
+ **/
+ public int compareTo(Object other) {
+ Node o = (Node) other;
+
+ int f = heuristic + cost;
+ int of = o.heuristic + o.cost;
+
+ if (f < of) {
+ return -1;
+ } else if (f > of) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ ** @return The cost of the heuristic
+ **/
+ public int getHeuristic() {
+ return heuristic;
+ }
+
+
+ /**
+ ** @return The actual cost of traversal
+ **/
+ public int getCost() {
+ return cost;
+ }
+
+ /**
+ ** Only for Debugging by printing contents of Node
+ **/
+ public void debugNode() {
+ System.println("x= "+ x + " y= "+ y + " cost= " + cost + " heuristic= "+ heuristic + " depth= " + depth);
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public int getY() {
+ return y;
+ }
+}
+
+/**
+ ** A simple sorted list
+ **
+ **/
+class SortedList {
+ /** The list of elements */
+ private Vector list;
+
+ public SortedList() {
+ list = new Vector();
+ }
+ /**
+ ** Retrieve the first element from the list
+ **
+ ** @return The first element from the list
+ **/
+ public Object first() {
+ Object o = list.elementAt(0);
+ return o;
+ }
+
+ /**
+ ** Empty the list
+ **/
+ public void clear() {
+ list.clear();
+ }
+
+ /**
+ **Add an element to the list - causes sorting
+ **
+ ** @param o The element to add
+ **/
+ public void add(Object o) {
+ list.addElement(o);
+ Node tmp = (Node) o;
+ int min = tmp.heuristic + tmp.cost;
+ int i;
+ int index = 0;
+ /* Move the Node with minimum cost to the first position */
+ for(i = 0; i < list.size(); i++) {
+ if(min > totalCost(list.elementAt(i))) {
+ min = totalCost(list.elementAt(i));
+ index = i;
+ }
+ }
+
+ if(index < 0 || index >=list.size()) {
+ System.printString("Illegal SortedList.add\n");
+ System.exit(-1);
+ return;
+ }
+
+ Object temp = list.elementAt(0);
+ list.setElementAt(list.elementAt(index),0);
+ list.setElementAt(temp, index);
+ }
+
+ /**
+ **@return fixed cost + heuristic cost
+ **/
+ public int totalCost(Object o) {
+ Node tmp = (Node) o;
+ int cost = tmp.getHeuristic() + tmp.getCost();
+ return cost;
+ }
+
+
+ /**
+ ** Remove an element from the list
+ **
+ ** @param o The element to remove
+ **/
+ public void remove(Object o) {
+ list.remove(o);
+ }
+
+ /**
+ ** Get the number of elements in the list
+ **
+ ** @return The number of element in the list
+ **/
+ public int size() {
+ return list.size();
+ }
+
+ /**
+ ** Check if an element is in the list
+ **
+ ** @param o The element to search for
+ ** @return True if the element is in the list
+ **/
+ public boolean contains(Object o) {
+ return list.contains(o);
+ }
+
+ /**
+ ** Only for Debugging by printing contents of openlist
+ **/
+ public void debugOpenList() {
+ for(int i=0; i<list.size(); i++) {
+ Node n = (Node) list.elementAt(i);
+ System.print("Element "+i+": n.getX()= "+n.getX()+" n.getY()= "+n.getY()+ "\n");
+ }
+ System.printString("\n");
+ }
+}
--- /dev/null
+/**
+ ** A path determined by some path finding algorithm. A series of steps from
+ ** the starting location to the target location. This includes a step for the
+ ** initial location.
+ **
+ **/
+public class Path {
+ /** The list of steps building up this path */
+ private Vector steps;
+
+ /**
+ ** Create an empty path
+ **/
+ public Path() {
+ steps = new Vector();
+ }
+
+ /**
+ ** Get the length of the path, i.e. the number of steps
+ **
+ ** @return The number of steps in this path
+ **/
+ public int getLength() {
+ return steps.size();
+ }
+
+ /**
+ ** Get the step at a given index in the path
+ **
+ ** @param index The index of the step to retrieve. Note this should
+ ** be >= 0 and < getLength();
+ ** @return The step information, the position on the map.
+ **/
+ public Step getStep(int index) {
+ return (Step) steps.elementAt(index);
+ }
+
+ /**
+ ** Get the x coordinate for the step at the given index
+ **
+ ** @param index The index of the step whose x coordinate should be retrieved
+ ** @return The x coordinate at the step
+ **/
+ public int getX(int index) {
+ return getStep(index).x;
+ }
+
+ /**
+ ** Get the y coordinate for the step at the given index
+ **
+ ** @param index The index of the step whose y coordinate should be retrieved
+ ** @return The y coordinate at the step
+ **/
+ public int getY(int index) {
+ return getStep(index).y;
+ }
+
+ /**
+ ** Append a step to the path.
+ **
+ ** @param x The x coordinate of the new step
+ ** @param y The y coordinate of the new step
+ **/
+ public void appendStep(int x, int y) {
+ steps.addElement(new Step(x,y));
+ }
+
+ /**
+ ** Prepend a step to the path.
+ **
+ ** @param x The x coordinate of the new step
+ ** @param y The y coordinate of the new step
+ **/
+ public void prependStep(int x, int y) {
+ steps.insertElementAt(new Step(x, y), 0);
+ }
+
+ /**
+ ** Check if this path contains the given step
+ **
+ ** @param x The x coordinate of the step to check for
+ ** @param y The y coordinate of the step to check for
+ ** @return True if the path contains the given step
+ **/
+ public boolean contains(int x, int y) {
+ return steps.contains(new Step(x,y));
+ }
+
+}
+
+/**
+ ** A single step within the path
+ **/
+class Step {
+ /** The x coordinate at the given step */
+ private int x;
+ /** The y coordinate at the given step */
+ private int y;
+
+ /**
+ ** Create a new step
+ **
+ ** @param x The x coordinate of the new step
+ ** @param y The y coordinate of the new step
+ **/
+ public Step(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ ** Get the x coordinate of the new step
+ **
+ ** @return The x coodindate of the new step
+ **/
+ public int getX() {
+ return x;
+ }
+
+ /**
+ ** Get the y coordinate of the new step
+ **
+ ** @return The y coodindate of the new step
+ **/
+ public int getY() {
+ return y;
+ }
+
+ /**
+ ** Same as Object#hashCode()
+ **/
+ public int hashCode() {
+ return x*y;
+ }
+
+ /**
+ ** Same as Object#equals(Object)
+ **
+ **/
+ public boolean equals(Object other) {
+ if (other instanceof Step) {
+ Step o = (Step) other;
+ if((o.x == x) && (o.y == y)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
--- /dev/null
+/**
+ ** An object representing the entity in the game that
+ ** is going to move along the path. This allows us to pass around entity/state
+ ** information to determine whether a particular tile is blocked, or how much
+ ** cost to apply on a particular tile.
+ **
+ ** a) Saves the current X and Y coordinates for a Player
+ ** b) Saves the destination goalX and goalY
+ ** c) Determines the boundary using high/low X and Y coordinates for
+ ** the current position
+ ** d) Keeps track of the STATE of the player
+ **/
+public class Player {
+ private int type;
+ private int x;
+ private int y;
+ private int lowx, highx;
+ private int lowy, highy;
+ private int state;
+ private int goalx, goaly;
+ private int rows, cols;
+ private Random rand;
+
+ public Player(int type, int x, int y) {
+ this.type = type;
+ this.x = x;
+ this.y = y;
+ }
+
+ public Player(int type, int x, int y, int rows, int cols, int bounds) {
+ this.type = type;
+ this.x = x;
+ this.y = y;
+ this.rows = rows;
+ this.cols = cols;
+ lowx = x - bounds;
+ highx = x + bounds;
+ lowy = y - bounds;
+ highy = y + bounds;
+ // define new boundaries
+ if (lowx <= 0)
+ lowx = 1;
+ if (lowy <= 0)
+ lowy = 1;
+ if (highx >= rows)
+ highx = rows-2;
+ if (highy >= cols)
+ highy = cols-2;
+ rand = new Random(30); //seed to generate random numbers
+ }
+
+ public void reset(GameMap[][] land, int row, int col, int bounds) {
+ //Teleport to new location
+ if(type == 1) { //PLANTER
+ x = (rand.nextInt(Math.abs(row - 2) + 1)) + 1;
+ y = (rand.nextInt(Math.abs(col - 2) + 1)) + 1;
+ goalx = -1;
+ goaly = -1;
+ setBoundary(bounds, row, col);
+ }
+
+ if(type == 0) { //LUMBERJACK
+ int trycount = 5; //try a few more times before teleporting
+ int i = 0;
+ while(i<trycount) {
+ int locx = (rand.nextInt(Math.abs(row - 2) + 1)) + 1;
+ int locy = (rand.nextInt(Math.abs(col - 2) + 1)) + 1;
+ if(!land[locx][locy].hasRock() && land[locx][locy].hasTree()) {
+ goalx = locx;
+ goaly = locy;
+ state = 1; //1=> MOVING state
+ return;
+ }
+ i++;
+ }
+ x = (rand.nextInt(Math.abs(row - 2) + 1)) + 1;
+ y = (rand.nextInt(Math.abs(col - 2) + 1)) + 1;
+ goalx = -1;
+ goaly = -1;
+ setBoundary(bounds, row, col);
+ }
+ }
+
+ public void setBoundary(int bounds, int rows, int cols) {
+ lowx = x - bounds;
+ highx = x + bounds;
+ lowy = y - bounds;
+ highy = y + bounds;
+ // define new boundaries
+ if (lowx <= 0)
+ lowx = 1;
+ if (lowy <= 0)
+ lowy = 1;
+ if (highx >= rows-1)
+ highx = rows-2;
+ if (highy >= cols-1)
+ highy = cols-2;
+ return;
+ }
+
+ /**
+ ** @return if Player is lumberjack or a planter
+ **/
+ public int kind() {
+ return type;
+ }
+
+ /**
+ ** Sets the X and Y coordinate of the Player
+ **/
+ public void setPosition(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public void setNewPosition(int x, int y, int row, int col, int bounds) {
+ setPosition(x, y);
+ setBoundary(bounds, row, col);
+ goalx = -1;
+ goaly = -1;
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ /** Sets state of the Player **/
+
+ public void setState(int state) {
+ this.state = state;
+ return;
+ }
+
+ public int getState() {
+ return this.state;
+ }
+
+ /** Randomly finds a goal in a given boundary for player
+ ** @return 0 on success and -1 when you cannot find any new goal
+ **/
+ public int findGoal(GameMap[][] land) {
+ /* Try setting the goal for try count times
+ * if not possible, then select a completely new goal
+ */
+ int trycount = (highx - lowx) + (highy - lowy);
+ int i;
+
+ Random rand = new Random(0);
+ for (i = 0; i < trycount; i++) {
+ int row = (rand.nextInt(Math.abs(highx - lowx)) + 1) + lowx;
+ int col = (rand.nextInt(Math.abs(highy - lowy)) + 1) + lowy;
+ if (type == 1 && (land[row][col].hasTree() == false) && (land[row][col].hasRock() == false)) {
+ goalx = row;
+ goaly = col;
+ return 0;
+ }
+ if (type == 0 && (land[row][col].hasTree() == true) && (land[row][col].hasRock() == false)) {
+ goalx = row;
+ goaly = col;
+ return 0;
+ }
+ }
+ return -1;
+ }
+
+ public void setGoal(int x, int y) {
+ goalx = x;
+ goaly = y;
+ }
+
+ public int getGoalX() {
+ return goalx;
+ }
+
+ public int getGoalY() {
+ return goaly;
+ }
+
+ /**
+ ** Only for debugging
+ **/
+ public debugPlayer() {
+ System.println("State= "+ state+ " Curr X= "+ x + " Curr Y= " + y + " Goal X= "+ goalx + " Goal Y= "+ goaly + " Type = " + type);
+ }
+
+ /**
+ ** @return true if reached the goal else return false
+ **/
+ public boolean atDest() {
+ if (x == goalx && y == goaly) {
+ return true;
+ }
+ return false;
+ }
+}
--- /dev/null
+#define ROW 400 /* columns in the map */
+#define COLUMN 100 /* rows of in the map */
+#define ROUNDS 512 /* Number of moves by each player */
+#define PLAYERS 20 /* Number of Players when num Players != num of client machines */
+#define RATI0 0.5 /* Number of lumberjacks to number of planters */
+#define BLOCK 3 /* Area around the gamer to consider */
+#define TREE_ZONE 0.4 /* Max percentage of trees in a zone */
+#define AGEUPDATETHRESHOLD 16 /* How frequently/how many rounds to increment age of tree */
+#define MAXAGE 100 /* Max age of a tree */
+
+
+#define LUMBERJACK 0 /* If lumberjack */
+#define PLANTER 1 /* If a tree planter */
+
+#define INIT 0 /* Initial state */
+#define MOVING 1 /* When moving along the map */
+
+public class RainForest extends Thread {
+ /**
+ * The grid where player is playing
+ **/
+ GameMap[][] land;
+
+ /**
+ ** The shared BarrierServer object updated when trees increment age
+ ** only updated by one thread running server
+ **/
+ Barrier barr;
+
+ /**
+ * The thread id involved
+ **/
+ int threadid;
+
+ /**
+ * The total number of threads
+ **/
+ int numThreads;
+
+
+ public RainForest() {
+
+ }
+
+ public RainForest(GameMap[][] land, Barrier barr, int threadid, int numThreads) {
+ this.land = land;
+ this.threadid = threadid;
+ this.barr = barr;
+ this.numThreads = numThreads;
+ }
+
+ public void run() {
+ int id, nthreads;
+ threadinfo[] mytinfo;
+ atomic {
+ id = threadid;
+ mytinfo = barr.tinfo;
+ nthreads = numThreads;
+ }
+
+ Random rand = new Random(id);
+ // Generate random numbers between 1 and row index/column index
+ int maxValue = ROW - 1;
+ int minValue = 1;
+ int row = (rand.nextInt(Math.abs(maxValue - minValue) + 1)) + minValue;
+ maxValue = COLUMN -1;
+ int col = (rand.nextInt(Math.abs(maxValue - minValue) + 1)) + minValue;
+ int person;
+ if((id&1) != 0) { //same as id%2
+ person = LUMBERJACK;
+ } else {
+ person = PLANTER;
+ }
+ Player gamer = new Player(person, row, col, ROW, COLUMN, BLOCK);
+
+ //
+ // Debug
+ // System.println("Player= "+ person+ " PosX= "+row+" PosY= "+col);
+ //
+
+ //Do N rounds
+ //do one move per round and synchronise
+ for(int i = 0; i<ROUNDS; i++) {
+ //System.out.println("iteration= " + i);
+ atomic {
+ doOneMove(land, gamer);
+ }
+ if((i&15) == 0 && id == 0) { //same as i%AGEUPDATETHRESHOLD
+ /* Update age of all trees in a Map */
+ atomic {
+ barr.updateAge(land, MAXAGE, ROW, COLUMN);
+ }
+ }
+ Barrier.enterBarrier(id,mytinfo,nthreads);
+ }
+ }
+
+ public static void main(String[] args) {
+ // Parse args get number of threads
+ RainForest tmprf = new RainForest();
+ RainForest.parseCmdLine(args, tmprf);
+ int numThreads= tmprf.numThreads;
+ threadinfo[] tinfo;
+ Barrier mybarr;
+
+ int[] mid = new int[8];
+ mid[0] = (128<<24)|(195<<16)|(136<<8)|162;//dc-1
+ mid[1] = (128<<24)|(195<<16)|(136<<8)|163;//dc-2
+ mid[2] = (128<<24)|(195<<16)|(136<<8)|164;//dc-3
+ mid[3] = (128<<24)|(195<<16)|(136<<8)|165;//dc-4
+ mid[4] = (128<<24)|(195<<16)|(136<<8)|166;//dc-5
+ mid[5] = (128<<24)|(195<<16)|(136<<8)|167;//dc-6
+ mid[6] = (128<<24)|(195<<16)|(136<<8)|168;//dc-7
+ mid[7] = (128<<24)|(195<<16)|(136<<8)|169;//dc-8
+
+
+ // Init land and place rocks in boundaries
+ GameMap[][] world;
+
+ atomic {
+ tinfo = global new threadinfo[numThreads];
+ for(int i=0; i<numThreads; i++) {
+ tinfo[i] = global new threadinfo();
+ }
+ }
+
+ atomic {
+ mybarr = global new Barrier(numThreads, tinfo);
+ world = global new GameMap[ROW][COLUMN];
+ int i, j;
+ for (i = 0; i < ROW; i++) {
+ for (j = 0; j < COLUMN; j++) {
+ world[i][j] = global new GameMap();
+ if (j == 0 || j == COLUMN-1) {
+ RockType r = global new RockType();
+ world[i][j].putRock(r);
+ }
+ if (i == 0 || i == ROW-1) {
+ RockType r = global new RockType();
+ world[i][j].putRock(r);
+ }
+ }
+ }
+ }
+
+ /* Set up threads */
+ RainForest[] rf;
+ atomic {
+ rf = global new RainForest[numThreads];
+ for(int i=0; i<numThreads; i++) {
+ rf[i] = global new RainForest(world, mybarr, i, numThreads);
+ }
+ }
+
+ /* Start threads */
+ RainForest tmp;
+ for(int i = 0; i<numThreads; i++) {
+ atomic {
+ tmp = rf[i];
+ }
+ tmp.start(mid[i]);
+ }
+
+ /* Join threads */
+ for(int i = 0; i<numThreads; i++) {
+ atomic {
+ tmp = rf[i];
+ }
+ tmp.join();
+ }
+ System.printString("Finished\n");
+ }
+
+ public void doOneMove(GameMap[][] land, Player gamer) {
+ // 1. Get start(x, y) position of the player
+ int currx = gamer.getX();
+ int curry = gamer.getY();
+
+ /* printLand(land, ROW, COLUMN); */
+
+ // 2. Get type of player (lumberjack or planter)
+ int type = gamer.kind();
+
+ /* gamer.debugPlayer(); */
+ //3. Change states
+ if (gamer.getState() == INIT) {
+ if (gamer.findGoal(land) < 0) {
+ gamer.reset(land, ROW, COLUMN, BLOCK);
+ return;
+ }
+ gamer.setState(MOVING);
+ }
+
+ if (gamer.getState() == MOVING) {
+ Goal nextmove = new Goal();
+ int maxSearchDistance = 10;
+ boolean allowDiagMovement = true;
+ /* Find shortest path using AStar algo from start to goal */
+ AStarPathFinder apath = new AStarPathFinder(land, maxSearchDistance, allowDiagMovement, ROW, COLUMN);
+ Path newpath = apath.findPath(gamer);
+
+ /* Reset state if there in no path from start to goal */
+ if(newpath == null) {
+ //
+ // Debug
+ // System.println("Path from ("+currx+","+curry+") to ("+gamer.getGoalX()+","+gamer.getGoalY()+") is null");
+ //
+
+ gamer.reset(land, ROW, COLUMN, BLOCK);
+ gamer.setState(INIT);
+ return;
+ }
+
+ nextmove.setXY(newpath.getX(0), newpath.getY(0));
+ gamer.setPosition(nextmove.getX(), nextmove.getY());
+ currx = gamer.getX();
+ curry = gamer.getY();
+ if (gamer.atDest()) {
+ if (gamer.kind() == LUMBERJACK) {
+ //If tree present, cut
+ if (land[currx][curry].hasTree()) {
+ land[currx][curry].cutTree();
+ //
+ // Debug
+ // System.println("Cut tree");
+ //
+ }
+ } else { // PLANTER
+ // If empty, plant tree
+ if (land[currx][curry].hasTree() == false) {
+ if(hasMoreTrees(land, currx, curry) == false) {
+ TreeType t = global new TreeType();
+ land[currx][curry].putTree(t);
+ //
+ // Debug
+ // System.println("Put tree");
+ //
+ }
+ }
+ }
+ gamer.setNewPosition(currx, curry, ROW, COLUMN, BLOCK);
+ gamer.setState(INIT);
+ } else if(land[currx][curry].hasTree() && gamer.kind() == LUMBERJACK) { //Cut trees along the way
+ land[currx][curry].cutTree();
+ //
+ // Debug
+ // System.println("Cut tree while moving");
+ //
+ }
+ // Not at destination - do nothing
+ return;
+ }
+ }
+
+ /**
+ ** Only for Debugging
+ **/
+ public void printLand(GameMap[][] land, int row, int col) {
+ for (int i = 0; i < row; i++) {
+ for (int j = 0; j < col; j++) {
+ land[i][j].print();
+ }
+ System.println("");
+ }
+ }
+
+ /**
+ * Parse the command line options.
+ **/
+ public static void parseCmdLine(String args[], RainForest rf) {
+ int i = 0;
+ String arg;
+ while(i < args.length && args[i].startsWith("-")) {
+ arg = args[i++];
+ //check options
+ if(arg.equals("-N")) {
+ if(i < args.length) {
+ rf.numThreads = new Integer(args[i++]).intValue();
+ }
+ } else if(arg.equals("-h")) {
+ rf.usage();
+ }
+ }
+
+ if(rf.numThreads == 0)
+ rf.usage();
+ }
+
+ /**
+ * The usage routine which describes the program options.
+ **/
+ public void usage() {
+ System.println("usage: ./RainForestN.bin master -N <threads>\n");
+ System.printString(" -N the number of threads\n");
+ System.printString(" -h help with usage\n");
+ }
+
+ /**
+ ** Check the number of trees in a given area
+ ** @return true if area covered more than the zone for trees
+ **/
+ public boolean hasMoreTrees(GameMap[][] land, int x, int y) {
+ int lowx = x - BLOCK;
+ int highx = x + BLOCK;
+ int lowy = y - BLOCK;
+ int highy = y + BLOCK;
+ // define new boundaries
+ if (lowx <= 0)
+ lowx = 1;
+ if (lowy <= 0)
+ lowy = 1;
+ if (highx >= ROW-1)
+ highx = ROW-2;
+ if (highy >= COLUMN-1)
+ highy = COLUMN-2;
+ int treeCount = 0;
+ int areaCount = 0;
+ for(int i = lowx; i < highx; i++) {
+ for(int j = lowy; j < highy; j++) {
+ if(land[i][j].tree != null)
+ treeCount++;
+ areaCount++;
+ }
+ }
+ if(treeCount >= (TREE_ZONE * areaCount)) {
+ return true;
+ }
+ return false;
+ }
+}
--- /dev/null
+/**
+ ** Rock and its properties
+ **/
+public class RockType {
+
+ public RockType() {
+ }
+}
--- /dev/null
+/**
+ ** Tree and its properties
+ **/
+public class TreeType {
+ private int age;
+
+ public TreeType() {
+ age = 0;
+ }
+
+ public int getage() {
+ return age;
+ }
+
+ public void incrementage() {
+ age++;
+ }
+
+ public void incrementTenYrs() {
+ age = age + 10;
+ }
+
+ public void incrementFiveYrs() {
+ age = age + 5;
+ }
+}
--- /dev/null
+#!/bin/sh
+lines=$(grep -n "#" tmp1RainForest.java | cut -d: -f1 | sed '1q')
+sed '/^#/d' tmp1RainForest.java > tmpRainForest.java
--- /dev/null
+MAINCLASS=RainForest
+SRC=tmp${MAINCLASS}.java \
+ Player.java \
+ TreeType.java \
+ GameMap.java \
+ RockType.java \
+ Barrier.java \
+ Goal.java \
+ Path.java \
+ Node.java \
+ AStarPathFinder.java \
+ ../../../../ClassLibrary/JavaDSM/Thread.java
+
+FLAGS1=-dsm -recoverystats -recovery -debug -nooptimize -mainclass ${MAINCLASS}
+
+default:
+ cpp ${MAINCLASS}.java > tmp1${MAINCLASS}.java
+ ./extractLines
+ ../../../../buildscript ${FLAGS1} -o ${MAINCLASS} ${SRC}
+
+clean:
+ rm tmp1RainForest.java
+ rm tmpRainForest.java
+ rm -rf tmpbuilddirectory
+ rm *.bin