import java.awt.*;
import java.io.*;
import AgentWorld.*;

// The 'main' class for running the 'Agent World' of CS 540 and CS 760.
//
//   - copyrighted 1997, 1998 by Jude Shavlik
//     (for educational use only)
//

// YOU SHOULD MAKE YOUR OWN COPY OF THIS FILE AND EDIT IT TO USE
// YOUR OWN PLAYER (AS WELL AS YOUR OWN CHOICE OF OTHER PLAYERS).

// Be sure (in Unix) to add the following to your ~/.cshrc.local file
// in order to have Java find your class files and the AgentWorld package:
//
//   setenv CLASSPATH .:./classes:/p/course/cs540-shavlik/public/AgentWorld/Packages
//
// On platforms other than the course computers, you'll have to copy 
// those files over to your machine and make sure these files are in 
// a classes directory that Java searches.
// You can access these class files via 
//
//     http://www.cs.wisc.edu/~shavlik/cs540/AgentWorld/Packages
//
// (this is a WWW link to that /p/course/cs540-shavlik/... directory listed above).

public class RunAgentWorld 
{
  public static void main(String args[])
  { boolean barrenWorld = false; // For debugging purposes, it can be helpful to
                                 // set this true and only have your own player
                                 // out there.

    boolean sparseWorld = true;  // For slower computers, have less objects 
                                 // in the world (the dimensions of the
                                 // world can't be changed).

    try 
    { // Need an AgentWindow instance with which to communicate.
      // This argument indicates whether the game is being displayed.
      // (you might wish to turn this off in the machine learning HW
      // to conserve cpu cycles for training).
      AgentWindow aw = new AgentWindow(true);

      // Create some 'baby' players that simply do random walks.
      // Notice you can specify the colors for players,
      // which will otherwise default depending on the player type.
      if (!barrenWorld && !sparseWorld) aw.addRandomWalker("Alice", Color.pink);
      if (!barrenWorld && !sparseWorld) aw.addRandomWalker("Bob",   Color.cyan);

      // Create a malicious player that chases other players.
      if (!barrenWorld) aw.addAssassin("The Jackal");
 
      // This next player will follow the mouse whenever 
      // the mouse button is down.
      // (You may wish to only display what this player sees, and then see
      // how high you can score by guiding it from its perspective.
      // The ability to maneuver a player is also useful for debugging.)
      if (!barrenWorld) aw.addFollowMousePlayer("The Pied Piper"); 

      // Here's how you'll hook up your player.
      // Name your class <LOGIN>Player, where <LOGIN> is replaced with
      // you login on the course computers - this will allow us
      // to mix-and-match players w/o having to worry about name conflicts,
      // e.g., I'd call mine ShavlikPlayer and create the file ShavlikPlayer.java.
      //
      // Below is a sample player that shows how one's code interacts with
      // the Agent World.  You can view this file at
      //
      //    /p/course/cs760-shavlik/public/AgentWorld/Java/SamplePlayer.java
      //
      //        or
      //
      //    http://cs.wisc.edu/~shavlik/cs540/AgentWorld/Java/SamplePlayer.java
      //
      // to see how the sensors are read, rewards received, etc.  You should
      // also look at Utils.java in that same directory; it contains some
      // possibly useful utility functions.
      //
      // Also, start with the sensors being displayed (hence, the 'true'
      // - you'll probably want to delete this 'true' and instead show
      // the sensors for your OWN agent).
      if (!barrenWorld) aw.addPlayer(new SamplePlayer(aw, true),
                                     "a Sample Player", Color.blue);

      // Below is how you'll add your own player.  Of course, feel
      // free to change the player's name and color.  (When you're
      // using your own player, you might want to commment-out the
      // previous command that added the SamplePlayer.)
      //
      // aw.addPlayer(new <YourLoginName>Player(aw, true),
      //                  "<YourLoginName>'s Player", Color.magenta);

      // The following is a semi-clever, hand-coded player.
      if (!barrenWorld) aw.addPlayer(new ShavlikPlayer(aw),
                                     "a Smart Player",  Color.yellow);

      // The following player has been trained, "from scratch,"
      // using artificial neural networks (ANNs) and a machine learning method
      // called "reinforcement learning."
      if (!barrenWorld && !sparseWorld)
      { String neuralNetworkFileName = "savedShavlikNetwork.jws";

        // The above file MUST EXIST IN THE DIRECTORY FROM WHICH YOU INVOKE JAVA
        // OR OTHERWISE THIS PLAYER WILL NOT BE CREATED.
        // This design is a bit crude, but it allows for portability.
        // On the course machines, you can replace the above with the 
        // following full pathname, if you wish:
        //
        //    /p/course/cs540-shavlik/public/AgentWorld/savedShavlikNetwork.jws
        //
        // (Oddity: this works fine in Solaris and WinNT but NOT WIn95???)
        if (neuralNetworkFileName != null &&
            ((new File(neuralNetworkFileName)).exists()))
        {
          aw.addPlayer(new ShavlikANNplayer(aw, neuralNetworkFileName),
                       "ML-Trained Player", Color.orange);
        }
        else if (neuralNetworkFileName != null)
        {
          Utils.println("The file " + neuralNetworkFileName + " cannot be found.");
        }
      }

      // Add some players whose scores aren't reported on the score board.
      if (!barrenWorld)
      {
        if (sparseWorld) aw.addAnonymousAssassins(1);
        else aw.addAnonymousAssassins(2);
      }
      if (!barrenWorld && !sparseWorld) aw.addAnonymousRandomWalkers(1);
      if (!barrenWorld && !sparseWorld) aw.addAnonymousSmartPlayers(1);
      // (Actually, the AnonymousSmartPlayers are more copies of ShavlikPlayer).
 
      // Can't have more than 100 of either of the following,
      // nor more than 25 players.
      if (!barrenWorld)
      {
        if (sparseWorld) aw.addMinerals(  50); else aw.addMinerals(100);
      }
      if (!barrenWorld)
      {
        if (sparseWorld) aw.addVegetables(50); else aw.addVegetables(100);
      }

      // At some point we may try to have a competition among the 
      // players produced by various students.  Since the
      // training and 'testing' environments, should be approximately
      // equivalent, we'll define the basic initial configuration to have:
      //
      //          5 Players (with at least 1 Assassin's & 0 FollowMouse's)
      //         50 Minerals
      //         50 Vegetables
      //
      // Of course the intelligence of the players will vary from the above
      // when competing against players of various students.
      // WE'LL POST MORE INFO ABOUT COMBINING PLAYERS OF MULTIPLE STUDENTS
      // ON THE CLASS HOME PAGE (http://www.cs.wisc.edu/~shavlik/cs540.html).

      // The "game manager" sleeps at most this long (in msec) for all the 
      // players to choose their moves.  Players that aren't ready continue
      // in the same direction as their last choice. You may wish to adjust
      // this depending on the speed of your code/machine and the number of
      // players.  (If all players are ready, the simulator proceeds without
      // waiting for the duration to expire, so it isn't too harmful to set
      // this high.  However, the player threads seem to occassionally die/hang
      // for no [obvious] reason; if a player times-out too many times in a row,
      // its thread will automatically be recreated - a low time-out
      // causes this detection and restarting to be accomplished faster.)
      aw.setClockPeriod(150);

      // You can request that the 'manager' wait for you to 
      // press GO before each move.
      aw.setSingleStepMode(false); // The default setting is also false.

      // The following will play the specified number of games,
      // where each game last for the stated number of steps.
      // Each game starts in a new randomized initial configuration.
      // The mean score is reported for each player at the end.
      // We'll say that games always end after 5000 units of time,
      // since the optimal behavior depends on game length.
      // (This command also automatically pushes the Start button.)
      if (!barrenWorld) aw.playThisManyGamesEachOfThisManyTimeSteps(1000, 5000);

      // If the above line is commented out, then you can create
      // the initial configuration before pushing the Start button.
    }
    
    catch(Exception e)
    {
      Utils.println("Exception encountered in main method: " + e);
      Utils.println("The following indicates the location of the problem:");
      e.printStackTrace(System.err);
      Utils.exit(-1);
    }
  }

}
