001 package com.croftsoft.apps.mars.model.seri; 002 003 import java.awt.*; 004 import java.io.Serializable; 005 import java.util.*; 006 007 import com.croftsoft.core.animation.clock.HiResClock; 008 import com.croftsoft.core.animation.clock.Timekeeper; 009 import com.croftsoft.core.lang.NullArgumentException; 010 011 import com.croftsoft.apps.mars.ai.DefaultTankOperator; 012 import com.croftsoft.apps.mars.ai.PlayerTankOperator; 013 import com.croftsoft.apps.mars.ai.TankOperator; 014 import com.croftsoft.apps.mars.model.AmmoDump; 015 import com.croftsoft.apps.mars.model.Game; 016 import com.croftsoft.apps.mars.model.Obstacle; 017 import com.croftsoft.apps.mars.model.Tank; 018 import com.croftsoft.apps.mars.model.TankAccessor; 019 import com.croftsoft.apps.mars.model.World; 020 import com.croftsoft.apps.mars.model.WorldAccessor; 021 022 /********************************************************************* 023 * A Serializable implementation of Game. 024 * 025 * @version 026 * 2003-09-10 027 * @since 028 * 2003-04-03 029 * @author 030 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 031 *********************************************************************/ 032 033 public final class SeriGame 034 implements Game, Serializable 035 ////////////////////////////////////////////////////////////////////// 036 ////////////////////////////////////////////////////////////////////// 037 { 038 039 private static final long serialVersionUID = 0L; 040 041 // 042 043 public static final double DEFAULT_TIME_FACTOR = 1.0; 044 045 public static final long DEFAULT_RANDOM_SEED = 1968L; 046 047 public static final double DEFAULT_INITIAL_PLAYER_X = 20.0; 048 049 public static final double DEFAULT_INITIAL_PLAYER_Y = 20.0; 050 051 public static final int DEFAULT_AMMO_DUMPS = 3; 052 053 public static final int DEFAULT_OBSTACLES = 6; 054 055 public static final int DEFAULT_WORLD_WIDTH = 600; 056 057 public static final int DEFAULT_WORLD_HEIGHT = 400; 058 059 public static final Color DEFAULT_FRIEND_COLOR = Color.BLUE; 060 061 public static final Color DEFAULT_ENEMY_COLOR = Color.RED; 062 063 public static final double DEFAULT_TIME_DELTA_MAX = 0.2; 064 065 public static final int DEFAULT_ATTEMPTS_MAX = 10; 066 067 public static final double DEFAULT_OBSTACLE_RADIUS_MAX = 60.0; 068 069 public static final double DEFAULT_OBSTACLE_RADIUS_MIN = 10.0; 070 071 // 072 073 private final double timeFactorDefault; 074 075 private final long randomSeed; 076 077 private final double initialPlayerX; 078 079 private final double initialPlayerY; 080 081 private final int ammoDumps; 082 083 private final int obstacles; 084 085 private final int worldWidth; 086 087 private final int worldHeight; 088 089 private final Color friendColor; 090 091 private final Color enemyColor; 092 093 private final double timeDeltaMax; 094 095 private final int attemptsMax; 096 097 private final double obstacleRadiusMax; 098 099 private final double obstacleRadiusMin; 100 101 // 102 103 private final Random actionsRandom; 104 105 private final Random contentRandom; 106 107 private final TankOperator playerTankOperator; 108 109 private final Timekeeper timekeeper; 110 111 private final World world; 112 113 // 114 115 private int level; 116 117 private Tank playerTank; 118 119 ////////////////////////////////////////////////////////////////////// 120 ////////////////////////////////////////////////////////////////////// 121 122 public static void main ( String [ ] args ) 123 ////////////////////////////////////////////////////////////////////// 124 { 125 SeriGame seriGame = new SeriGame ( ); 126 127 int level = 0; 128 129 while ( true ) 130 { 131 if ( seriGame.getLevel ( ) != level ) 132 { 133 level = seriGame.getLevel ( ); 134 135 System.out.println ( new Date ( ) + ": Level " + level ); 136 } 137 138 seriGame.update ( ); 139 } 140 } 141 142 ////////////////////////////////////////////////////////////////////// 143 ////////////////////////////////////////////////////////////////////// 144 145 public SeriGame ( 146 double timeFactorDefault, 147 long randomSeed, 148 double initialPlayerX, 149 double initialPlayerY, 150 int ammoDumps, 151 int obstacles, 152 int worldWidth, 153 int worldHeight, 154 Color friendColor, 155 Color enemyColor, 156 double timeDeltaMax, 157 int attemptsMax, 158 double obstacleRadiusMax, 159 double obstacleRadiusMin, 160 SeriAmmoDump.Shared seriAmmoDumpShared ) 161 ////////////////////////////////////////////////////////////////////// 162 { 163 this.timeFactorDefault = timeFactorDefault; 164 165 this.randomSeed = randomSeed; 166 167 this.initialPlayerX = initialPlayerX; 168 169 this.initialPlayerY = initialPlayerY; 170 171 this.ammoDumps = ammoDumps; 172 173 this.obstacles = obstacles; 174 175 this.worldWidth = worldWidth; 176 177 this.worldHeight = worldHeight; 178 179 NullArgumentException.check ( this.friendColor = friendColor ); 180 181 NullArgumentException.check ( this.enemyColor = enemyColor ); 182 183 this.timeDeltaMax = timeDeltaMax; 184 185 this.attemptsMax = attemptsMax; 186 187 this.obstacleRadiusMax = obstacleRadiusMax; 188 189 this.obstacleRadiusMin = obstacleRadiusMin; 190 191 timekeeper 192 = new Timekeeper ( new HiResClock ( ), timeFactorDefault ); 193 194 contentRandom = new Random ( randomSeed ); 195 196 // The random seed for actionsRandom is set in createLevel(). 197 198 actionsRandom = new Random ( ); 199 200 world = new SeriWorld ( 201 actionsRandom, 202 seriAmmoDumpShared ); 203 204 DefaultTankOperator defaultTankOperator 205 = new DefaultTankOperator ( actionsRandom ); 206 207 playerTankOperator = new PlayerTankOperator ( defaultTankOperator ); 208 209 level = 1; 210 211 createLevel ( ); 212 } 213 214 public SeriGame ( ) 215 ////////////////////////////////////////////////////////////////////// 216 { 217 this ( 218 DEFAULT_TIME_FACTOR, 219 DEFAULT_RANDOM_SEED, 220 DEFAULT_INITIAL_PLAYER_X, 221 DEFAULT_INITIAL_PLAYER_Y, 222 DEFAULT_AMMO_DUMPS, 223 DEFAULT_OBSTACLES, 224 DEFAULT_WORLD_WIDTH, 225 DEFAULT_WORLD_HEIGHT, 226 DEFAULT_FRIEND_COLOR, 227 DEFAULT_ENEMY_COLOR, 228 DEFAULT_TIME_DELTA_MAX, 229 DEFAULT_ATTEMPTS_MAX, 230 DEFAULT_OBSTACLE_RADIUS_MAX, 231 DEFAULT_OBSTACLE_RADIUS_MIN, 232 new SeriAmmoDump.Shared ( ) ); 233 } 234 235 ////////////////////////////////////////////////////////////////////// 236 // accessor methods 237 ////////////////////////////////////////////////////////////////////// 238 239 public Iterator getPath ( ) { 240 return playerTankOperator.getPath ( ); } 241 242 public int getLevel ( ) { return level; } 243 244 public TankAccessor getPlayerTankAccessor ( ) { return playerTank; } 245 246 public Tank getPlayerTank ( ) { return playerTank; } 247 248 public Timekeeper getTimekeeper ( ) { return timekeeper; } 249 250 public WorldAccessor getWorldAccessor ( ) { return world; } 251 252 public double getTimeFactorDefault ( ) { return timeFactorDefault; } 253 254 ////////////////////////////////////////////////////////////////////// 255 ////////////////////////////////////////////////////////////////////// 256 257 public void update ( ) 258 ////////////////////////////////////////////////////////////////////// 259 { 260 world.prepare ( ); 261 262 timekeeper.update ( ); 263 264 double timeDelta = timekeeper.getTimeDelta ( ); 265 266 if ( timeDelta > timeDeltaMax ) 267 { 268 timeDelta = timeDeltaMax; 269 } 270 271 world.update ( timeDelta ); 272 273 Tank [ ] tanks = world.getTanks ( ); 274 275 for ( int i = 0; i < tanks.length; i++ ) 276 { 277 Tank tank = tanks [ i ]; 278 279 if ( !tank.isActive ( ) ) 280 { 281 for ( int j = 0; j < attemptsMax; j++ ) 282 { 283 tank.initialize ( 284 worldWidth * actionsRandom.nextDouble ( ), 285 worldHeight * actionsRandom.nextDouble ( ) ); 286 287 if ( !world.isBlocked ( tank ) ) 288 { 289 break; 290 } 291 } 292 } 293 } 294 295 Obstacle [ ] obstacles = world.getObstacles ( ); 296 297 for ( int i = 0; i < obstacles.length; i++ ) 298 { 299 if ( obstacles [ i ].isActive ( ) ) 300 { 301 return; 302 } 303 } 304 305 level++; 306 307 createLevel ( ); 308 } 309 310 ////////////////////////////////////////////////////////////////////// 311 ////////////////////////////////////////////////////////////////////// 312 313 private void createLevel ( ) 314 ////////////////////////////////////////////////////////////////////// 315 { 316 actionsRandom.setSeed ( level ); 317 318 world.clear ( ); 319 320 playerTank = world.createTank ( 321 initialPlayerX, 322 initialPlayerY, 323 friendColor ); 324 325 playerTankOperator.setTankConsole ( playerTank ); 326 327 playerTank.setTankOperator ( playerTankOperator ); 328 329 Rectangle driftBounds 330 = new Rectangle ( 0, 0, worldWidth, worldHeight ); 331 332 for ( int i = 0; i < obstacles; i++ ) 333 { 334 double radius = ( obstacleRadiusMax - obstacleRadiusMin ) 335 * contentRandom.nextDouble ( ) + obstacleRadiusMin; 336 337 Obstacle obstacle = world.createObstacle ( 338 worldWidth * contentRandom.nextDouble ( ), 339 worldHeight * contentRandom.nextDouble ( ), 340 radius, 341 obstacleRadiusMin, 342 driftBounds ); 343 344 for ( int j = 0; j < attemptsMax; j++ ) 345 { 346 if ( !world.isBlocked ( obstacle ) ) 347 { 348 break; 349 } 350 351 obstacle.setCenter ( 352 worldWidth * contentRandom.nextDouble ( ), 353 worldHeight * contentRandom.nextDouble ( ) ); 354 } 355 } 356 357 for ( int i = 0; i < ammoDumps; i++ ) 358 { 359 AmmoDump ammoDump = world.createAmmoDump ( 360 worldWidth * contentRandom.nextDouble ( ), 361 worldHeight * contentRandom.nextDouble ( ) ); 362 363 for ( int j = 0; j < attemptsMax; j++ ) 364 { 365 if ( !world.isBlocked ( ammoDump ) ) 366 { 367 break; 368 } 369 370 ammoDump.setCenter ( 371 worldWidth * contentRandom.nextDouble ( ), 372 worldHeight * contentRandom.nextDouble ( ) ); 373 } 374 } 375 376 for ( int i = 0; i < level; i++ ) 377 { 378 Tank tank = world.createTank ( 379 ( i + 1 ) * worldWidth, 380 ( i + 1 ) * worldHeight, 381 enemyColor ); 382 } 383 384 for ( int i = 0; i < level - 1; i++ ) 385 { 386 Tank tank = world.createTank ( 387 -( i + 10 ) * worldWidth, 388 -( i + 10 ) * worldHeight, 389 friendColor ); 390 } 391 } 392 393 ////////////////////////////////////////////////////////////////////// 394 ////////////////////////////////////////////////////////////////////// 395 }