Package net.sf.robocode.battle

Source Code of net.sf.robocode.battle.BaseBattle$AbortCommand

/**
* Copyright (c) 2001-2014 Mathew A. Nelson and Robocode contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://robocode.sourceforge.net/license/epl-v10.html
*/
package net.sf.robocode.battle;


import net.sf.robocode.battle.events.BattleEventDispatcher;
import net.sf.robocode.io.Logger;
import net.sf.robocode.io.URLJarCollector;
import static net.sf.robocode.io.Logger.logError;
import static net.sf.robocode.io.Logger.logMessage;
import net.sf.robocode.settings.ISettingsManager;
import robocode.BattleRules;
import robocode.control.events.BattlePausedEvent;
import robocode.control.events.BattleResumedEvent;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;


/**
* @author Pavel Savara (original)
*/
public abstract class BaseBattle implements IBattle, Runnable {

  private final static int MAX_TPS = 10000;

  // Maximum turns to display the battle when battle ended
  protected final static int TURNS_DISPLAYED_AFTER_ENDING = 30;

  // Objects we use
  private Thread battleThread;
  IBattleManager battleManager;
  protected final BattleEventDispatcher eventDispatcher;
  private final ISettingsManager properties;

  // rules
  protected BattleRules battleRules;

  // Current round items
  private int roundNum;
  protected int currentTime;
  protected int totalTurns;

  protected int endTimer;

  // TPS (turns per second) calculation stuff
  private int tps;
  private long turnStartTime;
  private long measuredTurnStartTime;
  private int measuredTurnCounter;

  // Battle state
  private final AtomicBoolean isRunning = new AtomicBoolean(false);
  protected boolean isAborted;

  // Battle control
  protected boolean isPaused;
  private int stepCount;
  private boolean runBackward;
  private boolean roundOver;
  private final Queue<Command> pendingCommands = new ConcurrentLinkedQueue<Command>();

  protected BaseBattle(ISettingsManager properties, IBattleManager battleManager, BattleEventDispatcher eventDispatcher) {
    stepCount = 0;

    this.properties = properties;
    this.eventDispatcher = eventDispatcher;

    this.battleManager = battleManager;
  }

  public void setBattleThread(Thread newBattleThread) {
    battleThread = newBattleThread;
  }

  /**
   * Sets the roundNum.
   *
   * @param roundNum The roundNum to set
   */
  public void setRoundNum(int roundNum) {
    this.roundNum = roundNum;
  }

  /**
   * Gets the roundNum.
   *
   * @return Returns a int
   */
  public int getRoundNum() {
    return roundNum;
  }

  public int getNumRounds() {
    return battleRules.getNumRounds();
  }

  public Thread getBattleThread() {
    return battleThread;
  }

  public int getTime() {
    return currentTime;
  }

  public int getTotalTurns() {
    return totalTurns;
  }

  public boolean isLastRound() {
    return (roundNum + 1 == getNumRounds());
  }

  public int getTPS() {
    return tps;
  }

  /**
   * Informs on whether the battle is running or not.
   *
   * @return true if the battle is running, false otherwise
   */
  public boolean isRunning() {
    return isRunning.get();
  }

  /**
   * Informs on whether the battle is aborted or not.
   *
   * @return true if the battle is aborted, false otherwise
   */
  public boolean isAborted() {
    return isAborted;
  }

  public void cleanup() {
    battleRules = null;
    if (pendingCommands != null) {
      pendingCommands.clear();
      // don't pendingCommands = null;
    }
    URLJarCollector.enableGc(true);
    URLJarCollector.gc();
  }

  public void waitTillStarted() {
    synchronized (isRunning) {
      while (!isRunning.get()) {
        try {
          isRunning.wait();
        } catch (InterruptedException e) {
          // Immediately reasserts the exception by interrupting the caller thread itself
          Thread.currentThread().interrupt();

          return; // Break out
        }
      }
    }
  }

  public void waitTillOver() {
    synchronized (isRunning) {
      while (isRunning.get()) {
        try {
          isRunning.wait();
        } catch (InterruptedException e) {
          // Immediately reasserts the exception by interrupting the caller thread itself
          Thread.currentThread().interrupt();

          return; // Break out
        }
      }
    }
  }

  /**
   * When an object implementing interface {@code Runnable} is used
   * to create a thread, starting the thread causes the object's
   * {@code run()} method to be called in that separately executing
   * thread.
   * <p/>
   * The general contract of the method {@code run()} is that it may
   * take any action whatsoever.
   *
   * @see java.lang.Thread#run()
   */
  public void run() {
    try {
      initializeBattle();

      while (!isAborted && roundNum < getNumRounds()) {
        try {
          preloadRound();
          initializeRound();
          runRound();
        } catch (Exception e) {
          logError("Exception running a battle round", e);
          isAborted = true;
        } finally {
          finalizeRound();
          cleanupRound();
        }
        roundNum++;
      }
    } finally {
      finalizeBattle();
      cleanup();
    }
  }

  protected void initializeBattle() {
    URLJarCollector.enableGc(false);
    roundNum = 0;
    totalTurns = 0;

    // Notify that the battle is now running
    synchronized (isRunning) {
      isRunning.set(true);
      isRunning.notifyAll();
    }
  }

