Package com.drakulo.games.ais.core

Source Code of com.drakulo.games.ais.core.GameEngine

package com.drakulo.games.ais.core;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.drakulo.games.ais.core.audio.SoundHelper;
import com.drakulo.games.ais.core.building.Building;
import com.drakulo.games.ais.core.building.BuildingHelper;
import com.drakulo.games.ais.core.building.BuildingType;
import com.drakulo.games.ais.core.delayed.BuildingAction;
import com.drakulo.games.ais.core.delayed.HexagonMapAction;
import com.drakulo.games.ais.core.delayed.PreparationAction;
import com.drakulo.games.ais.core.delayed.ResearchAction;
import com.drakulo.games.ais.core.delayed.ColonyAction;
import com.drakulo.games.ais.ui.TileHelper;

/**
* <h1>The game engine</h1>
* <p>
* The game engine is the game's core. It handle all game logic. A call to the
* run method run will handle a loop of all game logic. Time between calls must
* be handled out of the engine.
* </p>
*
* @author Drakulo
*
*/
public final class GameEngine {
  /** Time since last update to perform a call to the game engine each second */
  private static int timeSinceGameUpdate = 0;

  /**
   * private constructor to force static use
   */
  private GameEngine() {
    // Nothing there
  }

  /**
   * This method lunches the game logic. Called once per second. Handle heavy
   * logic
   */
  public static void run(int delta) {
    // First, handle the colony pool
    Colony colony = null;
    do {
      colony = GameData.popColonyFromPool();
      if (colony != null) {
        GameData.addColony(colony);
      }
    } while (colony != null);

    // A call to the game logic must be done only once per
    // second.
    if (timeSinceGameUpdate >= 1000) {
      timeSinceGameUpdate = 0;
      List<Colony> colonies = GameData.getColonies();
      // System.out.println("Colonies to update : " + colonies.size());
      for (Colony c : colonies) {
        // System.out.println("Update for colony : " + c.getName());
        // Construction / update process
        buildingProcess(c);

        // Robots progress
        robotProcess(c);

        // Special actions process
        specialActionProcess(c);

        // Production process
        productionProcess(c);

        // Research progression
        researchProcess(c);

        // 3. Diplomacy TODO
        // 4. Battles TODO
      }

      // Exploration actions
      explorationActionsProcess();
    } else {
      // Wait for next second
      timeSinceGameUpdate += delta;
    }

  }

  /**
   * This method handle the robot progress
   */
  private static void explorationActionsProcess() {
    List<HexagonMapAction> actions = GameData.getHexagonMapActions();
    List<HexagonMapAction> actionsToRemove = new ArrayList<HexagonMapAction>();
    for (HexagonMapAction action : actions) {
      action.step();
      if (action.isDone()) {
        // The action is done so we have to remove it from the list.
        actionsToRemove.add(action);
      }
    }

    // All actions were processed. If there is some finished actions, we
    // remove them from the action list
    if (!actionsToRemove.isEmpty()) {
      for (HexagonMapAction action : actionsToRemove) {
        actions.remove(action);
        action.runCallback();
      }
    }
  }

  /**
   * This method handle the robot progress
   */
  private static void specialActionProcess(Colony c) {
    List<ColonyAction> actions = c.getSpecialActions();
    List<ColonyAction> actionsToRemove = new ArrayList<ColonyAction>();
    for (ColonyAction action : actions) {
      action.step();
      if (action.isDone()) {
        // The action is done so we have to remove it from the list.
        actionsToRemove.add(action);
      }
    }

    // All actions were processed. If there is some finished actions, we
    // remove them from the action list
    if (!actionsToRemove.isEmpty()) {
      for (ColonyAction action : actionsToRemove) {
        actions.remove(action);
        action.runCallback();
      }
    }
  }

