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         }