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 */
9 #define LUMBERJACK 0 /* If lumberjack */
10 #define PLANTER 1 /* If a tree planter */
11 #define SHIFT 2 /* Shift to new location */
13 #define INIT 0 /* Initial state */
14 #define MOVING 1 /* When moving along the map */
16 public class RainForestClient {
23 public RainForestClient(int seed) {
27 public RainForestClient() {
31 public static void main(String[] args) {
32 RainForestClient rfc = new RainForestClient();
33 RainForestClient.parseCmdLine(args, rfc);
35 Random rand = new Random(rfc.seed);
36 Socket sock = new Socket("dc-1.calit2.uci.edu",9002);
37 SocketInputStream si=new SocketInputStream(sock);
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);
44 if(str.equalsIgnoreCase("L")) {
47 if(str.equalsIgnoreCase("P")) {
51 // Barriers for syncronization
53 barr = new Barrier("128.195.136.162");
55 //Generate a random x and y coordinate to start with
56 int maxValue = ROW - 1;
58 int row = (rand.nextInt(Math.abs(maxValue - minValue) + 1)) + minValue;
60 int col = (rand.nextInt(Math.abs(maxValue - minValue) + 1)) + minValue;
61 Player gamer = new Player(person, row, col, ROW, COLUMN, BLOCK);
65 // System.println("Person= "+person+" LocX= "+row+" LocY= "+col);
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();
74 byte buf[] = new byte[9];
75 for(int i = 0; i<ROUNDS; i++) {
80 // Send the continue to read
82 sock.write(rfc.fillBytes("U",i));
85 //Read information of land object from Server
89 rstr = rfc.readFromSock(si, 9);
90 buf = rstr.getBytes();
91 str1 = rstr.subString(0, 1);
93 /* terminate if opcode sent is "O" */
94 if(str1.equalsIgnoreCase("O")) {
97 rfc.extractCoordinates(buf, land);
102 //rfc.printLand(land, ROW, COLUMN);
106 //do one move per round and write to server
108 rfc.doOneMove(land, gamer, sock, rand);
110 //Receive ACK from server and do player updates
111 rstr = rfc.readFromSock(si, 1);
112 retval = rstr.subString(0, 1);
115 //Update player position and player boundaries if success i.e. cut/plant tree
116 //Continue to the next iteration
118 if(retval.equalsIgnoreCase("S") && ((gamer.action == 'C') || gamer.action == 'P')) {
121 // if(gamer.action == 'C')
122 // System.println("Cutting");
123 // if(gamer.action == 'P')
124 // System.println("Planting");
127 gamer.setNewPosition(ROW, COLUMN, BLOCK);
128 gamer.setState(INIT);
133 // If success and player moving ... continue till goal reached
135 if(retval.equalsIgnoreCase("S") && gamer.action == 'M') {
136 //System.println("Moving");
141 // If server returns failure then retry
142 // move with a new goal
144 if(retval.equalsIgnoreCase("F")) {
147 // System.println("Failure....Retry\n");
149 gamer.setNewPosition(ROW, COLUMN, BLOCK);
150 gamer.setState(INIT);
153 } while(retval.equalsIgnoreCase("F"));
156 //Synchronize threads
158 Barrier.enterBarrier(barr);
161 //Special character "T" to terminate computation
163 sock.write(rfc.fillBytes("T", 0));
169 ** Create the land Map at client's end
170 ** @param b bytes read from client
171 ** @param land The map to be filled
173 public void extractCoordinates(byte[] b, GameMap[][] land) {
176 if(posX >= ROW && posY >= COLUMN) {
177 System.println("Error: Trying to access elements out of bounds in the array");
180 if(b[0] == (byte) 'T') {
181 land[posX][posY].putTree(new TreeType());
183 if(b[0] == (byte) 'R') {
184 land[posX][posY].putRock(new RockType());
190 val = ((b[1] & 0xFF) << 24) + ((b[2] & 0xFF) << 16) + ((b[3] & 0xFF) << 8) + (b[4] & 0xFF);
196 val = ((b[5] & 0xFF) << 24) + ((b[6] & 0xFF) << 16) + ((b[7] & 0xFF) << 8) + (b[8] & 0xFF);
201 ** Only for Debugging
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++) {
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
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();
225 //printLand(land, ROW, COLUMN);
228 // 2. Get type of player (lumberjack or planter)
229 int type = gamer.kind();
232 if (gamer.getState() == INIT) {
234 //gamer.debugPlayer();
236 if (gamer.findGoal(land, rand) < 0) {
237 gamer.reset(land, ROW, COLUMN, BLOCK, rand);
239 sock.write(fillBytes(SHIFT, 0, 0));
243 //gamer.debugPlayer();
245 gamer.setState(MOVING);
248 if (gamer.getState() == MOVING) {
249 Goal nextmove = new Goal();
250 int maxSearchDistance = 10;
251 boolean allowDiagMovement = true;
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);
257 /* Reset state if there in no path from start to goal */
258 if(newpath == null) {
261 // System.println("Path from ("+currx+","+curry+") to ("+gamer.getGoalX()+","+gamer.getGoalY()+") is null");
264 gamer.reset(land, ROW, COLUMN, BLOCK, rand);
265 gamer.setState(INIT);
267 sock.write(fillBytes(SHIFT, 0, 0));
271 nextmove.setXY(newpath.getX(0), newpath.getY(0));
272 gamer.setPosition(nextmove.getX(), nextmove.getY());
275 //gamer.debugPlayer();
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
284 sock.write(fillBytes(LUMBERJACK, currx, curry));
287 sock.write(fillBytes(SHIFT, 0, 0));
290 if (land[currx][curry].hasTree() == false) {
291 if(hasMoreTrees(land, currx, curry) == false) {
292 //Send next move to server
294 sock.write(fillBytes(PLANTER, currx, curry));
297 sock.write(fillBytes(SHIFT, 0, 0));
300 sock.write(fillBytes(SHIFT, 0, 0));
304 if(land[currx][curry].hasTree() && gamer.kind() == LUMBERJACK) { //Cut trees along the way
306 //Send next move to server
309 sock.write(fillBytes(LUMBERJACK, currx, curry));
312 // Not at destination - do nothing
314 sock.write(fillBytes(SHIFT, 0, 0));
322 ** Check the number of trees in a given area
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
328 ** @return true if area covered more than the zone for trees
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
342 if (highy >= COLUMN-1)
346 for(int i = lowx; i < highx; i++) {
347 for(int j = lowy; j < highy; j++) {
348 if(land[i][j].hasTree())
353 if(treeCount >= (TREE_ZONE * areaCount)) {
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
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
367 b[0] = (byte)'P'; //planting
368 if(type == LUMBERJACK)
369 b[0] = (byte)'C'; // cutting
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);
376 for(int i = 5; i<9; i++) {
377 int offset = (3-(i-5)) * 8;
378 b[i] = (byte) ((y >> offset) & 0xFF);
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
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")) {
393 if(str.equalsIgnoreCase("T")) {
397 for(int i = 1; i<5; i++) {
398 int offset = (3-(i-1)) * 8;
399 b[i] = (byte) ((index >> offset) & 0xFF);
407 ** Repeated read until you get all bytes
409 String readFromSock(SocketInputStream si, int maxBytes) {
410 byte []b=new byte[maxBytes];
412 System.out.println("Error\n");
413 return new String(b);
417 * Parse the command line options.
419 public static void parseCmdLine(String args[], RainForestClient rfc) {
422 while(i < args.length && args[i].startsWith("-")) {
425 if(arg.equals("-seed")) {
426 if(i < args.length) {
427 rfc.seed = new Integer(args[i++]).intValue();
429 } else if(arg.equals("-h")) {
439 * The usage routine which describes the program options.
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");