  protected void finalizeBattle() {
    // Notify that the battle is over
    synchronized (isRunning) {
      isRunning.set(false);
      isRunning.notifyAll();
    }
  }

  protected void preloadRound() {
    logMessage("----------------------");
    Logger.logMessage("Round " + (roundNum + 1) + " initializing..", false);
  }

  protected void initializeRound() {
    logMessage("");
    logMessage("Let the games begin!");

    roundOver = false;
    endTimer = 0;
    currentTime = 0;
  }

  private void runRound() {

    while (!roundOver) {
      processCommand();

      if (shouldPause() && !shouldStep()) {
        shortSleep();
        continue;
      }

      initializeTurn();

      runTurn();

      roundOver = isRoundOver();

      finalizeTurn();
    }
  }

  protected boolean isRoundOver() {
    return (endTimer > 5 * TURNS_DISPLAYED_AFTER_ENDING);
  }

  protected void finalizeRound() {}

  private void cleanupRound() {
    logMessage("Round " + (roundNum + 1) + " cleaning up.");
  }

  protected void initializeTurn() {
    turnStartTime = System.nanoTime();
  }

  protected void runTurn() {
    if (runBackward) {
      currentTime--;
      totalTurns--;
      if (currentTime == 0 && !isPaused) {
        pauseImpl();
      }
    } else {
      currentTime++;
      totalTurns++;
    }
  }

  protected void shutdownTurn() {
    endTimer++;
  }

  protected void finalizeTurn() {
    synchronizeTPS();
    calculateTPS();
  }

  private void synchronizeTPS() {
    // Let the battle sleep is the GUI is enabled and is not minimized
    // in order to keep the desired TPS

    if (battleManager.isManagedTPS()) {
      long delay = 0;

      if (!isAborted() && endTimer < TURNS_DISPLAYED_AFTER_ENDING) {
        int desiredTPS = properties.getOptionsBattleDesiredTPS();

        if (desiredTPS < MAX_TPS) {
          long deltaTime = System.nanoTime() - turnStartTime;

          delay = Math.max(1000000000 / desiredTPS - deltaTime, 0);
        }
      }
      if (delay > 500000) { // sleep granularity is worse than 500000
        try {
          Thread.sleep(delay / 1000000, (int) (delay % 1000000));
        } catch (InterruptedException e) {
          // Immediately reasserts the exception by interrupting the caller thread itself
          Thread.currentThread().interrupt();
        }
      }
    }
  }

  private void calculateTPS() {
    // Calculate the current turns per second (TPS)

    if (measuredTurnCounter++ == 0) {
      measuredTurnStartTime = turnStartTime;
    }

    long deltaTime = System.nanoTime() - measuredTurnStartTime;

    if (deltaTime / 500000000 >= 1) {
      tps = (int) (measuredTurnCounter * 1000000000L / deltaTime);
      measuredTurnCounter = 0;
    }
  }

  private boolean shouldPause() {
    return (isPaused && !isAborted);
  }

  private boolean shouldStep() {
    if (stepCount > 0) {
      stepCount--;
      return true;
    }
    return false;
  }

  // --------------------------------------------------------------------------
  // Processing and maintaining robot and battle controls
  // --------------------------------------------------------------------------

  protected void sendCommand(Command command) {
    pendingCommands.add(command);
  }

  private void processCommand() {
    Command command = pendingCommands.poll();

    while (command != null) {
      try {
        command.execute();
      } catch (Exception e) {
        logError(e);
      }
      command = pendingCommands.poll();
    }
  }

  public void stop(boolean waitTillEnd) {
    sendCommand(new AbortCommand());

    if (waitTillEnd) {
      waitTillOver();
    }
  }

  public void pause() {
    sendCommand(new PauseCommand());
  }

  public void resume() {
    sendCommand(new ResumeCommand());
  }

  public void step() {
    sendCommand(new StepCommand());
  }

  protected void stepBack() {
    sendCommand(new StepBackCommand());
  }

  private class PauseCommand extends Command {
    public void execute() {
      pauseImpl();
    }

  }

  private void pauseImpl() {
    isPaused = true;
    stepCount = 0;
    eventDispatcher.onBattlePaused(new BattlePausedEvent());
  }

  private class ResumeCommand extends Command {
    public void execute() {
      isPaused = false;
      stepCount = 0;
      eventDispatcher.onBattleResumed(new BattleResumedEvent());
    }
  }


  private class StepCommand extends Command {
    public void execute() {
      runBackward = false;
      if (isPaused) {
        stepCount++;
      }
    }
  }


  private class StepBackCommand extends Command {
    public void execute() {
      runBackward = true;
      if (isPaused) {
        stepCount++;
      }
    }
  }


  private class AbortCommand extends Command {
    public void execute() {
      isAborted = true;
    }
  }


  protected class RobotCommand extends Command {
    protected final int robotIndex;

    protected RobotCommand(int robotIndex) {
      this.robotIndex = robotIndex;
    }
  }

  //
  // Utility
  //

  private void shortSleep() {
    try {
      Thread.sleep(100);
    } catch (InterruptedException e) {
      // Immediately reasserts the exception by interrupting the caller thread itself
      Thread.currentThread().interrupt();
    }
  }
}
TOP

Related Classes of net.sf.robocode.battle.BaseBattle$AbortCommand

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.