code: package ontology.avatar;
  
  import java.awt.Dimension;
  import java.util.ArrayList;
  
  import core.vgdl.VGDLSprite;
  import core.competition.CompetitionParameters;
  import core.content.SpriteContent;
  import core.game.Game;
  import core.player.Player;
  import ontology.Types;
  import ontology.Types.ACTIONS;
  import tools.*;
  
  /**
   * Created with IntelliJ IDEA.
   * User: Diego
   * Date: 22/10/13
   * Time: 18:04
   * This is a Java port from Tom Schaul's VGDL - https://github.com/schaul/py-vgdl
   */
  public class MovingAvatar extends VGDLSprite {
  
      public ArrayList<Types.ACTIONS> actions;
      public ArrayList<Types.ACTIONS> actionsNIL;
      public Player player;
      private int playerID;
      private double score = 0.0;
      private Types.WINNER winState = Types.WINNER.NO_WINNER;
  
      /**
       * Disqualified flag, moved from Game class to individual players,
       * as there may be more than 1 in a game; variable still in Game
       * class for single player games to keep back-compatibility
       */
      protected boolean is_disqualified;
  
      //Avatar can have any KeyHandler system. We use KeyInput by default.
      private KeyHandler ki;
  
      public Types.MOVEMENT lastMovementType = Types.MOVEMENT.STILL;
  
      public MovingAvatar() {
      }
  
      public MovingAvatar(Vector2d position, Dimension size, SpriteContent cnt) {
          //Init the sprite
          this.init(position, size);
  
          //Specific class default parameter values.
          loadDefaults();
  
          //Parse the arguments.
          this.parseParameters(cnt);
      }
  
      protected void loadDefaults() {
          super.loadDefaults();
          actions = new ArrayList<Types.ACTIONS>();
          actionsNIL = new ArrayList<Types.ACTIONS>();
  
          color = Types.WHITE;
          speed = 1;
          is_avatar = true;
          is_disqualified = false;
      }
  
      public void postProcess() {
  
          //Define actions here first.
          if(actions.size()==0)
          {
              actions.add(Types.ACTIONS.ACTION_LEFT);
              actions.add(Types.ACTIONS.ACTION_RIGHT);
              actions.add(Types.ACTIONS.ACTION_DOWN);
              actions.add(Types.ACTIONS.ACTION_UP);
          }
  
          super.postProcess();
  
          //A separate array with the same actions, plus NIL.
          for(Types.ACTIONS act : actions)
          {
              actionsNIL.add(act);
          }
          actionsNIL.add(Types.ACTIONS.ACTION_NIL);
      }
  
      /**
       * This update call is for the game tick() loop.
       * @param game current state of the game.
       */
      public void updateAvatar(Game game, boolean requestInput, boolean[] actionMask) {
          lastMovementType = Types.MOVEMENT.STILL;
  
          Direction action;
  
          if (requestInput || actionMask == null) {
              //Sets the input mask for this cycle.
              ki.setMask(getPlayerID());
  
              //Get the input from the player.
              requestPlayerInput(game);
  
              //Map from the action mask to a Vector2D action.
              action = Utils.processMovementActionKeys(ki.getMask(), getPlayerID());
          } else {
              action = Utils.processMovementActionKeys(actionMask, getPlayerID());
          }
  
          //Apply the physical movement.
          applyMovement(game, action);
      }
  
      public void applyMovement(Game game, Direction action)
      {
      	//this.physics.passiveMovement(this);
          if (physicstype != Types.GRID)
      		super.updatePassive();
          lastMovementType = this.physics.activeMovement(this, action, speed);
      }
  
      /**
       * Requests the controller's input, setting the game.ki.action mask with the processed data.
       * @param game
       */
      protected void requestPlayerInput(Game game) {
          ElapsedCpuTimer ect = new ElapsedCpuTimer();
          ect.setMaxTimeMillis(CompetitionParameters.ACTION_TIME);
  
          Types.ACTIONS action;
          if (game.no_players > 1) {
              action = this.player.act(game.getObservationMulti(playerID), ect.copy());
          } else {
              action = this.player.act(game.getObservation(), ect.copy());
          }
          
          if(action == null){
              action = ACTIONS.ACTION_NIL;
          }
  
          if (CompetitionParameters.TIME_CONSTRAINED && ect.exceededMaxTime()) {
              long exceeded = -ect.remainingTimeMillis();
  
              if (ect.elapsedMillis() > CompetitionParameters.ACTION_TIME_DISQ) {
                  //The agent took too long to replay. The game is over and the agent is disqualified
                  System.out.println("Too long: " + playerID + "(exceeding " + (exceeded) + "ms): controller disqualified.");
                  game.disqualify(playerID);
              } else {
                  System.out.println("Overspent: " + playerID + "(exceeding " + (exceeded) + "ms): applying ACTION_NIL.");
              }
  
              action = Types.ACTIONS.ACTION_NIL;
          }
  
          if (action.equals(Types.ACTIONS.ACTION_ESCAPE)) {
              game.abort();
          } else if (!actions.contains(action)) {
              action = Types.ACTIONS.ACTION_NIL;
          }
  
          this.player.logAction(action);
          game.setAvatarLastAction(action, getPlayerID());
          ki.reset(getPlayerID());
          ki.setAction(action, getPlayerID());
      }
  
  
      public void updateUse(Game game)
      {
          //Nothing to do by default.
      }
  
      /**
       * Gets the key handler of this avatar.
       * @return - KeyHandler object.
       */
      public KeyHandler getKeyHandler() { return ki; }
  
      /**
       * Sets the key handler of this avatar.
       * @param k - new KeyHandler object.
       */
      public void setKeyHandler(KeyHandler k) {
          if (k instanceof KeyInput)
              ki = new KeyInput();
          else ki = k;
      }
  
      /**
       * Checks whether this player is disqualified.
       * @return true if disqualified, false otherwise.
       */
      public boolean is_disqualified() {
          return is_disqualified;
      }
  
      /**
       * Sets the disqualified flag.
       */
      public void disqualify(boolean is_disqualified) { this.is_disqualified = is_disqualified; }
  
      /**
       * Gets the score of this player.
       * @return score.
       */
      public double getScore() { return score; }
  
      /**
       * Sets the score of this player to a new value.
       * @param s - new score.
       */
      public void setScore(double s) { score = s; }
  
      /**
       * Adds a value to the current score of this player.
       * @param s - value to add to the score.
       */
      public void addScore (double s) { score += s; }
  
      /**
       * Gets the win state of this player.
       * @return - win state, value of Types.WINNER
       */
      public Types.WINNER getWinState() { return winState; }
  
      /**
       * Sets the win state of this player.
       * @param w - new win state.
       */
      public void setWinState(Types.WINNER w) { winState = w; }
  
  
      /**
       * Get this player's ID.
       * @return player ID.
       */
      public int getPlayerID() {
          return playerID;
      }
  
      /**
       * Set this player's ID to a new value.
       * @param id - new player ID.
       */
      public void setPlayerID(int id) {
          playerID = id;
      }
  
      public VGDLSprite copy() {
          MovingAvatar newSprite = new MovingAvatar();
          this.copyTo(newSprite);
  
          //copy player
          try {
              newSprite.player = player;
          } catch (Exception e) {e.printStackTrace();}
  
  
          return newSprite;
      }
  
      public void copyTo(VGDLSprite target) {
          MovingAvatar targetSprite = (MovingAvatar) target;
          targetSprite.actions = new ArrayList<Types.ACTIONS>();
          targetSprite.actionsNIL = new ArrayList<Types.ACTIONS>();
          targetSprite.playerID = this.playerID;
          targetSprite.winState = this.winState;
          targetSprite.score = this.score;
  
          //copy key handler
          targetSprite.setKeyHandler(this.getKeyHandler());
          
          // need to copy orientation here already because MovingAvatar.postProcess() requires the orientation
          targetSprite.orientation = this.orientation.copy();	
          
          targetSprite.postProcess();
          super.copyTo(targetSprite);
      }
  
  
  }
  