Android Open Source - Turn-of-War Logic






From Project

Back to project page Turn-of-War.

License

The source code is released under:

Apache License

If you think the Android project Turn-of-War listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * This file is part of Turn of War which is a fork of Dragon Wars
 * as of 20/11/2013.//from  w  w w . j av a 2 s  .  c o  m
 *
 * Copyright (C) 2013 Ed Woodhouse <edwoodhou@gmail.com>
 *
 * Turn of War is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Turn of War is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Turn of War. If not, see <http://www.gnu.org/licenses/>.
 */
/* This file is part of Dragon Wars.
 *
 * Dragon Wars is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Dragon Wars is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Dragon Wars. If not, see <http://www.gnu.org/licenses/>.
 */

package uk.co.fuuzetsu.turnofwar.engine;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Set;

/* Class containing things like damage calculation and path finding. */
public final class Logic {

  private static final String TAG = "Logic";

  public List<Position> findValidFieldsNextToUnit(final GameMap map,
      final Unit attackerUnit, final Unit targetUnit) {
    List<Position> potential = getValidNeighbours(map,
        targetUnit.getPosition());
    List<Position> dests = destinations(map, attackerUnit);
    Iterator<Position> iter = potential.iterator();

    /* Remove positions we can't reach anyway */
    while (iter.hasNext()) {
      Position p = iter.next();
      GameField gf = map.getField(p);

      if ((gf.hostsUnit() && !gf.getUnit().equals(attackerUnit))
          || !dests.contains(p)) {
        iter.remove();
      }
    }

    return potential;
  }

  public List<Position> findPath(final GameMap map, final Unit unit,
      final Position destination) {
    return AStar(map, unit, destination);
  }

  public Integer calculateMovementCost(final GameMap map, final Unit unit,
      final List<Position> path) {
    Double totalCost = 0.0;

    for (Position pos : path) {
      if (pos.equals(unit.getPosition())) {
        continue;
      }

      totalCost += getMovementCost(map, unit, pos);
    }

    // totalCost = Math.ceil(totalCost);

    return totalCost.intValue();
  }

  public List<Position> destinations(final GameMap map, final Unit unit) {
    Set<Position> checked = new HashSet<Position>();
    Set<Position> reachable = new HashSet<Position>();

    Position unitPosition = unit.getPosition();
    List<Node> start = new ArrayList<Node>();
    start.add(new Node(unitPosition, 0.0, 0.0));

    checked.add(unitPosition);
    reachable.add(unitPosition);

    List<Node> next = nextPositions(map, start);
    while (next.size() != 0) {
      List<Node> newNext = new ArrayList<Node>();

      for (Node n : next) {
        checked.add(n.getPosition());

        if (unit.getRemainingMovement() < n.getG()) {
          continue;
        }

        if (map.getField(n.getPosition()).doesAcceptUnit(unit)) {
          if ((map.getField(n.getPosition()).hostsUnit()
              && !(map.getField(n.getPosition()).getUnit()
                  .getName().equals("Submarine") || map
                  .getField(n.getPosition()).getUnit()
                  .getName().equals("MissileSub")) && !(map
              .getField(n.getPosition()).getUnit().getName()
                .equals("Stealth")))
              || (map.getField(n.getPosition()).hostsUnit()
                  && ((unit.getName().equals("Destroyer") || unit
                      .getName().equals("Submarine"))) && (map
                  .getField(n.getPosition()).getUnit()
                  .getName().equals("Submarine") || map
                  .getField(n.getPosition()).getUnit()
                  .getName().equals("MissileSub")))
              || (map.getField(n.getPosition()).hostsUnit()
                  && ((unit.getName().equals("Fighter") || unit
                      .getName().equals("Stealth"))) && map
                  .getField(n.getPosition()).getUnit()
                  .getName().equals("Stealth"))) {
            Player op = map.getField(n.getPosition()).getUnit()
                .getOwner(); // pass through subs and stealths
            // || ((!unit.getName().equals("Stealth") ||
            // !unit.getName().equals("Fighter")) &&
            // !map.getField(n.getPosition()).getUnit().getName().equals("Stealth"))
            if (!op.equals(unit.getOwner())) {
              continue;
              // }
            }
          }

          reachable.add(n.getPosition());
          List<Node> thisNext = new ArrayList<Node>(5);

          thisNext.add(n);
          thisNext = nextPositions(map, thisNext);

          for (Node thisNode : thisNext) {
            if (!checked.contains(thisNode.getPosition())) {
              newNext.add(thisNode);
            }
          }
        }
      }

      next = newNext;
    }

    List<Position> shown = new ArrayList<Position>();

    for (Position p : reachable) {
      if (map.getField(p).canBeStoppedOn()) {

        // if (getMovementCost(map, unit, p) >= 3) { ///find a type of
        // terrain by its movement cost eg trees = 3
        shown.add(p);

        if (!(unit.isFlying() || unit.isBoat())) { // only need to do
          // this for non
          // boats and planes
          Double totalCost = 0.0;
          List<Position> path = findPath(map, unit, p);
          for (Position pos : path) {
            if (pos.equals(unit.getPosition())) {
              continue;
            }
            totalCost += getMovementCost(map, unit, pos);
            // totalCost += 1;
          }
          // String A = "yolo";
          // Log.v(A, "remaining movement" + totalCost);

          if (totalCost > unit.getMaxMovement()) {
            shown.remove(p); // remove places that cannot be reached
            // (it would be better to not add
            // them to begin)
          }
        }
      }
    }
    return shown;
  }

