001         package com.croftsoft.apps.infravision;
002    
003         import java.applet.Applet;
004         import java.awt.Graphics;
005         import java.awt.*;
006         import java.awt.Color;
007         import java.awt.Point;
008         import java.awt.Rectangle;
009    
010         import com.croftsoft.core.gui.plot.PlotLib;
011         import com.croftsoft.core.lang.lifecycle.Lifecycle;
012         import com.croftsoft.core.math.RandomLib;
013    
014         /*********************************************************************
015         * Goblins hunt kobolds in the dark using infravision.
016         *
017         * @version
018         *   2002-03-02
019         * @since
020         *   1996-08-23
021         * @author
022         *   <a href="https://www.croftsoft.com/">David Wallace Croft</a>
023         *********************************************************************/
024    
025         public class  Infravision
026           extends Applet
027           implements Lifecycle, Runnable
028         //////////////////////////////////////////////////////////////////////
029         //////////////////////////////////////////////////////////////////////
030         {
031    
032         boolean  goblin_vision_on = false;
033    
034         private Point  lower_left  = new Point (   0,   0 );
035         private Point  upper_right = new Point ( 100, 100 );
036    
037         int walls_border_count = 2 * ( upper_right.x - lower_left.x + 1 )
038                                + 2 * ( upper_right.y - lower_left.y + 1 ) - 4;
039         int walls_count     = walls_border_count + 100;
040         int goblins_count   = 100;
041         int kobolds_count   = 100;
042    
043         boolean [ ]  goblin_alive = new boolean [ goblins_count ];
044         boolean [ ]  kobold_alive = new boolean [ kobolds_count ];
045    
046         int  goblins_alive_count = goblins_count;
047         int  kobolds_alive_count = kobolds_count;
048    
049         Point [ ]  goblin_place = new Point [ goblins_count ];
050         Point [ ]  kobold_place = new Point [ kobolds_count ];
051         Point [ ]  wall_place   = new Point [ walls_count   ];
052    
053         Thread    runner;
054         Image     offscreenImage;
055         Graphics  offscreenGraphics;
056    
057         static final int  ETHER  = 0;
058         static final int  WALL   = 1;
059         static final int  GOBLIN = 2;
060         static final int  KOBOLD = 3;
061    
062         private int    space_contents [ ] [ ]
063           = new int [ upper_right.x - lower_left.x + 1 ]
064                     [ upper_right.y - lower_left.y + 1 ];
065    
066         private Rectangle  r = new Rectangle ( );
067    
068         private Point  margin_top_left     = new Point ( 10, 10 );
069         private Point  margin_bottom_right = new Point ( 20, 20 );
070    
071         //////////////////////////////////////////////////////////////////////
072         //////////////////////////////////////////////////////////////////////
073    
074         public synchronized void  init ( )
075         //////////////////////////////////////////////////////////////////////
076         {
077           r = new Rectangle ( margin_top_left.x, margin_top_left.y,
078             getSize ( ).width  - margin_bottom_right.x,
079             getSize ( ).height - margin_bottom_right.y );
080    
081           offscreenImage = createImage ( getSize ( ).width, getSize ( ).height );
082    
083           offscreenGraphics = offscreenImage.getGraphics ( );
084    
085           init_walls   ( );
086    
087           goblins_init ( );
088    
089           kobolds_init ( );
090         }
091    
092         public void  start ( )
093         //////////////////////////////////////////////////////////////////////
094         {
095           runner = new Thread ( this );
096    
097           int  priority = runner.getPriority ( ) - 1;
098    
099           if ( priority >= Thread.MIN_PRIORITY )
100           {
101             runner.setPriority ( priority );
102           }
103    
104           runner.setDaemon ( true );
105    
106           runner.start ( );
107         }
108    
109         public synchronized void  stop ( )
110         //////////////////////////////////////////////////////////////////////
111         {
112           Thread  thread = runner;
113    
114           if ( thread != null )
115           {
116             runner = null;
117    
118             thread.interrupt ( );
119           }
120         }
121    
122         public synchronized void  destroy ( )
123         //////////////////////////////////////////////////////////////////////
124         {
125           stop ( );
126         }
127    
128         //////////////////////////////////////////////////////////////////////
129         //////////////////////////////////////////////////////////////////////
130    
131         public void  run ( )
132         //////////////////////////////////////////////////////////////////////
133         {
134           Thread  thread = Thread.currentThread ( );
135    
136           try
137           {
138             while ( thread == runner )
139             {
140               kobolds_move ( );
141    
142               goblins_move ( );
143    
144               paint ( offscreenGraphics );
145    
146               Graphics  g = this.getGraphics ( );
147    
148               g.drawImage ( offscreenImage, 0, 0, this );
149    
150               Thread.sleep ( 1000 );
151             }
152           }
153           catch ( InterruptedException e )
154           {
155           }
156         }
157    
158         //////////////////////////////////////////////////////////////////////
159         //////////////////////////////////////////////////////////////////////
160    
161         public Point  goblin_move_direction ( int  index_goblin ) {
162         //////////////////////////////////////////////////////////////////////
163           Point    direction         = new Point ( 0, 0 );
164           Point    proposed_location = new Point ( 0, 0 );
165           boolean  target_found      = false;
166         //////////////////////////////////////////////////////////////////////
167           if ( goblin_vision_on ) {
168             outer_loop:
169             for ( int index_x = -1;
170                       index_x <= 1;
171                       index_x++ ) {
172               for ( int index_y = -1;
173                         index_y <= 1;
174                         index_y++ ) {
175                 proposed_location.x = goblin_place [ index_goblin ].x + index_x;
176                 proposed_location.y = goblin_place [ index_goblin ].y + index_y;
177                 if ( space_contents
178                        [ proposed_location.x ]
179                        [ proposed_location.y ] == KOBOLD ) {
180                   target_found = true;
181                   direction.x = index_x;
182                   direction.y = index_y;
183                   break outer_loop;
184                 }
185               }
186             }
187           }
188           if ( !target_found ) {
189             direction.x = ( int ) RandomLib.roll ( 1, 3, -2 );
190             direction.y = ( int ) RandomLib.roll ( 1, 3, -2 );
191           }
192           return new Point ( direction.x, direction.y );
193         }
194    
195         public void  goblin_move ( int  index_goblin ) {
196         //////////////////////////////////////////////////////////////////////
197           boolean  abort_move = false;
198           Point    move_direction;
199           Point    new_place = new Point ( 0, 0 );
200         //////////////////////////////////////////////////////////////////////
201           new_place.x = goblin_place [ index_goblin ].x;
202           new_place.y = goblin_place [ index_goblin ].y;
203           move_direction = goblin_move_direction ( index_goblin );
204           new_place.x += move_direction.x;
205           new_place.y += move_direction.y;
206           if ( new_place.x < lower_left.x  ) abort_move = true;
207           if ( new_place.x > upper_right.x ) abort_move = true;
208           if ( new_place.y < lower_left.y  ) abort_move = true;
209           if ( new_place.y > upper_right.y ) abort_move = true;
210           if ( !abort_move ) {
211             if ( space_contents [ new_place.x ] [ new_place.y ] != ETHER ) {
212               if ( space_contents [ new_place.x ] [ new_place.y ] == KOBOLD ) {
213                  kill_kobold ( new_place );
214               } else abort_move = true;
215             }
216           }
217           if ( !abort_move ) {
218             space_contents
219               [ goblin_place [ index_goblin ].x ]
220               [ goblin_place [ index_goblin ].y ] = ETHER;
221             goblin_place [ index_goblin ].x = new_place.x;
222             goblin_place [ index_goblin ].y = new_place.y;
223             space_contents [ new_place.x ] [ new_place.y ] = GOBLIN;
224           }
225         }
226    
227         public void  goblins_move ( ) {
228         //////////////////////////////////////////////////////////////////////
229           for ( int index_goblin = 0;
230                     index_goblin < goblins_count;
231                     index_goblin++ ) {
232             if ( goblin_alive [ index_goblin ] ) {
233               goblin_move ( index_goblin );
234             }
235           }
236         }
237    
238         public Point  kobold_move_direction ( int  index_kobold ) {
239         //////////////////////////////////////////////////////////////////////
240           Point  direction = new Point ( 0, 0 );
241         //////////////////////////////////////////////////////////////////////
242           direction.x = ( int ) RandomLib.roll ( 1, 3, -2 );
243           direction.y = ( int ) RandomLib.roll ( 1, 3, -2 );
244           return new Point ( direction.x, direction.y );
245         }
246    
247         public void  kobold_move ( int  index_kobold ) {
248         //////////////////////////////////////////////////////////////////////
249           boolean  abort_move = false;
250           Point    move_direction;
251           Point    new_place = new Point ( 0, 0 );
252         //////////////////////////////////////////////////////////////////////
253           new_place.x = kobold_place [ index_kobold ].x;
254           new_place.y = kobold_place [ index_kobold ].y;
255           move_direction = kobold_move_direction ( index_kobold );
256           new_place.x += move_direction.x;
257           new_place.y += move_direction.y;
258           if ( new_place.x < lower_left.x  ) abort_move = true;
259           if ( new_place.x > upper_right.x ) abort_move = true;
260           if ( new_place.y < lower_left.y  ) abort_move = true;
261           if ( new_place.y > upper_right.y ) abort_move = true;
262           if ( !abort_move ) {
263             if ( space_contents [ new_place.x ] [ new_place.y ] != ETHER ) {
264               if ( space_contents [ new_place.x ] [ new_place.y ] == GOBLIN ) {
265                 kill_goblin ( new_place );
266               } else abort_move = true;
267             }
268           }
269           if ( !abort_move ) {
270             space_contents
271               [ kobold_place [ index_kobold ].x ]
272               [ kobold_place [ index_kobold ].y ] = ETHER;
273             kobold_place [ index_kobold ].x = new_place.x;
274             kobold_place [ index_kobold ].y = new_place.y;
275             space_contents [ new_place.x ] [ new_place.y ] = KOBOLD;
276           }
277         }
278    
279         public void  kobolds_move ( ) {
280         //////////////////////////////////////////////////////////////////////
281           for ( int index_kobold = 0;
282                     index_kobold < kobolds_count;
283                     index_kobold++ ) {
284             if ( kobold_alive [ index_kobold ] ) {
285               kobold_move ( index_kobold );
286             }
287           }
288         }
289    
290         public void kill_goblin ( Point  goblin_Point ) {
291         //////////////////////////////////////////////////////////////////////
292           for ( int index_goblin = 0;
293                     index_goblin < goblins_count;
294                     index_goblin++ ) {
295             if ( goblin_alive [ index_goblin ] ) {
296               if ( ( goblin_place [ index_goblin ].x == goblin_Point.x )
297                 && ( goblin_place [ index_goblin ].y == goblin_Point.y ) ) {
298                 goblin_alive [ index_goblin ] = false;
299                 space_contents [ goblin_Point.x ] [ goblin_Point.y ] = ETHER;
300                 goblins_alive_count--;
301                 break;
302               }
303             }
304           }
305         }
306    
307         public void kill_kobold ( Point  kobold_Point ) {
308         //////////////////////////////////////////////////////////////////////
309           for ( int index_kobold = 0;
310                     index_kobold < kobolds_count;
311                     index_kobold++ ) {
312             if ( kobold_alive [ index_kobold ] ) {
313               if ( ( kobold_place [ index_kobold ].x == kobold_Point.x )
314                 && ( kobold_place [ index_kobold ].y == kobold_Point.y ) ) {
315                 kobold_alive [ index_kobold ] = false;
316                 space_contents [ kobold_Point.x ] [ kobold_Point.y ] = ETHER;
317                 kobolds_alive_count--;
318                 break;
319               }
320             }
321           }
322         }
323    
324         public void kobolds_init ( ) {
325         //////////////////////////////////////////////////////////////////////
326           for ( int index_kobold = 0;
327                     index_kobold < kobolds_count;
328                     index_kobold++ ) {
329             do {
330               kobold_place [ index_kobold ] = new Point (
331                 ( int ) RandomLib.roll (
332                   1, upper_right.x - lower_left.x + 1, -1 ),
333                 ( int ) RandomLib.roll (
334                   1, upper_right.y - lower_left.y + 1, -1 ) );
335             } while ( space_contents
336               [ kobold_place [ index_kobold ].x ]
337               [ kobold_place [ index_kobold ].y ] != ETHER );
338             space_contents
339               [ kobold_place [ index_kobold ].x ]
340               [ kobold_place [ index_kobold ].y ] = KOBOLD;
341             kobold_alive [ index_kobold ] = true;
342           }
343         }
344    
345         public void goblins_init ( ) {
346         //////////////////////////////////////////////////////////////////////
347           for ( int index_goblin = 0;
348                     index_goblin < goblins_count;
349                     index_goblin++ ) {
350             do {
351               goblin_place [ index_goblin ] = new Point (
352                 ( int ) RandomLib.roll ( 1, upper_right.x - lower_left.x + 1, -1 ),
353                 ( int ) RandomLib.roll ( 1, upper_right.y - lower_left.y + 1, -1 ) );
354             } while ( space_contents
355               [ goblin_place [ index_goblin ].x ]
356               [ goblin_place [ index_goblin ].y ] != ETHER );
357             space_contents
358               [ goblin_place [ index_goblin ].x ]
359               [ goblin_place [ index_goblin ].y ] = GOBLIN;
360             goblin_alive [ index_goblin ] = true;
361           }
362         }
363    
364         public void init_walls ( ) {
365         //////////////////////////////////////////////////////////////////////
366           int wall_length_x = upper_right.x - lower_left.x + 1;
367           int wall_length_y = upper_right.y - lower_left.y - 1;
368         //////////////////////////////////////////////////////////////////////
369           for ( int index_wall = 0;
370                     index_wall < wall_length_x;
371                     index_wall++ ) {
372             wall_place [ index_wall ]
373               = new Point ( lower_left.x + index_wall, lower_left.y  );
374             wall_place [ index_wall + wall_length_x ]
375               = new Point ( lower_left.x + index_wall, upper_right.y );
376             space_contents
377               [ wall_place [ index_wall ].x ]
378               [ wall_place [ index_wall ].y ] = WALL;
379             space_contents
380               [ wall_place [ index_wall + wall_length_x ].x ]
381               [ wall_place [ index_wall + wall_length_x ].y ] = WALL;
382           }
383           for ( int index_wall = 0;
384                     index_wall < wall_length_y;
385                     index_wall++ ) {
386             wall_place [ index_wall + 2 * wall_length_x ]
387               = new Point ( lower_left.x, lower_left.y + 1 + index_wall );
388             wall_place [ index_wall + 2 * wall_length_x + wall_length_y ]
389               = new Point ( upper_right.x, lower_left.y + 1 + index_wall );
390             space_contents
391               [ wall_place [ index_wall + 2 * wall_length_x ].x ]
392               [ wall_place [ index_wall + 2 * wall_length_x ].y ] = WALL;
393             space_contents
394               [ wall_place [ index_wall + 2 * wall_length_x + wall_length_y ].x ]
395               [ wall_place [ index_wall + 2 * wall_length_x + wall_length_y ].y ] = WALL;
396           }
397           for ( int index_wall = walls_border_count;
398                     index_wall < walls_count;
399                     index_wall++ ) {
400             do {
401               wall_place [ index_wall ] = new Point (
402                 ( int ) RandomLib.roll ( 1, upper_right.x - lower_left.x + 1, -1 ),
403                 ( int ) RandomLib.roll ( 1, upper_right.y - lower_left.y + 1, -1 ) );
404             } while ( space_contents
405               [ wall_place [ index_wall ].x ]
406               [ wall_place [ index_wall ].y ] != ETHER );
407             space_contents
408               [ wall_place [ index_wall ].x ]
409               [ wall_place [ index_wall ].y ] = WALL;
410           }
411         }
412    
413         public boolean  mouseDown ( Event e, int x, int y ) {
414         //////////////////////////////////////////////////////////////////////
415           goblin_vision_on = !goblin_vision_on;
416    /*
417           for ( int index_bug = 0;
418                     index_bug < bugs_max;
419                     index_bug++ ) {
420             if ( bug_energy [ index_bug ] <= 0 ) {
421               double  scale_x
422                 = r.width  / ( upper_right.x - lower_left.x + 1 );
423               double  scale_y
424                 = r.height / ( upper_right.y - lower_left.y + 1 );
425               bug_location [ index_bug ]
426                 = PlotLib.graphics_to_plot_transform (
427                 new Point ( x, y ), r, this.getGraphics ( ),
428                 lower_left.x, upper_right.x, lower_left.y, upper_right.y );
429    System.out.println ( "New critter at " + bug_location [ index_bug ].x
430      + "," + bug_location [ index_bug ].y );
431               bug_energy [ index_bug ] = baby_energy;
432               for ( int index_gene = 0;
433                         index_gene < genes_max;
434                         index_gene++ ) {
435                 bug_genes_x [ index_bug ] [ index_gene ]
436                   = ( RandomLib.roll ( 1, 2, 0 ) == 1 );
437                 bug_genes_y [ index_bug ] [ index_gene ]
438                   = ( Dice.roll ( 1, 2, 0 ) == 1 );
439               }
440               break;
441             }
442           }
443    */
444           return true;
445         }
446    
447         public void  paint ( Graphics g ) {
448         //////////////////////////////////////////////////////////////////////
449           g.setColor ( java.awt.Color.black );
450           g.fillRect ( 0, 0, getSize ( ).width, getSize ( ).height );
451           g.setColor ( java.awt.Color.white );
452    //       g.drawRect ( r.x, r.y, r.width, r.height );
453           plot_kobolds ( r, g );
454           plot_goblins ( r, g );
455           plot_wall ( r, g );
456           g.drawString (
457             "Kobolds:  " + kobolds_alive_count + "    " +
458             "Goblins:  " + goblins_alive_count + "    " +
459             "Goblin vision on:  " + goblin_vision_on,
460             r.x, r.y + r.height + 10 );
461         }
462    
463         public void  plot_goblins ( Rectangle  r, Graphics  g ) {
464         //////////////////////////////////////////////////////////////////////
465           for ( int index_goblin = 0;
466                     index_goblin < goblins_count;
467                     index_goblin++ ) {
468             if ( goblin_alive [ index_goblin ] ) {
469               PlotLib.xy ( java.awt.Color.magenta,
470                 goblin_place [ index_goblin ].x,
471                 goblin_place [ index_goblin ].y,
472                 r, g,
473                 lower_left.x, upper_right.x, lower_left.y, upper_right.y,
474                 1, true );
475             }
476           }
477         }
478    
479         public void  plot_kobolds ( Rectangle  r, Graphics  g ) {
480         //////////////////////////////////////////////////////////////////////
481           for ( int index_kobold = 0;
482                     index_kobold < kobolds_count;
483                     index_kobold++ ) {
484             if ( kobold_alive [ index_kobold ] ) {
485               PlotLib.xy ( java.awt.Color.green,
486                 kobold_place [ index_kobold ].x,
487                 kobold_place [ index_kobold ].y,
488                 r, g,
489                 lower_left.x, upper_right.x, lower_left.y, upper_right.y,
490                 1, true );
491             }
492           }
493         }
494    
495         public void  plot_wall ( Rectangle  r, Graphics  g ) {
496         //////////////////////////////////////////////////////////////////////
497           for ( int index_wall = 0;
498                     index_wall < walls_count;
499                     index_wall++ ) {
500             PlotLib.xy ( java.awt.Color.gray,
501               wall_place [ index_wall ].x,
502               wall_place [ index_wall ].y,
503               r, g,
504               lower_left.x, upper_right.x, lower_left.y, upper_right.y,
505               1, true );
506           }
507         }
508    
509         //////////////////////////////////////////////////////////////////////
510         //////////////////////////////////////////////////////////////////////
511         }