  /**
   * This method handle the robot progress
   */
  private static void robotProcess(Colony c) {
    List<PreparationAction> actions = c.getPreparationActions();
    List<PreparationAction> actionsToRemove = new ArrayList<PreparationAction>();
    for (PreparationAction action : actions) {
      action.step();
      if (action.isDone()) {
        // The action is done so we have to remove it from the list.
        actionsToRemove.add(action);

        // The preparation is done. The tile have to be modified
        TileHelper.setTile(action.getX(), action.getY(),
            TileHelper.BUILDABLE_TILE, c);
        c.releaseRobots(1);
      }
    }

    // All actions were processed. If there is some finished actions, we
    // remove them from the action list
    if (!actionsToRemove.isEmpty()) {
      for (PreparationAction action : actionsToRemove) {
        actions.remove(action);
        action.runCallback();
      }
    }
  }

  /**
   * This method handle research steps
   */
  private static void researchProcess(Colony c) {
    ResearchAction research = c.getResearch();
    // If the research is null, that's because the player didn't started a
    // research. In that case, there is nothing to do.
    if (research != null) {
      research.step();
      if (research.isDone()) {
        // The research is done.
        research.getTechnology().setOwned(true);
        c.setResearch(null);
      }
    }
  }

  /**
   * This method handles building construction and update
   */
  private static void buildingProcess(Colony c) {
    List<BuildingAction> actions = c.getBuildingActions();
    List<BuildingAction> actionsToRemove = new ArrayList<BuildingAction>();
    for (BuildingAction action : actions) {
      // For each action, we make a step
      action.step();
      if (action.isDone()) {
        // The action is done so we have to remove it from the list.
        actionsToRemove.add(action);

        // Robots associated to the construction / update have to be
        // released
        c.releaseRobots(action.getRobotsUsed());

        // We have to update the building list in the game data.
        Building building = action.getBuilding();

        if (action.isUpgrade()) {
          building.upgrade();// Uprade
          building.setUpgrading(false); // The upgrading is done
        } else {
          // If the created building is unique, a flag must be set
          if (BuildingType.RESEARCH_CENTER.equals(building.getType())) {
            c.setResearchCenterBuilt(true);
          }

          building.setUnderConstruction(false);

          // Creation
          c.addBuilding(building);
        }
        SoundHelper.playSound(SoundHelper.BUILDING_END);
      }
    }

    // All actions were processed. If there is some finished actions, we
    // remove them from the action list
    if (!actionsToRemove.isEmpty()) {
      for (BuildingAction action : actionsToRemove) {
        actions.remove(action);
        action.runCallback();
      }
    }
  }

  /**
   * Runs the production / consumption process
   */
  private static void productionProcess(Colony c) {
    // First we get the global modifiers : production - consumption
    Map<Resource, BigDecimal> modifiers = analyzeModifiers(c);
    if (hasNegativeModifiers(modifiers)) {
      if (storeCanAbsorbLoss(c, modifiers)) {
        // There is enough resources in store to absorb the production
        // loss. Resource amount in store will decrease
        applyModifiers(c, modifiers);
      } else {
        // There is not enough resources in store to absorb the loss. We
        // have a problem : not all buildings can run but some may.
        chooseAndRunBuildings();
      }
    } else {
      // There is only production, we can simply apply it
      applyModifiers(c, modifiers);
    }
  }

  /**
   * Analyses the buildings production and consumption and stock it in a map.
   * Key : the resource. Value : the production modifier
   *
   * @return a map of modifiers (production - consumption)
   */
  private static Map<Resource, BigDecimal> analyzeModifiers(Colony c) {
    Resource[] resources = Resource.values();
    Map<Resource, BigDecimal> analysis = new HashMap<Resource, BigDecimal>();
    BigDecimal value;
    for (Resource r : resources) {
      analysis.put(r, BigDecimal.ZERO);
    }

    // For each building we will retreive production and consumption
    List<Building> buildings = c.getBuildings();
    if (!buildings.isEmpty()) {
      int i = 0;
      i++;
    }
    for (Building b : buildings) {
      Map<Resource, BigDecimal> prod = BuildingHelper.getProductionOf(b);
      Map<Resource, BigDecimal> cons = BuildingHelper.getConsumptionOf(b);
      for (Resource r : resources) {
        // Production
        value = prod.get(r).divide(BigDecimal.valueOf(60));
        if (value != null) {
          analysis.put(r, analysis.get(r).add(value));
        }

        // Consumption
        value = cons.get(r).divide(BigDecimal.valueOf(60));
        if (value != null) {
          analysis.put(r, analysis.get(r).subtract(value));
        }
      }
    }
    return analysis;
  }

