Advertisement
Guest User

Kissat ja hiiret speksin mukaan

a guest
Jan 11th, 2012
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 14.66 KB | None | 0 0
  1. package fpchallenge;
  2.  
  3. import java.lang.management.ManagementFactory;
  4. import java.lang.management.OperatingSystemMXBean;
  5. import java.lang.management.RuntimeMXBean;
  6. import java.text.DateFormat;
  7. import java.text.SimpleDateFormat;
  8. import java.util.ArrayList;
  9. import java.util.Collection;
  10. import java.util.Collections;
  11. import java.util.Comparator;
  12. import java.util.Date;
  13. import java.util.HashMap;
  14. import java.util.List;
  15. import java.util.Map;
  16. import java.util.Random;
  17. import java.util.Timer;
  18. import java.util.TimerTask;
  19. import java.util.concurrent.ExecutorService;
  20. import java.util.concurrent.Executors;
  21. import java.util.concurrent.TimeUnit;
  22. import java.util.concurrent.atomic.AtomicInteger;
  23.  
  24. public class MazeTest {
  25.     public static void main(String[] args) throws InterruptedException {
  26.         Maze maze = new Maze( 10,10,false );
  27.         for( int i = 0; i < 15; i++ )
  28.             maze.enter( new Cat( maze ) );
  29.         for( int i = 0; i < 45; i++ )
  30.             maze.enter( new Rat( maze ) );
  31.         for( int i = 0; i < 5; i++ )
  32.             maze.enter( new Dog( maze ) );
  33.         maze.start( );
  34.         Thread.sleep( 10000 );
  35.         maze.stop( 5,TimeUnit.SECONDS );   
  36.     }
  37. }
  38.  
  39. // Maze.java
  40.  
  41. class Maze {
  42.     private static class Room {
  43.         final Location location;
  44.         Animal animal;
  45.        
  46.         Room( Location location ) {
  47.             this.location = location;
  48.         }
  49.        
  50.         public String toString( ) {
  51.             return animal != null ? animal.toString( ) : "N/A" + " at " + location;
  52.         }
  53.     }
  54.    
  55.     private static class MazeEvent {
  56.         private static final AtomicInteger nextOrdinal = new AtomicInteger( );
  57.         private final String message;
  58.         private final Date timestamp;
  59.         private final int ordinal;
  60.  
  61.         MazeEvent( String message ) {
  62.             this.message = message;
  63.             timestamp = new Date( );
  64.             ordinal = nextOrdinal.incrementAndGet( );
  65.         }
  66.        
  67.         @Override
  68.         public String toString( ) {
  69.             DateFormat df = new SimpleDateFormat( "HH:mm:ss.SSS" );
  70.             return String.format( "Event %5d at %s %s",ordinal,df.format( timestamp ), message );
  71.         }
  72.     }
  73.  
  74.     private final int width;
  75.     private final int height;
  76.     private final Map<Location,Room> rooms;
  77.     private ExecutorService threads;
  78.     private final Random random = new Random( System.currentTimeMillis( ) );
  79.     private final List<MazeEvent> events = new ArrayList<MazeEvent>( );
  80.     private final Collection<Animal> animals = new ArrayList<Animal>( );
  81.     private final AtomicInteger animalCount = new AtomicInteger( );
  82.     private final boolean predatorsAnnihilateOnCollission;
  83.    
  84.     Maze( int width,int height,boolean predatorsAnnihilateOnCollission ) {
  85.         this.width = width;
  86.         this.height = height;
  87.         this.predatorsAnnihilateOnCollission = predatorsAnnihilateOnCollission;
  88.         rooms = new HashMap<Location,Room>( );
  89.         for( int x = 0; x < width; x++ )
  90.              for( int y = 0; y < height; y++ )
  91.                  rooms.put( new Location( x,y ),new Room( new Location( x,y ) ) );
  92.     }
  93.  
  94.     void logEvent( String message ) {
  95.         synchronized( events ) {
  96.             events.add( new MazeEvent( message ) );
  97.         }
  98.     }
  99.    
  100.     public int getWidth( ) {
  101.         return width;
  102.     }
  103.    
  104.     public int getHeight( ) {
  105.         return height;
  106.     }
  107.    
  108.     synchronized boolean moveTo( Animal animal,Location currLocation,Location newLocation ) {
  109.         // Dead animals do not move
  110.         if( ! animal.isAlive( ) || newLocation.equals( currLocation ) )
  111.             return false;
  112.        
  113.         Room newRoom = rooms.get( newLocation );
  114.         Room currRoom = rooms.get( currLocation );
  115.        
  116.         if( animal != newRoom.animal ) {
  117.             if( newRoom.animal == null ) {
  118.                 newRoom.animal = animal;
  119.                 currRoom.animal = null;
  120.                 logEvent( animal + " moved from " + currLocation + " to " + newLocation );
  121.                 return true;
  122.             }
  123.             // Two non-predators cannot fit the same room, prevent movement
  124.             if( ! newRoom.animal.isPredator( ) && ! animal.isPredator( ) )
  125.                 return false;
  126.            
  127.             // Both are predators, they annihilate each other
  128.             if( newRoom.animal.isPredator( ) && animal.isPredator( ) ) {
  129.                 if( predatorsAnnihilateOnCollission ) {
  130.                     logEvent( animal + " moved from " + currLocation + " to " + newLocation );
  131.                     logEvent( animal + " and " + newRoom.animal + " annihilated each other at location " + newRoom.location );
  132.                     ( ( AbstractAnimal ) animal ).killed( newRoom.animal );
  133.                     ( ( AbstractAnimal ) newRoom.animal ).killed( animal );
  134.                     ( ( AbstractAnimal ) newRoom.animal ).setTerminated( newRoom.location );
  135.                     ( ( AbstractAnimal ) animal ).setTerminated( currRoom.location );
  136.                     return true;
  137.                 }
  138.                 else
  139.                     return false;
  140.             }
  141.             // Only one of two is a predator
  142.             else if( newRoom.animal.isPredator( ) || animal.isPredator( ) ) {
  143.                 logEvent( animal + " moved from " + currLocation + " to " + newLocation );
  144.                 //dumpMaze( animal,newRoom.animal );
  145.                 if( animal.isPredator( ) ) {
  146.                     logEvent( newRoom.animal + " was killed by " + animal + " at location " + newRoom.location );
  147.                     ( ( AbstractAnimal ) newRoom.animal ).setTerminated( newRoom.location );
  148.                     ( ( AbstractAnimal ) animal ).killed( newRoom.animal );
  149.                     currRoom.animal = null;
  150.                     newRoom.animal = animal;
  151.                 }
  152.                 else {
  153.                     logEvent( animal + " was killed by " + newRoom.animal + " at location " + newRoom.location );
  154.                     ( ( AbstractAnimal ) newRoom.animal ).killed( animal );
  155.                     ( ( AbstractAnimal ) animal ).setTerminated( currRoom.location );
  156.                 }
  157.                 return true;
  158.             }
  159.            
  160.             return true;
  161.         }
  162.        
  163.         return false;
  164.     }
  165.  
  166.     synchronized void animalDestroyed( Animal animal,Location atLocation ) {
  167.         Room room = rooms.get( atLocation );
  168.         if( room.animal == animal ) {
  169.             room.animal = null;
  170.             animalCount.decrementAndGet( );
  171.             logEvent( "Destroyed " + animal + " at " + room.location );
  172.         }
  173.     }
  174.    
  175.     synchronized Location getInitialLocation( Animal animal ) {
  176.         // First try random (x,y)
  177.         int randomX = width - random.nextInt( width ) - 1;
  178.         int randomY = height - random.nextInt( height ) - 1;
  179.         Location location = new Location( randomX,randomY );
  180.         Room room = rooms.get( location );
  181.         if( room.animal == null ) {
  182.             room.animal = animal;
  183.             animalCount.incrementAndGet( );
  184.             return location;
  185.         }
  186.        
  187.         // No luck, then try brute force
  188.         for( int x = 0; x < width; x++ ) {
  189.             for( int y = 0; y < height; y++ ) {
  190.                 location = new Location( x,y );
  191.                 room = rooms.get( location );
  192.                 if( room != null && room.animal == null ) {
  193.                     room.animal = animal;
  194.                     animalCount.incrementAndGet( );
  195.                     return location;
  196.                 }      
  197.             }
  198.         }
  199.        
  200.         throw new IllegalStateException( "No free locations available" );
  201.     }
  202.  
  203.     public void enter( Animal animal ) {
  204.         if( animals.size( ) == width * height )
  205.             throw new IllegalStateException( "No free locations available" );
  206.        
  207.         animals.add( animal );
  208.     }
  209.    
  210.     public synchronized void start( ) {
  211.         OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean( );
  212.         int nop = osBean.getAvailableProcessors( );
  213.         logEvent(   "Running " + animals.size( ) + " threads concurrently" );
  214.         logEvent( "Number of cores is " + nop + " and thus true parallelism degree is restricted to " + nop );
  215.         logEvent( "Predators annihilate each other on collission is set to " + predatorsAnnihilateOnCollission );
  216.         threads = Executors.newFixedThreadPool( animals.size( ) );
  217.         for( Animal animal : animals )
  218.             threads.submit( ( AbstractAnimal ) animal );
  219.         animals.clear( );
  220.     }
  221.    
  222.     public void stop( long timeout,TimeUnit tu ) throws InterruptedException {
  223.         threads.shutdownNow( );
  224.         threads.awaitTermination( timeout,tu );
  225.         synchronized( events ) {
  226.             Collections.sort( events,
  227.                     new Comparator<MazeEvent>( ) {
  228.                         @Override
  229.                         public int compare( MazeEvent e1,MazeEvent e2 ) {
  230.                             return ( int ) ( e1.ordinal - e2.ordinal );
  231.                         }
  232.                     }
  233.             );
  234.             for( MazeEvent event : events ) {
  235.                 System.out.println( event );
  236.             }
  237.         }
  238.            
  239.         System.out.println( "\nGame Over. Survived animals (" + animalCount.get() + ") are: " );
  240.         synchronized( this ) {
  241.             for( Room room : rooms.values( ) ) {
  242.                 if( room.animal != null ) {
  243.                     if( ! room.animal.isAlive( ) )
  244.                         System.out.println( room.animal + " is terminated so this is a BUG" );
  245.                     else {
  246.                         AbstractAnimal animal = ( AbstractAnimal ) room.animal;
  247.                         if( animal.isPredator( ) ) {
  248.                             System.out.println( animal + " at location " + room.location +
  249.                                                 ". Killed " + animal.getNumberOfKilledAnimals( ) +
  250.                                                 " animal(s)." );
  251.                         }
  252.                         else
  253.                             System.out.println( animal + " at location " + room.location );
  254.                     }
  255.                 }
  256.             }
  257.         }
  258.         RuntimeMXBean rtbean = ManagementFactory.getRuntimeMXBean( );
  259.         System.out.println( "\nJVM uptime upon terminatation is " + rtbean.getUptime( ) + " ms" );
  260.     }
  261. }
  262.  
  263. // Animal.java (not useful in this case, but ..)
  264.  
  265. interface Animal {
  266.     public Location getLocation( );
  267.     public boolean isPredator( );
  268.     public boolean isAlive( );
  269. }
  270.  
  271. // AbstractAnimal.java
  272.  
  273. abstract class AbstractAnimal implements Animal, Runnable {
  274.     private final Maze maze;
  275.     private final Random random = new Random( System.nanoTime( ) );
  276.     private volatile Location location;
  277.     private volatile boolean terminated;
  278.     private final int minThinkTime;
  279.     private final int maxThinkTime;
  280.     private AtomicInteger killedAnimals = new AtomicInteger( );
  281.    
  282.     public AbstractAnimal( Maze maze ) {
  283.         this( maze,100,1000 );
  284.     }
  285.  
  286.     public AbstractAnimal( Maze maze,int minThinkTime,int maxThinkTime ) {
  287.         this.maze = maze;
  288.         this.minThinkTime = minThinkTime;
  289.         this.maxThinkTime = maxThinkTime;
  290.     }
  291.  
  292.     protected Maze getMaze( ) {
  293.         return maze;
  294.     }
  295.    
  296.     protected long getRandom( int low,int high ) {
  297.         return low + random.nextInt( high - low );
  298.     }
  299.    
  300.     public Location getLocation( ) {
  301.         return location;
  302.     }
  303.  
  304.     void killed( Animal animal ) {
  305.         killedAnimals.incrementAndGet( );
  306.     }
  307.    
  308.     public int getNumberOfKilledAnimals( ) {
  309.         return killedAnimals.get( );
  310.     }
  311.    
  312.     void setTerminated( Location atLocation ) {
  313.         if( isAlive( ) ) {
  314.             terminated = true;
  315.             location = atLocation;
  316.             maze.animalDestroyed( this,atLocation );
  317.         }
  318.     }
  319.    
  320.     public boolean isAlive( ) {
  321.         return ! terminated;
  322.     }
  323.  
  324.     @Override
  325.     public void run( ) {
  326.         try {
  327.             location = maze.getInitialLocation( this );
  328.             maze.logEvent( "Initial location of " + this + " is set to " + location );
  329.            
  330.             while( isAlive( ) ) {
  331.                 move( );
  332.                 if( isAlive( ) ) {
  333.                     long thinkTime = getRandom( minThinkTime,maxThinkTime );
  334.                     maze.logEvent( this + " thinking " + thinkTime + " millisecs before next move" );
  335.                     Thread.sleep( thinkTime );
  336.                 }
  337.             }
  338.         }
  339.         catch( IllegalStateException e ) {
  340.             maze.logEvent( this + " couldn't enter the maze due to exception: " + e );
  341.         }
  342.         catch( InterruptedException e ) {
  343.             Thread.currentThread().interrupt( );
  344.         }
  345.         maze.logEvent( "Thread " + Thread.currentThread( ).getName( ) + " serving " + this + " is returned to the pool" );
  346.     }
  347.    
  348.     private void move( ) {
  349.         // Get stable reference
  350.         Location l = location;
  351.         int x = l.x;
  352.         int y = l.y;
  353.         int direction = random.nextInt( 8 );
  354.         for( int i = 0; i < 4; i++, direction++ ) {
  355.             switch( direction % 8 ) {
  356.                 case 0 :
  357.                     // North
  358.                     y = l.y > 0 ? l.y - 1 : l.y;
  359.                     break;
  360.                 case 1 :
  361.                     // South
  362.                     y = l.y < ( maze.getHeight( ) - 1 ) ? l.y + 1 : l.y;
  363.                     break;
  364.                 case 2 :
  365.                     // West
  366.                     x = l.x > 0 ? l.x - 1 : l.x;
  367.                     break;
  368.                 case 3 :
  369.                     // East
  370.                     x = l.x < ( maze.getWidth( ) - 1 ) ? l.x + 1 : l.x;
  371.                     break;
  372.                 case 4 :
  373.                     // North-east
  374.                     x = l.x < ( maze.getWidth( ) - 1 ) ? l.x + 1 : l.x;
  375.                     y = l.y < ( maze.getHeight( ) - 1 ) ? l.y + 1 : l.y;
  376.                     break;
  377.                 case 5 :
  378.                     // North-west
  379.                     x = l.x > 0 ? l.x - 1 : 0;
  380.                     y = l.y < ( maze.getHeight( ) - 1 ) ? l.y + 1 : l.y;
  381.                     break;                 
  382.                 case 6 :
  383.                     // South-west
  384.                     x = l.x > 0 ? l.x - 1 : l.x;
  385.                     y = l.y > 0 ? l.y - 1 : l.y;
  386.                     break;
  387.                 case 7 :
  388.                     // South-east
  389.                     x = l.x < ( maze.getWidth( ) - 1 ) ? l.x + 1 : l.x;
  390.                     y = l.y > 0 ? l.y - 1 : l.y;
  391.                     break;
  392.                 default :
  393.                     throw new RuntimeException( "This is a bug" );
  394.             }
  395.  
  396.             Location newLocation = new Location( x,y );
  397.             Location currLocation = location;
  398.             location = newLocation;
  399.             if( maze.moveTo( this,currLocation,newLocation ) ) {
  400.                 location = newLocation;
  401.                 break;
  402.             }
  403.             else {
  404.                 // If movement fails
  405.                 location = currLocation;
  406.             }
  407.         }
  408.         if( location == l && isAlive( ) )
  409.             maze.logEvent( this + " couln't move due to congestion near location " + location );
  410.     }
  411. }
  412.  
  413. // Location.java
  414.  
  415. class Location {
  416.     public final int x, y;
  417.    
  418.     Location( int x,int y ) {
  419.         this.x = x;
  420.         this.y = y;
  421.     }
  422.  
  423.     @Override
  424.     public String toString( ) {
  425.         return "(" + x + ", " + y + ")";
  426.     }
  427.    
  428.     @Override
  429.     public int hashCode() {
  430.         final int prime = 31;
  431.         int result = 1;
  432.         result = prime * result + x;
  433.         result = prime * result + y;
  434.         return result;
  435.     }
  436.  
  437.     @Override
  438.     public boolean equals(Object obj) {
  439.         if (this == obj)
  440.             return true;
  441.         if (obj == null)
  442.             return false;
  443.         if (getClass() != obj.getClass())
  444.             return false;
  445.         Location other = (Location) obj;
  446.         if (x != other.x)
  447.             return false;
  448.         if (y != other.y)
  449.             return false;
  450.         return true;
  451.     }
  452. }
  453.  
  454. // Cat.java
  455.  
  456. class Cat extends AbstractAnimal {
  457.     private static final AtomicInteger ordinals = new AtomicInteger( );
  458.     private final int id;
  459.  
  460.     public Cat( Maze maze ) {
  461.         super( maze );
  462.         id = ordinals.incrementAndGet( );
  463.     }
  464.  
  465.     @Override
  466.     public boolean isPredator( ) {
  467.         return true;
  468.     }
  469.    
  470.     @Override
  471.     public String toString( ) {
  472.         return "Cat " + id;
  473.     }
  474. }
  475.  
  476. // Rat.java
  477.  
  478. class Rat extends AbstractAnimal {
  479.     private static final AtomicInteger ordinals = new AtomicInteger( );
  480.     private final int id;
  481.    
  482.     public Rat( Maze maze ) {
  483.         super( maze );
  484.         id = ordinals.incrementAndGet( );
  485.     }
  486.  
  487.     @Override
  488.     public boolean isPredator( ) {
  489.         return false;
  490.     }
  491.  
  492.     @Override
  493.     public String toString( ) {
  494.         return "Rat " + id;
  495.     }
  496. }
  497.  
  498. // Dog.java
  499.  
  500. class Dog extends AbstractAnimal {
  501.     private static final AtomicInteger ordinals = new AtomicInteger( );
  502.     private final int id;
  503.     private final long maxLifeTime;
  504.     private final Timer timer = new Timer( );
  505.  
  506.     public Dog( Maze maze ) {
  507.         super( maze );
  508.         id = ordinals.incrementAndGet( );
  509.         maxLifeTime = getRandom( 2000,20000 );
  510.     }
  511.  
  512.     @Override
  513.     void setTerminated( Location atLocation ) {
  514.         timer.cancel( );
  515.         super.setTerminated( atLocation );
  516.     }
  517.    
  518.     @Override
  519.     public void run( ) {
  520.         timer.schedule(
  521.                 new TimerTask( ) {
  522.                     @Override
  523.                     public void run() {
  524.                         getMaze( ).logEvent( Dog.this + " is dying since maximum life time " + maxLifeTime + " ms has now elapsed. Killed " +
  525.                                             getNumberOfKilledAnimals( ) + " animals." );
  526.                         setTerminated( getLocation( ) );
  527.                     }                  
  528.                 },
  529.                 maxLifeTime
  530.         );
  531.         super.run( );
  532.     }
  533.  
  534.     @Override
  535.     public boolean isPredator( ) {
  536.         return true;
  537.     }
  538.    
  539.     @Override
  540.     public String toString( ) {
  541.         return "Dog " + id;
  542.     }
  543. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement