001 package edu.cmu.gamebots; 002 003 // edu.isi.gamebots.examples.ExampleBot 004 // Copyright 2000, University of Southern California, 005 // Information Science Institute 006 // 007 // Personal and Educational use is hereby granted. 008 // Permission required for commercial use and redistribution. 009 010 // CMU Gamebots Team: 011 // Minor hacks added to make it play domination a little better... 012 // Mods by [srs] Steve Schaffer (srs3+@andrew.cmu.edu) 013 // [chris] Chris Sollitto (cs3@andrew.cmu.edu) 014 015 016 import java.awt.*; 017 import java.awt.geom.*; 018 import java.lang.*; 019 import java.util.*; 020 021 import javax.swing.*; 022 023 import edu.isi.gamebots.client.*; 024 import edu.isi.gamebots.examples.*; 025 026 027 /** 028 * This example implementation the Bot class shows basic message handling, Bot 029 * control, and and uses {@link UTMapUI} for a map in its user interface. 030 * 031 * @author <a href="mailto:amarshal+gamebots@isi.edu">Andrew n marshall</a> 032 * @author <a href="mailto:srs3+@andrew.cmu.edu">Steve Schaffer</a> 033 * @author <a href="mailto:cs3@andrew.cmu.edu'>Chris Sollitto</a> 034 */ 035 public class CMU_JBot extends Bot { 036 // Private Static Data 037 /////////////////////////////////////////////////////////////////////////// 038 protected static final int MAX_OUTPUT = 100; 039 protected static final double PLAYER_RADIUS = 18.0d; 040 protected static final double THETA_DELTA = (2d*Math.PI)/60d; // Angular Delta (6 deg) 041 protected static final int NONE = 0; 042 043 // state 044 protected static final int EXPLORING = 1; 045 protected static final int HEALING = 2; 046 protected static final int HUNTING = 3; 047 048 //[srs] 049 protected static final int DOMINATING = 4; 050 protected int shotTime = 0; 051 protected boolean gotWeapon = false; 052 053 // interference 054 protected static final int INTERFERENCE_BUMP = 1; 055 protected static final int INTERFERENCE_WALL = 2; 056 protected static final int INTERFERENCE_DAMAGE = 3; 057 058 // directional tendancy 059 protected static final int LEFT = 1; 060 protected static final int RIGHT = 2; 061 062 /** 063 * Compares Paths based on theta. 064 * 065 * Note: this comparator imposes orderings that are inconsistent with equals(...). 066 */ 067 protected static final Comparator pathComparator = new Comparator() { 068 public int compare( Object aObj, Object bObj ) { 069 Path a = (Path) aObj; 070 Path b = (Path) bObj; 071 072 if( a.theta < b.theta ) 073 return -1; 074 if( a.theta == b.theta ) 075 return 0; 076 else // a.theta > b.theta 077 return 1; 078 } 079 }; 080 081 // Private Data 082 /////////////////////////////////////////////////////////////////////// 083 protected NodeMap map = new NodeMap(); 084 085 protected Random random = new Random(); 086 087 protected Thread runnerThread; 088 089 protected boolean logIntents = false; 090 protected boolean logMessages = false; 091 protected boolean logSelf = false; 092 093 protected boolean didInit = false; 094 095 protected Object stateLock = new Object(); 096 protected long stateChangeTime = 0; 097 protected int state = EXPLORING; 098 protected int direction = NONE; // for rot/straft tendancies.. 099 100 /** 101 * This lock is used to synchronized reads from/writes to the various state 102 * variables. 103 */ 104 protected final Object selfLock = new Object(); 105 protected double x, y, z; // in world coordinates 106 protected double yaw, pitch, roll; // in Radians 107 protected int health, armor, ammo; 108 protected int team = 255; 109 protected String weapon; 110 protected Vector3D here; // Location as of the last vision update 111 112 protected boolean interfered = false; 113 protected long interferenceTime = 0; 114 protected int interferenceType = NONE; 115 116 protected long lastRotIncTime = 0; 117 protected double yawTarget; 118 119 protected Object nodeInfoLock = new Object(); 120 protected java.util.Map idToNode = new HashMap(); // Id String to Node object 121 protected Collection knownNodes = idToNode.values(); // automatic updates 122 protected Set exploredNodes = new HashSet(); 123 protected Set visibleNodes = new HashSet(); 124 protected Set reachableNodes = new HashSet(); 125 126 protected Node target, lastTarget; 127 protected long targetAcquiredTime = 0; 128 protected long targetLostTime = 0; 129 130 protected long domTargetChangeTime = 0; //[srs] 131 protected long pathRelock = 0; 132 protected int domTarget = 1; 133 protected int domsfound = 0; 134 protected String dom1id = "-"; 135 protected String dom2id = "-"; 136 protected String dom3id = "-"; 137 protected Vector3D dom1loc; 138 protected Vector3D dom2loc; 139 protected Vector3D dom3loc; 140 protected int dom1owner = TEAM_NONE; 141 protected int dom2owner = TEAM_NONE; 142 protected int dom3owner = TEAM_NONE; 143 protected Vector3D previousHere; 144 protected Message domPath; 145 protected int domPathStep = -1; 146 protected boolean askPath = false; 147 148 // Public Methods 149 /////////////////////////////////////////////////////////////////////// 150 public JComponent getView() { 151 return map; 152 } 153 154 // Protected Methods 155 /////////////////////////////////////////////////////////////////////// 156 157 // runner 158 protected Runnable runner = new Runnable() { 159 public void run() { 160 Thread thread = Thread.currentThread(); 161 while( thread == runnerThread ) { 162 try { 163 if( didInit ) { 164 synchronized( stateLock ) { 165 switch( state ) { 166 default: 167 case EXPLORING: 168 explore(); 169 break; 170 171 case HEALING: 172 heal(); 173 break; 174 175 case HUNTING: 176 hunt(); 177 break; 178 179 case DOMINATING: //[srs] 180 dominate(); 181 break; 182 } 183 } // end sync 184 } // end if 185 186 // [srs] thread.sleep( 1000l ); 187 //[srs] keep from shooting at walls, etc. 188 for( int i = 0; i<6; i++ ) 189 { 190 if(didInit && shotTime>0) 191 { 192 shotTime--; 193 if(shotTime==0) 194 { 195 stopShooting(); 196 } 197 } 198 thread.sleep( 1000 ); 199 } 200 201 } catch( InterruptedException error ) { 202 // ignore 203 } 204 } 205 } 206 }; 207 208 // Event Handlers 209 protected void connected() { 210 super.connected(); 211 212 log.logNote( "Connected... ("+new Date()+")" ); 213 214 runnerThread = new Thread( runner ); 215 runnerThread.start(); 216 217 map.repaint(); 218 } 219 220 protected void receivedAsyncMessage( Message message ) { 221 long now = System.currentTimeMillis(); 222 // log.logNote("[srs] --ASYNCH-- ("+message.getType()+") @"+now); 223 if( didInit ) { 224 if( message.getType().equals( BUMP ) ) { 225 interferenceTime = System.currentTimeMillis(); 226 interferenceType = INTERFERENCE_BUMP; 227 interfered = true; 228 } else if( message.getType().equals( WALL ) ) { 229 interferenceTime = System.currentTimeMillis(); 230 interferenceType = INTERFERENCE_WALL; 231 interfered = true; 232 } else if( message.getType().equals( DAMAGE ) ) { 233 interferenceTime = System.currentTimeMillis(); 234 interferenceType = INTERFERENCE_DAMAGE; 235 interfered = true; 236 } 237 else if( message.getType().equals( DIE ) ) 238 { //[srs] 239 log.logNote("[srs] DIED!"); 240 gotWeapon = false; //flag need weapon 241 shotTime = 0; //stop shooting 242 domTargetChangeTime=now; 243 askPath = false; 244 domPath = null; 245 domPathStep = -1; 246 } 247 else if( message.getType().equals( SEE ) ) 248 { //[srs] 249 if (Integer.parseInt(message.getProperty("Team"))!=team) 250 shootAt(message.getProperty( ACTOR_ID )); //shoot any enemies 251 } 252 else if( message.getType().equals( ITEM ) ) 253 { //[srs] get item 254 String i = message.getProperty( ITEM_ID ); 255 if(i.indexOf(WEAPON_1)!=-1 || i.indexOf(WEAPON_2)!=-1 ) 256 { 257 gotWeapon = true; //flag we are armed 258 } 259 } 260 else if (message.getType().equals( PATH ) ) 261 { 262 log.logNote( "[srs] Recieved Path ###### " ); 263 if(askPath==true) domPath = message; //store it 264 265 } 266 }else if( message.getType().equals( INFO ) ) { 267 // Init 268 // Should check to make sure it is only the first... 269 Properties props = new Properties(); 270 props.setProperty( client.PLAYER_NAME, getName() ); 271 int team = getInitialTeam(); 272 if( team != TEAM_ANY ) 273 props.setProperty( client.PLAYER_TEAM, Integer.toString(team) ); 274 client.sendMessage( client.INIT, props ); 275 didInit = true; 276 } 277 278 if( logMessages ) 279 log.logNote( message ); 280 } 281 282 protected void receivedSyncMessage( MessageBlock block ) { 283 long now = System.currentTimeMillis(); 284 // log.logNote("[srs] SYNCH -- "+now ); 285 286 StringBuffer sb = new StringBuffer(); 287 if( logMessages ) { 288 sb.append( block ); 289 } 290 291 synchronized( selfLock ) { 292 if( here == null || 293 ( here.x != x || 294 here.y != y || 295 here.z != z ) ) 296 here = new Vector3D( x, y, z ); 297 } 298 Message message; 299 String type, value; 300 Node node; 301 302 synchronized( nodeInfoLock ) { 303 visibleNodes.clear(); 304 reachableNodes.clear(); 305 306 Iterator i = block.getMessages(); 307 while( i.hasNext() ) { 308 message = (Message) i.next(); 309 type = message.getType(); 310 if( type.equals( END ) ) { 311 // ignore 312 } else if( message.getType().equals( SELF ) ) { 313 if( logSelf ) 314 log.logNote( message ); 315 updateSelf( message ); 316 if( logSelf ) 317 log.logNote( "DEBUG: Loc: "+x+" "+y+" "+z+"; Rot: "+pitch+" "+yaw+" "+roll ); 318 } else if( type.equals( PLAYER ) ) 319 { 320 /* ---- CHRIS added ---- */ 321 if (Integer.parseInt(message.getProperty("Team"))!=team) 322 shootAt(message.getProperty( ACTOR_ID )); 323 /* ------------------- */ 324 325 } 326 else if( type.equals( GAMESTATE ) ) 327 { //[srs] get updated dom info 328 329 if(!dom1id.equals("-")) 330 { String s = message.getProperty( dom1id ); //actually the parser is a bit broken on this issue... but we'll deal with it 331 if(s!=null) dom1owner = Integer.parseInt(s); 332 } 333 if(!dom2id.equals("-")) 334 { String s = message.getProperty( dom2id ); 335 if(s!=null) dom2owner = Integer.parseInt(s); 336 } 337 if(!dom3id.equals("-")) 338 { String s = message.getProperty( dom3id ); 339 if(s!=null) dom3owner = Integer.parseInt(s); 340 } 341 342 } 343 else { //some kind of nav node (or dom, or mov) [srs] 344 node = (Node) idToNode.get( message.getProperty( ACTOR_ID ) ); 345 if( node == null ) { 346 node = new Node( message ); 347 if( node.id != null ) 348 idToNode.put( node.id, node ); 349 else if( logMessages ) 350 sb.append( "\n * No ID: " ); 351 } 352 353 value = message.getProperty( ACTOR_REACHABLE ); 354 if( value != null && 355 value.equals( TRUE ) ) { 356 node.reachableFrom( here ); 357 reachableNodes.add( node ); 358 } 359 360 visibleNodes.add( node ); 361 362 if( type.equals( NAV )|| type.equals( MOV ) ) 363 { 364 node.type = NODE_NAVIGATION; 365 node.owner = TEAM_NONE; 366 } 367 else if ( type.equals( DOM ) ) 368 { 369 node.type = NODE_DOMINATION; 370 node.owner = Integer.parseInt( message.getProperty( OWNER ) ); 371 372 //[srs] store away locs of all doms found 373 if( domsfound < 3 ) //[srs] this might be a previous unknown one 374 { 375 String id = message.getProperty( ACTOR_ID ); 376 if( !id.equals(dom1id) && !id.equals(dom2id) && !id.equals(dom3id) ) //[srs] haven't seen before 377 { 378 value = message.getProperty( LOCATION ); 379 if( value != null ) { 380 double vector[] = parseVector( value ); 381 382 if(domsfound==0) {dom1id=id; dom1loc = new Vector3D(vector[0],vector[1],vector[2]);} 383 if(domsfound==1) {dom2id=id; dom2loc = new Vector3D(vector[0],vector[1],vector[2]);} 384 if(domsfound==2) {dom3id=id; dom3loc = new Vector3D(vector[0],vector[1],vector[2]);} 385 domsfound++; 386 } 387 } 388 } 389 } 390 else if ( type.equals( INV ) ) 391 { 392 node.type = NODE_INVENTORY; 393 node.owner = TEAM_NONE; 394 } 395 396 397 } 398 if( logMessages ) { 399 sb.append('\n'); 400 sb.append( message ); 401 } 402 } 403 404 runnerThread.interrupt(); 405 if( logMessages ) 406 log.logNote( sb.toString() ); 407 } 408 409 map.repaint(); 410 } 411 412 protected void disconnected() { 413 didInit = false; 414 415 log.logNote( "Disconnected... ("+new Date()+")" ); 416 417 if( runnerThread != null ) { 418 Thread oldThread = runnerThread; 419 runner = null; 420 oldThread.interrupt(); 421 } 422 423 map.repaint(); 424 } 425 426 protected void updateSelf( Message message ) { 427 String value; 428 double vector[]; 429 430 synchronized( selfLock ) { 431 value = message.getProperty( PLAYER_NAME ); 432 if( value != null ) 433 setName( value ); 434 435 value = message.getProperty( PLAYER_TEAM ); 436 if( value != null ) { 437 try { 438 team = Integer.parseInt( value ); 439 } catch( NumberFormatException error ) { 440 // Log and ignore 441 log.logError( "Illegal \""+PLAYER_TEAM+"\" value: "+value, error ); 442 } 443 } 444 445 value = message.getProperty( LOCATION ); 446 if( value != null ) { 447 vector = parseVector( value ); 448 x = vector[0]; 449 y = vector[1]; 450 z = vector[2]; 451 } 452 453 value = message.getProperty( ROTATION ); 454 if( value != null ) { 455 vector = parseVector( value ); 456 pitch = vector[0] * 2 * Math.PI / 65535; 457 yaw = vector[1] * 2 * Math.PI / 65535; 458 roll = vector[2] * 2 * Math.PI / 65535; 459 } 460 461 value = message.getProperty( PLAYER_AMMO ); 462 if( value != null ) { 463 try { 464 ammo = Integer.parseInt( value ); 465 } catch( NumberFormatException error ) { 466 // Log and ignore 467 log.logError( "Illegal \""+PLAYER_AMMO+"\" value: "+value, error ); 468 } 469 } 470 471 value = message.getProperty( PLAYER_ARMOR ); 472 if( value != null ) { 473 try { 474 armor = Integer.parseInt( value ); 475 } catch( NumberFormatException error ) { 476 // Log and ignore 477 log.logError( "Illegal \""+PLAYER_ARMOR+"\" value: "+value, error ); 478 } 479 } 480 481 value = message.getProperty( PLAYER_HEALTH ); 482 if( value != null ) { 483 try { 484 health = Integer.parseInt( value ); 485 } catch( NumberFormatException error ) { 486 // Log and ignore 487 log.logError( "Illegal \""+PLAYER_HEALTH+"\" value: "+value, error ); 488 } 489 } 490 491 value = message.getProperty( PLAYER_WEAPON ); 492 if( value != null && 493 value != weapon ) 494 weapon = value; 495 gotWeapon = true; //[srs] 496 } 497 498 synchronized( nodeInfoLock ) { 499 if( target != null && 500 target.loc.near( x, y, z, PLAYER_RADIUS ) ) { 501 exploredNodes.add( target ); 502 if( target != null ) 503 lastTarget = target; 504 target = null; 505 } 506 } 507 map.repaint(); 508 } 509 510 protected void explore() { 511 long now = System.currentTimeMillis(); 512 // Assumes synchronized on stateLock 513 514 if( state != EXPLORING ) { 515 state = EXPLORING; 516 stateChangeTime = now; 517 } 518 519 // log.logNote( "[srs] Exploring... (found "+domsfound+" doms)" ); 520 521 if( domsfound>=3 && now-stateChangeTime>15000 ) 522 { dominate(); return; //don't need to explore if we found all doms [srs] 523 } 524 525 if( domsfound>0 && now-stateChangeTime>40000 ) 526 { 527 dominate(); return; //if it's been a real long time exploring - start dom 528 } 529 530 // Atomic copy (need a consistent set of variables, but won't write to them; 531 final double x, y, z, yaw, pitch, roll; 532 synchronized( selfLock ) { 533 x = CMU_JBot.this.x; 534 y = CMU_JBot.this.y; 535 z = CMU_JBot.this.z; 536 yaw = CMU_JBot.this.yaw; 537 pitch = CMU_JBot.this.pitch; 538 } 539 540 synchronized( nodeInfoLock ) { 541 if( reachableNodes == null ) 542 { 543 //[srs] return; // No game update yet. 544 findNewTarget();//[srs] try to find some reachable ones. 545 } 546 547 if( target == null ) { 548 targetLostTime = now; 549 } 550 //[srs] //elseif..> 551 if( reachableNodes.contains( target ) ) { 552 long delay = interferenceTime - targetAcquiredTime; 553 if( ( interferenceType == INTERFERENCE_WALL && 554 delay > 1000 ) || 555 ( interferenceType != NONE && 556 delay > 3000 ) || 557 ( delay > 6000 ) ) { // Give up after some time 558 if( logIntents ) 559 log.logNote( "Giving up on target. Interference Type: "+interferenceType+", delay: "+delay ); 560 findNewTarget(); 561 } else { 562 // Otherwise continue persuing target. 563 runTo( target.id ); 564 } 565 return; 566 } 567 568 if( reachableNodes.isEmpty() ) { 569 if( logIntents ) 570 log.logNote( "No visible nodes." ); 571 findNewTarget(); 572 } else { 573 Node node; 574 575 // log.logNote( "[srs]Looking for interesting..." ); 576 boolean retargetNow = false; 577 Iterator t = reachableNodes.iterator(); 578 while( t.hasNext() ) 579 { 580 node = (Node) t.next(); 581 if( node.type == NODE_DOMINATION && node.owner!=team ) 582 { //opponent's dom point - go for it! 583 log.logNote( "[srs] Opponent's DOM!" ); 584 retargetNow = true; 585 //state = DOMINATING -- to do 586 } 587 else if( gotWeapon = false && node.type == NODE_INVENTORY ) 588 { //need a weapon? (but only if there's not a dom) 589 log.logNote( "[srs]Want a weapon!" ); 590 retargetNow = true; 591 } 592 593 if(retargetNow==true) 594 { //lock on to the point 595 direction = NONE; interferenceType = NONE; targetAcquiredTime = now; 596 if( target != null ) lastTarget = target; 597 target = node; runTo( target.id ); 598 return; //[srs] if no retarget, just fall through. else end here. 599 } 600 } 601 602 603 { // {} by [srs] pick random node 604 // log.logNote( "[srs]Generic explore...." ); 605 606 Set options = new HashSet( reachableNodes ); 607 options.removeAll( exploredNodes ); 608 if( options.isEmpty() ) { 609 if( random.nextBoolean() ) { 610 if( logIntents ) 611 log.logNote( "No unexplored nodes." ); 612 findNewTarget(); 613 return; 614 } 615 options = reachableNodes; 616 if( lastTarget != null ) 617 reachableNodes.remove( lastTarget ); 618 } 619 620 Iterator i = options.iterator(); 621 while( i.hasNext() ) { 622 node = (Node) i.next(); 623 if( node.loc.near( x, y, z, PLAYER_RADIUS ) ) 624 i.remove(); 625 } 626 if( options.isEmpty() ) { 627 if( logIntents ) 628 log.logNote( "No distant nodes." ); 629 findNewTarget(); 630 return; 631 } 632 633 node = (Node) options.toArray()[ random.nextInt( options.size() ) ]; 634 if( target == null ) { 635 if( lastTarget == node ) 636 { if( logIntents ) 637 log.logNote( "No visible nodes." ); 638 findNewTarget(); 639 } // {} by [srs] 640 } else { 641 if( target == node ) 642 findNewTarget(); 643 } 644 645 direction = NONE; 646 interferenceType = NONE; 647 targetAcquiredTime = now; 648 if( target != null ) 649 lastTarget = target; 650 target = node; 651 runTo( target.id ); 652 653 log.logNote( "[srs] Exploring... (found "+domsfound+" doms) new targ:"+target ); 654 655 } 656 657 } 658 } 659 } 660 661 protected void heal() { 662 } 663 664 protected void hunt() { 665 } 666 667 protected void dominate() //[srs] go do dom points and take control of them 668 { 669 Thread thread = Thread.currentThread(); 670 long now = System.currentTimeMillis(); 671 672 if( state != DOMINATING ) { 673 state = DOMINATING; 674 stateChangeTime = now; 675 } 676 677 // log.logNote( "[srs] -DOMINATING-! ("+domsfound+" doms found)" ); 678 679 if( domsfound==0 || (domsfound<3 && now-stateChangeTime>20000 ) ) 680 //[srs] havent found all of them and within reasonable time (or don't know any) 681 { 682 log.logNote( "[srs] Not dominating "); 683 684 explore(); return; 685 } 686 687 if(askPath==false && (now-domTargetChangeTime)>3000) 688 { 689 domTarget = chooseDomTarget(); 690 691 log.logNote( "[srs] DomTarget : "+domTarget ); 692 // if(random.nextInt(100)>77) { log.logNote( "[srs] not dominating: " ); explore();return;} //still explore with some prob. 693 694 695 // ask for a path to the doms 696 log.logNote( "[srs] Getting path... "); 697 askPath=true; domPathStep=-1; 698 if(domTarget==1) pathTo( dom1loc.x, dom1loc.y, dom1loc.z ); 699 if(domTarget==2) pathTo( dom2loc.x, dom2loc.y, dom2loc.z ); 700 if(domTarget==3) pathTo( dom3loc.x, dom3loc.y, dom3loc.z ); 701 702 try{thread.sleep(5000); } //give server a chance to find us a path 703 catch( InterruptedException error ) { 704 // ignore + I HATE JAVA, BTFW 705 } 706 } 707 708 709 if(askPath==true && domPath!=null) //we got a path back - should be following it. 710 { 711 Vector3D loc; 712 if(domPathStep>=0) loc = parseStep(domPath,domPathStep); 713 else loc = parseStep(domPath,0); 714 715 if(loc!=null) 716 { 717 // log.logNote("[srs] Following Path to "+loc.x+","+loc.y+","+loc.z); 718 // runTo(loc.x,loc.y,loc.z); 719 } 720 721 if(loc==null) //if we've reached the end of the path 722 { 723 log.logNote("[srs] Path complete!"); 724 askPath=false; 725 domPathStep=-1; 726 domPath=null; 727 return; 728 } 729 else if(domPathStep==-1) 730 { 731 if(loc!=null) { 732 log.logNote("[srs] Starting path: runto("+loc.x+","+loc.y+","+loc.z+")"); 733 runTo(loc.x,loc.y,loc.z); 734 pathRelock = now; 735 } 736 domPathStep++; 737 } 738 else if (loc.near( x, y, z, PLAYER_RADIUS )) 739 { 740 log.logNote("[srs] Path point complete: "+domPathStep); 741 domPathStep++; 742 743 loc = parseStep(domPath,domPathStep); 744 if (loc!=null) 745 { log.logNote("[srs] Continuing path: runto("+loc.x+","+loc.y+","+loc.z+")"); 746 runTo(loc.x,loc.y,loc.z); 747 pathRelock = now; 748 } 749 } 750 else 751 { 752 if(previousHere==null) previousHere = new Vector3D(0,0,0); 753 if( previousHere.near(x,y,z, PLAYER_RADIUS) && now-pathRelock>10000 ) { //try and get out of stuck on ramp, etc 754 log.logNote("[srs] Stuck on path.. jitter!"); jitter(); 755 try{thread.sleep(100000);} catch( InterruptedException error ) {}; pathRelock=0; 756 askPath=false; dominate(); return; 757 } 758 previousHere.x = x; previousHere.y = y; previousHere.z = z; 759 760 } 761 762 763 } 764 765 } 766 767 protected Vector3D parseStep(Message message, int step) 768 { 769 Vector3D temp = null; 770 771 String s = message.getProperty( Integer.toString(step) ); 772 if(s==null) return null; 773 774 String loc = s.substring(s.indexOf(" ")); 775 if(loc==null) return null; 776 777 try { double[] vector = parseVector( loc ); 778 temp = new Vector3D( vector[0], vector[1], vector[2] ); 779 } catch( RuntimeException error ) { } 780 return temp; 781 782 } 783 784 //[srs] 785 protected void pathTo( double x, double y, double z ) 786 { 787 log.logNote( "[srs] Getting Path to: "+x+","+y+","+z ); 788 Properties props = new Properties(); 789 props.setProperty( LOCATION, x+" "+y+" "+z ); 790 props.setProperty( ACTOR_ID, Integer.toString(111) ); //"unique" id 791 client.sendMessage( GETPATH, props ); 792 } 793 794 //[srs] 795 protected int chooseDomTarget() 796 { 797 // log.logNote( "[srs]Choosing new dom: " ); 798 if(domsfound>=1 && dom1owner!=team && random.nextBoolean() ) return 1; 799 if(domsfound>=3 && dom3owner!=team && random.nextBoolean() ) return 3; 800 if(domsfound>=2 && dom2owner!=team && random.nextBoolean() ) return 2; 801 802 int v = random.nextInt(2)+1; 803 if( v<=domsfound ) return v; 804 805 return 1; 806 } 807 808 /* ---- CHRIS added ---- */ 809 protected void shootAt( String target ) 810 { 811 //[srs] shoot only one thing at a time 812 if(shotTime>0) stopShooting(); 813 814 if( target == null ) 815 throw new IllegalArgumentException( "Target cannot be null." ); 816 817 Properties props = new Properties(); 818 props.setProperty( ARG_TARGET, target ); 819 client.sendMessage( SHOOT, props ); 820 shotTime = 2; //[srs] shoot for 2 ticks 821 //log.logNote( "[srs]Shooting at: "+target ); 822 823 } 824 /* --------------------- */ 825 826 //[srs] 827 protected void stopShooting( ) 828 { 829 Properties props = new Properties(); 830 client.sendMessage( STOP_SHOOT, props ); 831 } 832 833 834 protected void findNewTarget() { 835 // log.logNote( "[srs]Finding new target!" ); 836 837 interferenceType = NONE; 838 synchronized( nodeInfoLock ) { 839 if( target != null ) 840 lastTarget = target; 841 target = null; 842 } 843 interfered = false; 844 incRotation(); 845 } 846 847 protected void incRotation() { 848 long now = System.currentTimeMillis(); 849 if( now-lastRotIncTime < 200 ) { 850 // log.logNote( "Don't turn yet." ); 851 return; 852 } 853 if( direction == NONE ) { 854 if( random.nextBoolean() ) 855 direction = LEFT; 856 else 857 direction = RIGHT; 858 } 859 double newYaw; 860 if( direction == LEFT ) 861 newYaw = yaw+(Math.PI/6); // 15 deg 862 else 863 newYaw = yaw-(Math.PI/6); // 15 deg 864 if( newYaw == yawTarget ) { 865 if( logIntents ) 866 log.logNote( "Stuck in rotation: Jittering." ); 867 jitter(); // get unstuck 868 } else { 869 if( logIntents ) 870 log.logNote( "Rotating to "+newYaw ); 871 turnTo( pitch, newYaw, 0 ); 872 yawTarget = newYaw; 873 lastRotIncTime = now; 874 } 875 } 876 877 protected void jitter() { 878 switch( random.nextInt(8) ) { 879 case 0: 880 runTo( x+(PLAYER_RADIUS/2), y, z ); 881 break; 882 case 1: 883 runTo( x+(PLAYER_RADIUS/2), y+(PLAYER_RADIUS/2), z ); 884 break; 885 case 2: 886 runTo( x, y+(PLAYER_RADIUS/2), z ); 887 break; 888 case 3: 889 runTo( x-(PLAYER_RADIUS/2), y+(PLAYER_RADIUS/2), z ); 890 break; 891 case 4: 892 runTo( x-(PLAYER_RADIUS/2), y, z ); 893 break; 894 case 5: 895 runTo( x-(PLAYER_RADIUS/2), y-(PLAYER_RADIUS/2), z ); 896 break; 897 case 6: 898 runTo( x, y-(PLAYER_RADIUS/2), z ); 899 break; 900 default: 901 runTo( x+(PLAYER_RADIUS/2), y-(PLAYER_RADIUS/2), z ); 902 break; 903 } 904 } 905 906 // Inner Classes 907 /////////////////////////////////////////////////////////////////////////// 908 protected class Path { 909 public final Vector3D to; // Usually the location of a node 910 public final Vector3D from; 911 public final double theta; // Angle on the x-y plane, from x axis 912 public final double phi; // Angle from the x-y plane 913 public final double distSquared; 914 915 public final Line2D line; 916 917 public Path( Vector3D to, Vector3D from ) { 918 this.to = to; 919 this.from = from; 920 921 double dx = to.x-from.x; 922 double dy = to.y-from.y; 923 double dz = to.z-from.z; 924 theta = Math.atan2( dy, dx ); 925 double xyRadiusSquared = dx*dx + dy*dy; 926 phi = Math.atan2( dz, Math.sqrt( xyRadiusSquared ) ); 927 distSquared = xyRadiusSquared + dz*dz; 928 929 line = new Line2D.Double( from.x, from.y, to.x, to.y ); 930 } 931 } 932 933 protected class Node { 934 // Public Data 935 /////////////////////////////////////////////////////////////////////// 936 public final String id; 937 public int type = NONE; // [srs] done. 938 public int owner = TEAM_NONE; //[srs] if a dom node 939 940 public final Vector3D loc; 941 public final SortedSet paths = new TreeSet( pathComparator ); 942 943 // Public Methods 944 /////////////////////////////////////////////////////////////////////// 945 public Node( Message message ) { 946 String value = message.getProperty( LOCATION ); 947 Vector3D temp = null; 948 if( value != null ) { 949 try { 950 double[] vector = parseVector( value ); 951 temp = new Vector3D( vector[0], vector[1], vector[2] ); 952 } catch( RuntimeException error ) { 953 // temp 954 } 955 } 956 loc = temp; 957 id = message.getProperty( ACTOR_ID ); 958 } 959 960 public boolean equals( Object obj ) { 961 if( !(obj instanceof Node) ) 962 return false; 963 Node node = (Node) obj; 964 if( id == null ) 965 return node.id == null && 966 loc.near( node.loc, PLAYER_RADIUS ); 967 return id.equals( node.id ); 968 } 969 970 public String toString() { 971 return "{Node "+ACTOR_ID+"="+id+", "+LOCATION+"="+loc+"}"; 972 } 973 974 public void reachableFrom( Vector3D from ) { 975 synchronized( paths ) { 976 Path path = new Path( loc, from ); 977 if( !paths.contains( path ) ) { 978 SortedSet sub = paths.headSet( path ); 979 if( !sub.isEmpty() ) { 980 Path prev = (Path) sub.last(); 981 if( prev != null && 982 (path.theta - prev.theta < THETA_DELTA) && 983 (path.distSquared > prev.distSquared) ) 984 paths.remove( prev ); 985 } 986 sub = paths.tailSet( path ); 987 if( !sub.isEmpty() ) { 988 Path next = (Path) sub.first(); 989 if( next != null && 990 (next.theta - path.theta < THETA_DELTA) && 991 (path.distSquared > next.distSquared) ) 992 paths.remove( next ); 993 } 994 // TO-DO: special case theta's near +/-pi? 995 paths.add( path ); 996 } 997 } 998 } 999 } 1000 1001 protected class NodeMap extends JComponent { 1002 // Private Constants 1003 /////////////////////////////////////////////////////////////////////// 1004 protected final double minSymbolSize = 8d; 1005 protected final double symbolSize = 12d; 1006 1007 protected final Color COLOR_TEAM_GOLD = new Color( 0xCC9900 ); // Gold 1008 protected final Color COLOR_TEAM_DEFAULT = Color.black; 1009 1010 protected final Color COLOR_BACKGROUND = Color.white; 1011 protected final Color COLOR_AXIS = Color.lightGray; 1012 1013 protected final Color COLOR_NODE = Color.gray; 1014 protected final Color COLOR_NODE_VISIBLE = Color.darkGray; 1015 protected final Color COLOR_NODE_TARGET = Color.pink; 1016 protected final Color COLOR_NODE_TARGET_VISIBLE = Color.magenta; 1017 protected final Color COLOR_PATH = new Color( 0xEEEEEE ); // Very light gray 1018 1019 // Private Data 1020 /////////////////////////////////////////////////////////////////////// 1021 protected Object scaleLock = new Object(); 1022 protected double scale, symbolScale; 1023 1024 protected Line2D xAxis = new Line2D.Double( -Double.MAX_VALUE, 0, Double.MAX_VALUE, 0 ); 1025 protected Line2D yAxis = new Line2D.Double( 0, -Double.MAX_VALUE, 0, Double.MAX_VALUE ); 1026 protected Ellipse2D playerCircle = new Ellipse2D.Double( -symbolSize/2, -symbolSize/2, 1027 symbolSize, symbolSize ); 1028 protected Ellipse2D navPointCircle = new Ellipse2D.Double( -symbolSize/4, -symbolSize/4, 1029 symbolSize/2, symbolSize/2 ); 1030 1031 // Public Methods 1032 /////////////////////////////////////////////////////////////////////// 1033 public NodeMap() { 1034 setDoubleBuffered( true ); 1035 setScale( minSymbolSize/(2d*PLAYER_RADIUS) ); 1036 } 1037 1038 public double getScale() { 1039 return scale; 1040 } 1041 1042 public void setScale( double scale ) { 1043 synchronized( scaleLock ) { 1044 this.scale = scale; 1045 this.symbolScale = Math.max( 2*PLAYER_RADIUS, minSymbolSize/scale )/symbolSize; 1046 } 1047 repaint(); 1048 } 1049 1050 // Private Methods 1051 /////////////////////////////////////////////////////////////////////// 1052 protected void paintComponent( Graphics g ) { 1053 Color oldColor = g.getColor(); 1054 Font oldFont = g.getFont(); 1055 1056 Font font = getFont(); 1057 g.setFont( font ); 1058 FontMetrics fm = getFontMetrics( font ); 1059 Dimension size = getSize(); 1060 1061 if( g instanceof Graphics2D ) { 1062 // Clear background 1063 g.setColor( COLOR_BACKGROUND ); 1064 g.fillRect( 0, 0, size.width, size.height ); 1065 1066 if( paintComponent2D( (Graphics2D) g.create() ) ) 1067 repaint(); 1068 } else { 1069 // Clear background 1070 g.setColor( getBackground() ); 1071 g.fillRect( 0, 0, size.width, size.height ); 1072 1073 g.setColor( getForeground() ); 1074 g.drawString( "Requires Graphics2D", 2, fm.getAscent()+2 ); 1075 } 1076 1077 if( !client.isConnected() ) { 1078 final String message = "Disconnected"; 1079 int width = fm.stringWidth( message ); 1080 1081 g.setColor( Color.red ); 1082 g.drawString( message, size.width-width-2, size.height-fm.getDescent()-2 ); 1083 } 1084 1085 1086 g.setColor( oldColor ); 1087 g.setFont( oldFont ); 1088 } 1089 1090 protected boolean paintComponent2D( Graphics2D g ) { 1091 Graphics2D g2, g3; 1092 Iterator i, i2; 1093 Node node; 1094 Path path; 1095 boolean needRepaint = false; 1096 1097 Dimension size = getSize(); 1098 Rectangle2D.Double bounds = new Rectangle2D.Double( 0, 0, size.width, size.height ); 1099 1100 // Atomic copy (need a consistent set of variables, but won't write to them; 1101 final double scale, symbolScale; 1102 synchronized( scaleLock ) { 1103 scale = this.scale; 1104 symbolScale = this.symbolScale; 1105 } 1106 final double x, y, z, yaw, pitch; 1107 synchronized( selfLock ) { 1108 x = CMU_JBot.this.x; 1109 y = CMU_JBot.this.y; 1110 z = CMU_JBot.this.z; 1111 yaw = CMU_JBot.this.yaw; 1112 pitch = CMU_JBot.this.pitch; 1113 } 1114 1115 // Scale && translate 1116 g.translate( bounds.width/2, bounds.height/2 ); 1117 g.scale( scale, scale ); 1118 g2 = (Graphics2D) g.create(); 1119 g2.translate( -x, -y ); 1120 1121 // Draw Origin 1122 g2.setColor( COLOR_AXIS ); 1123 g2.draw( xAxis ); 1124 g2.draw( yAxis ); 1125 1126 // synchronized( nodeInfoLock ) { 1127 try { 1128 // Draw Paths... 1129 i = knownNodes.iterator(); 1130 while( i.hasNext() ) { 1131 node = (Node) i.next(); 1132 1133 i2 = node.paths.iterator(); 1134 g2.setColor( COLOR_PATH ); 1135 while( i2.hasNext() ) { 1136 path = (Path) i2.next(); 1137 g2.draw( path.line ); 1138 } 1139 } 1140 1141 // Draw Nodes... 1142 i = knownNodes.iterator(); 1143 while( i.hasNext() ) { 1144 node = (Node) i.next(); 1145 1146 g3 = (Graphics2D) g2.create(); 1147 g3.translate( node.loc.x, node.loc.y ); 1148 g3.scale( symbolScale, symbolScale ); 1149 drawNode( g3, node ); 1150 g3.dispose(); 1151 } 1152 } catch( RuntimeException error ) { 1153 // Probably just a problem with not blocking while accessing the node Info 1154 needRepaint = true; 1155 } 1156 1157 // Draw Players... 1158 1159 g2.dispose(); 1160 1161 // Draw Self 1162 g2 = (Graphics2D) g.create(); 1163 g2.scale( symbolScale, symbolScale ); 1164 drawPlayer( g2, team, yaw, pitch ); 1165 g2.dispose(); 1166 1167 return needRepaint; 1168 } 1169 1170 protected void drawPlayer( Graphics2D g, int team, double yaw, double pitch ) { 1171 switch( team ) { 1172 case TEAM_RED: 1173 g.setColor( Color.red ); 1174 break; 1175 case TEAM_BLUE: 1176 g.setColor( Color.blue ); 1177 break; 1178 case TEAM_GREEN: 1179 g.setColor( Color.green ); 1180 break; 1181 case TEAM_GOLD: 1182 g.setColor( COLOR_TEAM_GOLD ); 1183 break; 1184 default: 1185 g.setColor( COLOR_TEAM_DEFAULT ); 1186 break; 1187 } 1188 1189 double length = symbolSize*Math.cos( pitch ); 1190 double x = length * Math.cos( yaw ); 1191 double y = length * Math.sin( yaw ); 1192 1193 g.draw( playerCircle ); 1194 g.draw( new Line2D.Double( 0d, 0d, x, y ) ); 1195 } 1196 1197 protected void drawNode( Graphics2D g, Node node ) { 1198 switch( node.type ) { 1199 default: 1200 if( visibleNodes.contains(node) ) { 1201 if( node == target ) 1202 g.setColor( Color.magenta ); 1203 else 1204 g.setColor( Color.darkGray ); 1205 } else { 1206 if( node == target ) 1207 g.setColor( Color.pink ); 1208 else 1209 g.setColor( Color.lightGray ); 1210 } 1211 g.draw( navPointCircle ); 1212 break; 1213 } 1214 } 1215 } 1216 }