  public List<Node> nextPositions(final GameMap map, final List<Node> toCheck) {

    List<Node> result = new ArrayList<Node>();

    for (Node n : toCheck) {
      Double costSoFar = n.getG();
      Position currentPosition = n.getPosition();
      List<Position> adj = getValidNeighbours(map, currentPosition);

      for (Position pos : adj) {
        GameField cField = map.getField(pos);
        Double newCost = costSoFar + cField.getMovementModifier();
        result.add(new Node(pos, newCost, 0.0));
      }
    }

    return result;
  }

  /* Returns damage as if the attacker was standing on a different position */
  public Pair<Double, Double> calculateDamageFrom(final GameMap map,
      final Unit attacker, final Unit defender, final Position position) {
    /* We can cheat and temporarily set a unit's position to the fake one */

    Position originalPosition = attacker.getPosition();
    attacker.setPosition(position);
    Pair<Double, Double> damage = calculateDamage(map, attacker, defender);
    attacker.setPosition(originalPosition);
    return damage;
  }

  public Pair<Double, Double> calculateDamage(final GameMap map,
      final Unit attacker, final Unit defender) {
    Double a = calculateRawDamage(map, attacker, defender);
    Double b = (double) 0; // no return fire
    // Double b = calculateCounterDamage(map, attacker, defender);
    return new Pair<Double, Double>(a, b);
  }

  public Double calculateRawDamage(final GameMap map, final Unit attacker,
      final Unit defender) {
    GameField defenderField = map.getField(defender.getPosition());

    // DAMAGE TO ORIGINAL DEFENDER FROM ATTACKER

    Double fieldDefense = 0.0;
    if (defender.isFlying()) {
      fieldDefense = 0.0;
    } else {
      fieldDefense = defenderField.getDefenseModifier(); // original
      // attackers
      // defense mod
    }

    int damage = 0;
    damage = attacker.getAttack();

    if (fieldDefense > 0 && damage > 1) {
      damage = damage - 1;
    }

    return attacker.getHealth() > 0.0 ? damage : 0.0;
  }