  /**
   * Tests if there is a negative value in the modifiers map. That's a simple
   * search of a negative value.
   *
   * @param modifiers
   *            the modifiers
   * @return true if there is a negative value
   */
  private static boolean hasNegativeModifiers(
      Map<Resource, BigDecimal> modifiers) {
    Set<Resource> resources = modifiers.keySet();
    BigDecimal value;
    for (Resource r : resources) {
      value = modifiers.get(r);
      if (value != null && value.signum() == -1) {
        return true;
      }
    }
    return false;
  }

  /**
   * This method takes modifiers and apply them to the store. The store has
   * space limits according to buildings specs. If the previous store amount
   * with the modifiers exeeds the max storable space, then the production
   * will be capped to the max storable value.
   *
   * @param modifiers
   *            The modifiers map
   */
  private static void applyModifiers(Colony c,
      Map<Resource, BigDecimal> modifiers) {
    Set<Resource> resources = modifiers.keySet();
    Map<Resource, BigDecimal> storageSpace = getStoreSpace(c);
    BigDecimal maxSpace;
    BigDecimal amount;
    BigDecimal currentStock;
    for (Resource r : resources) {
      maxSpace = storageSpace.get(r);
      amount = modifiers.get(r);
      currentStock = c.getResource(r);
      if (NumberHelper.infEq(maxSpace, currentStock.add(amount))) {
        // Tere is no more space in store for this resource, so we cap
        // it to the max storable. However, if the command center is not
        // built, it means that the player is currently colonizing the
        // sector
        if (c.isCommandCenterBuilt()) {
          c.setResource(r, maxSpace);
        } else {
          // The command center is not built yet. Resources are not
          // modified
        }
      } else {
        // Enough space for the amount produced
        c.updateResource(r, amount);
      }
      c.setCurrentModifier(r, amount);
    }
  }

  /**
   * Tests if there is enough resources in store to absorb the given modifiers
   * loss
   *
   * @param c
   *            the colony
   * @param modifiers
   *            the modifiers map
   * @return true if there is enough resources in store to absorb the loss
   */
  private static boolean storeCanAbsorbLoss(Colony c,
      Map<Resource, BigDecimal> modifiers) {
    Resource[] resources = Resource.values();
    BigDecimal storeValue;
    BigDecimal modifierValue;
    for (Resource r : resources) {
      storeValue = c.getResource(r);
      modifierValue = modifiers.get(r);
      if (NumberHelper.inf(storeValue, modifierValue)) {
        // Store value is lesser than the modifier. Absorption is not
        // possible
        return false;
      }
    }
    return true;
  }

  /**
   * This method has to choose wich buildings will run and wich will not. The
   * choices will be done according different paramaters
   */
  private static void chooseAndRunBuildings() {
    // The selection is made by
    // TODO
  }

  /**
   * Calculate the total amount of store space provided by the buildings
   *
   * @param colony
   *            The colony
   * @return a map describing the store space available for each resource
   */
  private static Map<Resource, BigDecimal> getStoreSpace(Colony c) {
    Map<Resource, BigDecimal> storeSpace = new HashMap<Resource, BigDecimal>();
    Resource[] resources = Resource.values();
    // Initialize of storeSpace map
    for (Resource r : resources) {
      storeSpace.put(r, BigDecimal.ZERO);
    }

    BigDecimal space;
    List<Building> buildings = c.getBuildings();
    // For each building we'll check the space provided for each resource
    for (Building b : buildings) {
      for (Resource r : resources) {
        space = b.getStoreSpaceFor(r);
        storeSpace.put(r, storeSpace.get(r).add(space));
      }
    }
    return storeSpace;
  }
}
TOP

Related Classes of com.drakulo.games.ais.core.GameEngine

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.