changes in benchmarks for the PPoPP paper
[IRC.git] / Robust / src / Benchmarks / Distributed / RainForest / java / RainForestClient.java
1 #define ROW                 100  /* columns in the map */
2 #define COLUMN              100  /* rows of in the map */
3 #define ROUNDS              256   /* Number of moves by each player */
4 #define PLAYERS             20   /* Number of Players when num Players != num of client machines */
5 #define RATI0               0.5  /* Number of lumberjacks to number of planters */
6 #define BLOCK               3    /* Area around the gamer to consider */
7 #define TREE_ZONE           0.4  /* Max percentage of trees in a zone */
8
9 #define LUMBERJACK          0    /* If lumberjack */
10 #define PLANTER             1    /* If a tree planter */
11 #define SHIFT               2    /* Shift to new location */
12
13 #define INIT                0    /* Initial state */
14 #define MOVING              1    /* When moving along the map */
15
16 public class RainForestClient {
17
18   /**
19    ** The random seed
20    **/
21   int seed;
22
23   public RainForestClient(int seed) {
24     this.seed = seed;
25   }
26
27   public RainForestClient() {
28
29   }
30
31   public static void main(String[] args) {
32     RainForestClient rfc = new RainForestClient();
33     RainForestClient.parseCmdLine(args, rfc);
34
35     Random rand = new Random(rfc.seed);
36     Socket sock = new Socket("dc-1.calit2.uci.edu",9002);
37     SocketInputStream si=new SocketInputStream(sock);
38
39     /* Read player type from Server */
40     byte b[] = new byte[1]; //read planter or lumber jack
41     String str1 = rfc.readFromSock(si, 1);
42     String str = str1.subString(0, 1);
43     int person;
44     if(str.equalsIgnoreCase("L")) {
45       person = LUMBERJACK;
46     }
47     if(str.equalsIgnoreCase("P")) {
48       person = PLANTER;
49     }
50
51     // Barriers for syncronization
52     Barrier barr;
53     barr =  new Barrier("128.195.136.162");
54
55     //Generate a random x and y coordinate to start with
56     int maxValue = ROW - 1;
57     int minValue = 1;
58     int row = (rand.nextInt(Math.abs(maxValue - minValue) + 1)) + minValue;
59     maxValue = COLUMN -1;
60     int col = (rand.nextInt(Math.abs(maxValue - minValue) + 1)) + minValue;
61     Player gamer = new Player(person, row, col, ROW, COLUMN, BLOCK);
62
63     //
64     // Debug
65     // System.println("Person= "+person+" LocX= "+row+" LocY= "+col); 
66     //
67
68     GameMap[][] land = new GameMap[ROW][COLUMN];
69     for(int i = 0; i<ROW; i++) {
70       for(int j = 0; j<COLUMN; j++) {
71         land[i][j] = new GameMap();
72       }
73     }
74     byte buf[] = new byte[9];
75     for(int i = 0; i<ROUNDS; i++) {
76       String retval;
77       do {
78         retval = null;
79         // 
80         // Send the continue to read
81         //
82         sock.write(rfc.fillBytes("U",i));
83
84         //
85         //Read information of land object from Server
86         //
87         String rstr;
88         while(true) {
89           rstr = rfc.readFromSock(si, 9);
90           buf = rstr.getBytes();
91           str1 = rstr.subString(0, 1);
92
93           /* terminate if opcode sent is "O" */
94           if(str1.equalsIgnoreCase("O")) {
95             break;
96           } else {
97             rfc.extractCoordinates(buf, land);
98           }
99         }
100
101         //Debug 
102         //rfc.printLand(land, ROW, COLUMN);
103
104         //
105         //Do rounds 
106         //do one move per round and write to server
107         //
108         rfc.doOneMove(land, gamer, sock, rand);
109
110         //Receive ACK from server and do player updates
111         rstr = rfc.readFromSock(si, 1);
112         retval = rstr.subString(0, 1);
113
114         //
115         //Update player position and player boundaries if success i.e. cut/plant tree
116         //Continue to the next iteration
117         //
118         if(retval.equalsIgnoreCase("S") && ((gamer.action == 'C') || gamer.action == 'P')) {
119           // 
120           // Debug
121           // if(gamer.action == 'C')
122           //   System.println("Cutting");
123           // if(gamer.action == 'P')
124           //   System.println("Planting");
125           //
126
127           gamer.setNewPosition(ROW, COLUMN, BLOCK);
128           gamer.setState(INIT);
129           break;
130         }
131
132         //
133         // If success and player moving ... continue till goal reached
134         //
135         if(retval.equalsIgnoreCase("S") && gamer.action == 'M') {
136           //System.println("Moving");
137           break;
138         }
139
140         //
141         // If server returns failure then retry 
142         // move with a new goal
143         //
144         if(retval.equalsIgnoreCase("F")) {
145           // 
146           // Debug
147           // System.println("Failure....Retry\n");
148           //
149           gamer.setNewPosition(ROW, COLUMN, BLOCK);
150           gamer.setState(INIT);
151         }
152
153       } while(retval.equalsIgnoreCase("F"));
154
155       //
156       //Synchronize threads
157       //
158       Barrier.enterBarrier(barr);
159     }
160     //
161     //Special character "T" to terminate computation
162     //
163     sock.write(rfc.fillBytes("T", 0));
164     sock.close();
165
166   }
167
168   /**
169    ** Create the land Map at client's end
170    ** @param b bytes read from client
171    ** @param land The map to be filled
172    **/
173   public void extractCoordinates(byte[] b, GameMap[][] land) {
174     int posX = getX(b); 
175     int posY = getY(b);
176     if(posX >= ROW && posY >= COLUMN) {
177       System.println("Error: Trying to access elements out of bounds in the array");
178     }
179
180     if(b[0] == (byte) 'T') {
181       land[posX][posY].putTree(new TreeType());
182     }
183     if(b[0] == (byte) 'R') {
184       land[posX][posY].putRock(new RockType());
185     }
186   }
187
188   int getX(byte[] b) {
189     int val;
190     val = ((b[1] & 0xFF) << 24) + ((b[2] & 0xFF) << 16) + ((b[3] & 0xFF) << 8) + (b[4] & 0xFF);
191     return val;
192   }
193
194   int getY(byte[] b) {
195     int val;
196     val = ((b[5] & 0xFF) << 24) + ((b[6] & 0xFF) << 16) + ((b[7] & 0xFF) << 8) + (b[8] & 0xFF);
197     return val;
198   }
199
200   /**
201    ** Only for Debugging 
202    **/
203   public void printLand(GameMap[][] land, int row, int col) {
204     for (int i = 0; i < row; i++) {
205       for (int j = 0; j < col; j++) {
206         land[i][j].print();
207       }
208       System.println("");
209     }
210   }
211
212   /**
213    ** One move by the gamer
214    ** @param land The map to be searched
215    ** @param gamer The player making the move
216    ** @return 0 is success , -1 otherwise
217    **/
218   public int doOneMove(GameMap[][] land, Player gamer, Socket sock, Random rand) {
219     // 1. Get start(x, y) position of the player
220     int currx = gamer.getX();
221     int curry = gamer.getY();
222
223     //
224     //Debug
225     //printLand(land, ROW, COLUMN); 
226     //
227
228     // 2. Get type of player (lumberjack or planter)
229     int type = gamer.kind();
230
231     //3. Change states
232     if (gamer.getState() == INIT) {
233
234       //gamer.debugPlayer(); 
235
236       if (gamer.findGoal(land, rand) < 0) {
237         gamer.reset(land, ROW, COLUMN, BLOCK, rand);
238         gamer.action = 'M';
239         sock.write(fillBytes(SHIFT, 0, 0));
240         return 0;
241       }
242
243       //gamer.debugPlayer(); 
244
245       gamer.setState(MOVING);
246     } 
247
248     if (gamer.getState() == MOVING) {
249       Goal nextmove = new Goal();
250       int maxSearchDistance = 10;
251       boolean allowDiagMovement = true;
252
253       /* Find shortest path using AStar algo from start to goal */
254       AStarPathFinder apath =  new  AStarPathFinder(land, maxSearchDistance, allowDiagMovement, ROW, COLUMN);
255       Path newpath = apath.findPath(gamer);
256
257       /* Reset state if there in no path from start to goal */
258       if(newpath == null) {
259         //
260         // Debug
261         // System.println("Path from ("+currx+","+curry+") to ("+gamer.getGoalX()+","+gamer.getGoalY()+") is null"); 
262         //
263
264         gamer.reset(land, ROW, COLUMN, BLOCK, rand);
265         gamer.setState(INIT);
266         gamer.action = 'M';
267         sock.write(fillBytes(SHIFT, 0, 0));
268         return 0;
269       }
270
271       nextmove.setXY(newpath.getX(0), newpath.getY(0));
272       gamer.setPosition(nextmove.getX(), nextmove.getY());
273       //
274       //Debug
275       //gamer.debugPlayer();
276       //
277       currx = gamer.getX();
278       curry = gamer.getY();
279       if (gamer.atDest()) {
280         if (gamer.kind() == LUMBERJACK) {
281           if (land[currx][curry].hasTree()) {
282             //Send next move to server
283             gamer.action = 'C';
284             sock.write(fillBytes(LUMBERJACK, currx, curry));
285             return 0;
286           } 
287           sock.write(fillBytes(SHIFT, 0, 0));
288           return 0;
289         } else { // PLANTER
290           if (land[currx][curry].hasTree() == false) {
291             if(hasMoreTrees(land, currx, curry) == false) {
292               //Send next move to server
293               gamer.action = 'P';
294               sock.write(fillBytes(PLANTER, currx, curry));
295               return 0;
296             }
297             sock.write(fillBytes(SHIFT, 0, 0));
298             return 0;
299           } 
300           sock.write(fillBytes(SHIFT, 0, 0));
301           return 0;
302         } 
303       } else {
304         if(land[currx][curry].hasTree() && gamer.kind() == LUMBERJACK) { //Cut trees along the way
305           //
306           //Send next move to server
307           //
308           gamer.action = 'C';
309           sock.write(fillBytes(LUMBERJACK, currx, curry));
310           return 0;
311         }
312         // Not at destination - do nothing
313         gamer.action = 'M';
314         sock.write(fillBytes(SHIFT, 0, 0));
315       }
316       
317       return 0;
318     }
319   }
320
321   /**
322    ** Check the number of trees in a given area
323    **
324    ** @param land The map to be searched
325    ** @param x The x coordinate to plant a tree
326    ** @param y The y coordinate to plant a tree
327    **
328    ** @return true if area covered more than the zone for trees 
329    **/
330   public boolean hasMoreTrees(GameMap[][] land, int x, int y) {
331     int lowx = x - BLOCK;
332     int highx = x + BLOCK;
333     int lowy = y - BLOCK;
334     int highy = y + BLOCK;
335     // define new boundaries
336     if (lowx <= 0) 
337       lowx = 1;
338     if (lowy <= 0) 
339       lowy = 1;
340     if (highx >= ROW-1) 
341       highx = ROW-2;
342     if (highy >= COLUMN-1) 
343       highy = COLUMN-2;
344     int treeCount = 0;
345     int areaCount = 0;
346     for(int i = lowx; i < highx; i++) {
347       for(int j = lowy; j < highy; j++) {
348         if(land[i][j].hasTree()) 
349           treeCount++;
350         areaCount++;
351       }
352     }
353     if(treeCount >= (TREE_ZONE * areaCount)) {
354       return true;
355     }
356     return false;
357   }
358
359   /** Fill byte array
360    ** @param type The player kind 1 => Planter 0=> Lumberjack 2=> Shift to new location
361    ** @param x The x coordinate of player
362    ** @param y The y coordinate of player
363    **/
364   byte[] fillBytes(int type, int x, int y) {
365     byte[] b = new byte[9]; //1 byte for the move + 8 bytes for x and y
366     if(type == PLANTER)
367       b[0] = (byte)'P'; //planting
368     if(type == LUMBERJACK)
369       b[0] = (byte)'C'; // cutting
370     if(type == SHIFT)
371       b[0] = (byte)'M'; //moving
372     for(int i = 1; i<5; i++) {
373       int offset = (3-(i-1)) * 8;
374       b[i] = (byte) ((x >> offset) & 0xFF);
375     }
376     for(int i = 5; i<9; i++) {
377       int offset = (3-(i-5)) * 8;
378       b[i] = (byte) ((y >> offset) & 0xFF);
379     }
380     return b;
381   }
382
383   /** Fill byte array for round index and termination
384    ** @param x The x coordinate of player
385    ** @param y The y coordinate of player
386    **/
387   byte[] fillBytes(String str, int index) {
388     byte[] b = new byte[5]; //1 byte for the control msg + 4 bytes for roundIndex 
389     if(str.equalsIgnoreCase("U")) {
390       b[0] = (byte)'U';
391     }
392
393     if(str.equalsIgnoreCase("T")) {
394       b[0] = (byte)'T';
395     }
396
397     for(int i = 1; i<5; i++) {
398       int offset = (3-(i-1)) * 8;
399       b[i] = (byte) ((index >> offset) & 0xFF);
400     }
401
402     return b;
403   }
404
405
406   /**
407    ** Repeated read until you get all bytes
408    **/
409   String readFromSock(SocketInputStream si, int maxBytes) {
410     byte []b=new byte[maxBytes];
411     if (si.readAll(b)<0)
412         System.out.println("Error\n");
413     return new String(b);
414   }
415
416   /**
417    * Parse the command line options.
418    **/
419   public static void parseCmdLine(String args[], RainForestClient rfc) {
420     int i = 0;
421     String arg;
422     while(i < args.length && args[i].startsWith("-")) {
423       arg = args[i++];
424       //check options
425       if(arg.equals("-seed")) {
426         if(i < args.length) {
427           rfc.seed = new Integer(args[i++]).intValue();
428         }
429       } else if(arg.equals("-h")) {
430         rfc.usage();
431       }
432     }
433
434     if(rfc.seed <= 0)
435       rfc.usage();
436   }
437
438   /**
439    * The usage routine which describes the program options.
440    **/
441   public void usage() {
442     System.printString("usage: ./Client.bin -seed <seed value for Random variable>\n");
443     System.printString("    -seed the seed value for Random\n");
444     System.printString("    -h help with usage\n");
445   }
446 }