  private List<Position> AStar(final GameMap map, final Unit unit,
      final Position destination) {
    if (!map.isValidField(destination)) {
      return new ArrayList<Position>(0);
    }

    PriorityQueue<Node> openSet = new PriorityQueue<Node>(10,
        new AStarComparator());
    Set<Node> closedSet = new HashSet<Node>();

    Node root = new Node(unit.getPosition(), 0.0,
        1.0 * getManhattanDistance(unit.getPosition(), destination));
    openSet.add(root);

    while (openSet.size() != 0) {
      Node current = openSet.poll();

      if (current.getPosition().equals(destination)) {
        return reconstructPath(current);
      }

      closedSet.add(current);

      for (Position n : getValidNeighbours(map, current.getPosition())) {
        GameField gf = map.getField(n);
        if ((!gf.doesAcceptUnit(unit))
            || (gf.hostsUnit()
                && (!(gf.getUnit().getOwner().equals(unit
                    .getOwner()))) && !((gf.getUnit()
                .getName().equals("Stealth") || (gf.getUnit()
                .getName().equals("Submarine") || (gf.getUnit()
                .getName().equals("MissileSub"))))))) {
          // dont consider squares with enemy units
          continue;
        }
        Node neigh = new Node(n, gf.getMovementModifier(),
            1.0 * getManhattanDistance(unit.getPosition(),
                destination));
        Double tentG = current.getG() + neigh.getG();
        if (closedSet.contains(neigh)) {
          if (tentG >= neigh.getG()) {
            continue;
          }
        }

        if ((!openSet.contains(neigh)) || tentG < neigh.getG()) {
          neigh.setParent(current);

          if (!openSet.contains(neigh)) {
            openSet.add(neigh);
          }
        }
      }
    }
    return new ArrayList<Position>(0); /* Search failed */
  }

  private List<Position> getValidSurroundingPositions(final GameMap map, // Attack
      // directions
      final Position pos) {
    List<Position> positions = getValidNeighbours(map, pos);
    return positions;
  }

  private List<Position> getValidNeighbours(final GameMap map,
      final Position pos) {
    List<Position> positions = new ArrayList<Position>(4);
    positions.add(new Position(pos.getX(), pos.getY() + 1));
    positions.add(new Position(pos.getX(), pos.getY() - 1));
    positions.add(new Position(pos.getX() + 1, pos.getY()));
    positions.add(new Position(pos.getX() - 1, pos.getY()));
    List<Position> validPositions = new ArrayList<Position>(4);

    for (Position p : positions) {
      if (map.isValidField(p)) {
        validPositions.add(p);
      }
    }
    return validPositions;
  }

  private List<Position> getValidSurroundingPositionsRanged(
      final GameMap map, // Attack directions
      final Position pos, String name) {
    List<Position> positions = getValidNeighboursRanged(map, pos, name);
    return positions;
  }

  private List<Position> getValidNeighboursRanged(final GameMap map,
      final Position pos, String name) {
    List<Position> positions = new ArrayList<Position>();
    int min = 0; // min range
    int max = 0; // max range
    int x = 0;
    int y = 0;

    if (name.equals("RocketTruck")) {
      min = 3; //was 2 4
      max = 5;
    } else if (name.equals("AntiAir")) {
      min = 3;
      max = 5;
    } else if (name.equals("AntiAirBoat")) {
      min = 3;
      max = 5;
    } else if (name.equals("Battleship")) {
      min = 2;
      max = 6;
    } else if (name.equals("MissileSub")) {
      min = 3;
      max = 7;
    }
    for (x = -max; x <= +max; x++) {
      for (y = -max; y <= +max; y++) {
        if (((Math.abs(x) + Math.abs(y)) >= min)
            && ((Math.abs(x) + Math.abs(y)) <= max)) {
          positions.add(new Position(pos.getX() + x, pos.getY() + y));
        }
      }
    }
    List<Position> validPositions = new ArrayList<Position>();
    for (Position p : positions) {
      if (map.isValidField(p)) {
        validPositions.add(p);
      }
    }
    return validPositions;
  }

  private class AStarComparator implements Comparator<Node> {
    @Override
    public int compare(final Node a, final Node b) {
      Double t = a.getF() - b.getF();

      if (t > 0) {
        return 1;
      }

      if (t < 0) {
        return -1;
      }

      return 0;
    }
  }

  private List<Position> reconstructPath(final Node node) {
    List<Position> path = new ArrayList<Position>();
    path.add(node.getPosition());
    Node parent = node.getParent();

    while (parent != null) {
      path.add(parent.getPosition());
      parent = parent.getParent();
    }

    return path;
  }

  private class Node {
    private Node parent;
    private final Position p;
    private Double g;
    private final Double h;

    public Node(final Position p, final Double g, final Double h) {
      this.p = p;

      this.g = g;
      this.h = h;
    }

    public Node getParent() {
      return parent;
    }

    public void setParent(final Node parent) {
      this.parent = parent;
      this.g = this.g + parent.getG();
    }

