Android Open Source - dragon-wars Logic






From Project

Back to project page dragon-wars.

License

The source code is released under:

GNU General Public License

If you think the Android project dragon-wars 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 Dragon Wars.
 *//ww w  . j a  v a  2s  .  c om
 * 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 com.group7.dragonwars.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()) {
                        Player op = map.getField(n.getPosition())
                                    .getUnit().getOwner();

                        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()) {
                shown.add(p);
            }
        }

        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) {
        return new Pair<Double, Double>(
            calculateRawDamage(map, attacker, defender),
            calculateCounterDamage(map, attacker, defender));
    }


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

        Double fieldDefense = defenderField.getDefenseModifier() - 1;
        Double unitDefense = attacker.isRanged()
            ? defender.getRangeDefense() : defender.getMeleeDefense() - 1;

        Double damage = attacker.getAttack()
            + (2 * attacker.getAttack()
               * (attacker.getHealth() / attacker.getMaxHealth()));

        Double finalDamage = damage - (((fieldDefense * damage) / 2)
                                       + ((unitDefense * damage) / 2));

        return attacker.getHealth() > 0.0 ? finalDamage : 0.0;

    }

    public Double calculateCounterDamage(final GameMap map, final Unit attacker,
                                         final Unit defender) {
        Double initialDamage = calculateRawDamage(map, attacker, defender);
        Double defenderHealth = defender.getHealth() - initialDamage;
        defenderHealth = (defenderHealth < 0) ? 0 : defenderHealth;

        return calculateTheoreticalCounterDamage(map, defender, attacker,
                defenderHealth);
    }

    private Double calculateTheoreticalCounterDamage(
        final GameMap map, final Unit attacker,
        final Unit defender, final Double atkHealth) {
        GameField defenderField = map.getField(defender.getPosition());

        double fieldDefense = defenderField.getDefenseModifier() - 1;
        double unitDefense = attacker.isRanged()
            ? defender.getRangeDefense() : defender.getMeleeDefense() - 1;

        double damage = attacker.getAttack()
            + (2 * attacker.getAttack()
               * (atkHealth / attacker.getMaxHealth()));

        double finalDamage = damage - (((fieldDefense * damage) / 2)
                                       + ((unitDefense * damage) / 2));

        return attacker.getHealth() > 0 ? finalDamage : 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)) {
                    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> 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> getAdjacentPositions(final Position pos) {
        List<Position> positions = new ArrayList<Position>();
        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()));
        return positions;
    }

    private List<Position> getValidSurroundingPositions(final GameMap map,
            final Position pos) {
        List<Position> positions = getValidNeighbours(map, pos);
        Position nep, nwp, sep, swp;
        Integer i = pos.getX(), j = pos.getY();
        nep = new Position(i - 1, j - 1);

        if (map.isValidField(nep)) {
            positions.add(nep);
        }

        nwp = new Position(i + 1, j - 1);

        if (map.isValidField(nwp)) {
            positions.add(nwp);
        }

        sep = new Position(i - 1, j + 1);

        if (map.isValidField(sep)) {
            positions.add(sep);
        }

        swp = new Position(i + 1, j + 1);

        if (map.isValidField(swp)) {
            positions.add(swp);
        }

        return positions;

    }

    private class AStarComparator implements
        Comparator<Node> {
        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 Position p;
        private Double g, 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 getH() {
            return h;
        }

        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
        if (unit.isFlying()) {
            return 1.0;
        }

        return map.getField(origin).getMovementModifier();
    }

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

        for (Position p : atkFields) {
            if (map.isValidField(p)) {
                if (map.getField(p).hostsUnit()) {
                    Player uOwner = map.getField(p).getUnit().getOwner();

                    if (!uOwner.equals(unit.getOwner())) {
                        atkUnits.add(p);
                    }
                }
            }
        }

        return atkUnits;
    }

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

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

    private Set<Position> getAttackableFields(final GameMap map,
                                              final Unit unit,
                                              final Position position) {
        if (!unit.isRanged()) {
            return new HashSet<Position>(
                       getValidSurroundingPositions(map, position));
        }

        RangedUnit ru = (RangedUnit) unit;
        return getPositionsInRange(map, position, ru.getMinRange(),
                                   ru.getMaxRange());
    }

    public Set<Position> getAttackableFields(final GameMap map,
                                             final Unit unit) {
        /*if (!unit.isRanged())
            return getPositionsInRange(map, unit.getPosition(), 1.0);

        RangedUnit ru = (RangedUnit) unit;
        return getPositionsInRange(map, ru.getPosition(), ru.getMinRange(),
                                   ru.getMaxRange());*/
        return getAttackableFields(map, unit, unit.getPosition());
    }

    private Set<Position> getPositionsInRange(final GameMap map,
                                              final Position origin,
                                              final Double range) {
        Set<Position> positions = new HashSet<Position>();
        Double maxr = Math.ceil(range);

        for (Integer x = 0; x < maxr * 2; x++) {
            for (Integer y = 0; y < maxr * 2; y++) {
                Position newP = new Position(x, y);

                // Pair<Integer, Integer> dist = getManhattanDistance(origin,
                // newP);
                if (x < maxr) {
                    newP = new Position(newP.getX() - x, newP.getY());
                } else if (x > maxr) {
                    newP = new Position(newP.getX() + x, newP.getY());
                }

                if (y < maxr) {
                    newP = new Position(newP.getX(), newP.getY() - x);
                } else if (y > maxr) {
                    newP = new Position(newP.getX(), newP.getY() + y);
                }

                if (newP.equals(origin) || !map.isValidField(newP)) {
                    continue;
                }

                positions.add(newP);

            }
        }

        return positions;
    }

    private Set<Position> getPositionsInRange(final GameMap map,
                                              final Position origin,
                                              final Double minRange,
                                              final Double maxRange) {
        Set<Position> positions = getPositionsInRange(map, origin, maxRange);
        Set<Position> filtered = new HashSet<Position>();

        for (Position p : positions) {
            Pair<Integer, Integer> dist;
            dist = getDistanceAway(origin, p);

            if (Math.hypot(dist.getLeft(), dist.getRight()) < minRange) {
                continue;
            }

            filtered.add(p);
        }

        return filtered;
    }

    /* 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

com.group7.dragonwars.DrawingThread.java
com.group7.dragonwars.GameActivity.java
com.group7.dragonwars.GameView.java
com.group7.dragonwars.HelpActivity.java
com.group7.dragonwars.IsAiAdapter.java
com.group7.dragonwars.MainMenuActivity.java
com.group7.dragonwars.MapSelectActivity.java
com.group7.dragonwars.PlayerSelectActivity.java
com.group7.dragonwars.Results.java
com.group7.dragonwars.StatisticsActivity.java
com.group7.dragonwars.engine.BasicMapInfo.java
com.group7.dragonwars.engine.BitmapChanger.java
com.group7.dragonwars.engine.Building.java
com.group7.dragonwars.engine.DrawableMapObject.java
com.group7.dragonwars.engine.FloatPair.java
com.group7.dragonwars.engine.FuncEx.java
com.group7.dragonwars.engine.Func.java
com.group7.dragonwars.engine.GameField.java
com.group7.dragonwars.engine.GameFinishedException.java
com.group7.dragonwars.engine.GameMap.java
com.group7.dragonwars.engine.GameState.java
com.group7.dragonwars.engine.InformationState.java
com.group7.dragonwars.engine.Logic.java
com.group7.dragonwars.engine.MapReader.java
com.group7.dragonwars.engine.Pair.java
com.group7.dragonwars.engine.PlayerAI.java
com.group7.dragonwars.engine.Player.java
com.group7.dragonwars.engine.Position.java
com.group7.dragonwars.engine.RangedUnit.java
com.group7.dragonwars.engine.Statistics.java
com.group7.dragonwars.engine.Unit.java
com.group7.dragonwars.engine.Database.Database.java
com.group7.dragonwars.engine.GoalArbitration.AtomicAction.java
com.group7.dragonwars.engine.GoalArbitration.AttackAt.java
com.group7.dragonwars.engine.GoalArbitration.BuildUnit.java
com.group7.dragonwars.engine.GoalArbitration.MoveTo.java
com.group7.dragonwars.engine.GoalArbitration.Node.java
com.group7.dragonwars.engine.GoalArbitration.StateTree.java