    public Double getG() {
      return g;
    }

    public Double getF() {
      return h + g;
    }

    public Position getPosition() {
      return p;
    }

    @Override
    public boolean equals(final Object other) {
      if (this == other) {
        return true;
      }

      if (!(other instanceof Node)) {
        return false;
      }

      Node that = (Node) other;
      return p.equals(that.getPosition());
    }

    @Override
    public int hashCode() {
      return p.hashCode();
    }
  }

  private Double getMovementCost(final GameMap map, final Unit unit,
      final Position origin) {
    /* g(x) for search */
    // flying units ignore this; always 1
    // right
    // if (unit.isFlying() || unit.isBoat()) {
    // return 1.0;
    // } else if (!unit.isBoat() && !unit.isFlying()) {
    // if (unit.getMobility().equals("t")) {// tread
    // if (map.getField(origin).getName().equals("Grass")) {
    // return 1.0;
    // } else if (map.getField(origin).getName().equals("Sand")) {
    // return 4.0;
    if (map.getField(origin).getName().equals("Forest") && !unit.isFlying()) {
      return 2.0;
    } else {
      return 1.0;
    }
    // } else if (map.getField(origin).getName().equals("Mountain")) {
    // return 4.0;
    // } else if (map.getField(origin).getName().equals("River")) {
    // return 4.0;
    // } else if (map.getField(origin).getName().equals("Highway")) {
    // return 3.0;
    // } else {
    // return 1.0;
    // }
    // } else {
    // return 1.0;
    // }
    // }
  }

  public Set<Position> getAttackableUnitPositions(final int myGo,
      final GameMap map, final Unit unit, final Position position) {
    Set<Position> atkFields = getAttackableFields(myGo, map, unit, position);
    Set<Position> atkUnits = new HashSet<Position>();

    for (Position p : atkFields) {
      if (map.isValidField(p)) {
        if (myGo == 0 && unit.isRanged) {
          atkUnits.add(p);
        } else {
          if (map.getField(p).hostsUnit()) {
            Unit target = map.getField(p).getUnit();
            boolean hostile = !map.getField(p).getUnit().getOwner()
                .equals(unit.getOwner());

            if (unit.getName().equals("Tank")
                || unit.getName().equals("HeavyTank")) {
              if (hostile
              // && (!target.isBoat() && !target.isFlying()) ) {
                  // shoot at all ground units

                  && (!target.getName().equals("Submarine")
                      && !target.getName().equals(
                          "MissileSub") && !target
                        .isFlying())) {
                // shoot at all ground and surface naval
                atkUnits.add(p);
              }
            } else if (unit.getName().equals("AntiAir")
                || unit.getName().equals("AntiAirBoat")) {
              if (hostile && !target.getName().equals("Stealth")
                  && target.isFlying()) {
                // shoot at all air units, not stealth
                atkUnits.add(p);
              }
            } else if (unit.getName().equals("Fighter")) {
              if (hostile && target.isFlying()) {
                // shoot at all air units
                atkUnits.add(p);
              }
            } else if (unit.getName().equals("Stealth")) {
              if (hostile
                  && !target.getName().equals("Submarine")
                  && !target.getName().equals("MissileSub")) {
                // shoot at all apart from subs
                atkUnits.add(p);
              }
            } else if (unit.getName().equals("Destroyer")) {
              if (hostile && !target.isFlying()) {
                atkUnits.add(p);
              }
            } else if (unit.getName().equals("Submarine")) {
              if (hostile && target.isBoat()) {
                atkUnits.add(p);
              }
            } else if (unit.getName().equals("Bomber")
                || unit.getName().equals("Battleship")
                || unit.getName().equals("RocketTruck")
                || unit.getName().equals("MissileSub")) {
              if (hostile && !target.isFlying()
                  && !target.getName().equals("Submarine")
                  && !target.getName().equals("MissileSub")) {
                atkUnits.add(p);
              }
            }
          }
        }
      }
    }
    return atkUnits;
  }

  public Set<Position> getAttackableUnitPositions(int myGo,
      final GameMap map, final Unit unit) {

    return getAttackableUnitPositions(myGo, map, unit, unit.getPosition());
  }

  private Set<Position> getAttackableFields(final int myGo,
      final GameMap map, final Unit unit, final Position position) {
    String name = unit.getName(); // sort out ranged/owned/direct range
    // squares
    if (!unit.isRanged()) {
      return new HashSet<Position>(getValidSurroundingPositions(map,
          position));
    } else {
      return new HashSet<Position>(getValidSurroundingPositionsRanged(
          map, position, name));
    }
  }

  public Set<Position> getAttackableFields(final GameMap map, final Unit unit) {
    return getAttackableFields(0, map, unit, unit.getPosition());
  }

  /* Used as a heuristic for A* */
  private Integer getManhattanDistance(final Position origin,
      final Position destination) {
    /* h(x) */
    Pair<Integer, Integer> distance = getDistanceAway(origin, destination);

    return distance.getLeft() + distance.getRight();
  }

  private Pair<Integer, Integer> getDistanceAway(final Position origin,
      final Position destination) {
    Integer x = Math.abs(origin.getX() - destination.getX());
    Integer y = Math.abs(origin.getY() - destination.getY());
    return new Pair<Integer, Integer>(x, y);
  }

}




Java Source Code List

uk.co.fuuzetsu.turnofwar.DrawingThread.java
uk.co.fuuzetsu.turnofwar.GameActivity.java
uk.co.fuuzetsu.turnofwar.GameView.java
uk.co.fuuzetsu.turnofwar.HelpActivity.java
uk.co.fuuzetsu.turnofwar.IsAiAdapter.java
uk.co.fuuzetsu.turnofwar.MainGyroSplash.java
uk.co.fuuzetsu.turnofwar.MainMenuActivity.java
uk.co.fuuzetsu.turnofwar.MapSelectActivity.java
uk.co.fuuzetsu.turnofwar.MenuActivity.java
uk.co.fuuzetsu.turnofwar.PlayerSelectActivity.java
uk.co.fuuzetsu.turnofwar.Results.java
uk.co.fuuzetsu.turnofwar.StatisticsActivity.java
uk.co.fuuzetsu.turnofwar.engine.BasicMapInfo.java
uk.co.fuuzetsu.turnofwar.engine.BitmapChanger.java
uk.co.fuuzetsu.turnofwar.engine.Building.java
uk.co.fuuzetsu.turnofwar.engine.ColourSwap.java
uk.co.fuuzetsu.turnofwar.engine.DrawableMapObject.java
uk.co.fuuzetsu.turnofwar.engine.FloatPair.java
uk.co.fuuzetsu.turnofwar.engine.FuncEx.java
uk.co.fuuzetsu.turnofwar.engine.Func.java
uk.co.fuuzetsu.turnofwar.engine.GameField.java
uk.co.fuuzetsu.turnofwar.engine.GameFinishedException.java
uk.co.fuuzetsu.turnofwar.engine.GameMap.java
uk.co.fuuzetsu.turnofwar.engine.GameState.java
uk.co.fuuzetsu.turnofwar.engine.InformationState.java
uk.co.fuuzetsu.turnofwar.engine.Logic.java
uk.co.fuuzetsu.turnofwar.engine.MapReader.java
uk.co.fuuzetsu.turnofwar.engine.Pair.java
uk.co.fuuzetsu.turnofwar.engine.PlayerAI.java
uk.co.fuuzetsu.turnofwar.engine.Player.java
uk.co.fuuzetsu.turnofwar.engine.Position.java
uk.co.fuuzetsu.turnofwar.engine.Statistics.java
uk.co.fuuzetsu.turnofwar.engine.Unit.java
uk.co.fuuzetsu.turnofwar.engine.Database.Database.java
uk.co.fuuzetsu.turnofwar.engine.GoalArbitration.AtomicAction.java
uk.co.fuuzetsu.turnofwar.engine.GoalArbitration.AttackAt.java
uk.co.fuuzetsu.turnofwar.engine.GoalArbitration.BuildUnit.java
uk.co.fuuzetsu.turnofwar.engine.GoalArbitration.MoveTo.java
uk.co.fuuzetsu.turnofwar.engine.GoalArbitration.Node.java
uk.co.fuuzetsu.turnofwar.engine.GoalArbitration.StateTree.java