/** * Copyright (C) 2002-2012 The FreeCol Team * * This file is part of FreeCol. * * FreeCol 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 2 of the License, or * (at your option) any later version. * * FreeCol 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 FreeCol. If not, see <http://www.gnu.org/licenses/>. */ package net.sf.freecol.common.model.pathfinding; import net.sf.freecol.common.model.Europe; import net.sf.freecol.common.model.Location; import net.sf.freecol.common.model.Map; import net.sf.freecol.common.model.PathNode; import net.sf.freecol.common.model.Player; import net.sf.freecol.common.model.Settlement; import net.sf.freecol.common.model.Tile; import net.sf.freecol.common.model.Unit; /** * Handy library of GoalDeciders. */ public final class GoalDeciders { /** * Gets a composite goal decider composed of two or more individual * goal deciders. The first one dominates the second etc. * * @param gds A series (two minimum) of <code>GoalDecider</code>s * to compose. * @return A new <code>GoalDecider</code> composed of the argument * goal deciders. */ public static GoalDecider getComposedGoalDecider(final GoalDecider... gds) { if (gds.length < 2) { throw new IllegalArgumentException("Short GoalDecider list"); } return new GoalDecider() { private GoalDecider[] goalDeciders = gds; public PathNode getGoal() { for (int i = 0; i < goalDeciders.length; i++) { PathNode path = goalDeciders[i].getGoal(); if (path != null) return path; } return null; } public boolean hasSubGoals() { return true; } public boolean check(Unit u, PathNode path) { boolean ret = false; for (int i = goalDeciders.length-1; i >= 0; i--) { ret = goalDeciders[i].check(u, path); } return ret; } }; } /** * Gets a GoalDecider to find the `closest' settlement owned by the * searching unit player, with connected ports weighted double. * * @return The closest settlement goal decider. */ public static GoalDecider getOurClosestSettlementGoalDecider() { return new GoalDecider() { private PathNode bestPath = null; private float bestValue = 0.0f; public PathNode getGoal() { return bestPath; } public boolean hasSubGoals() { return true; } public boolean check(Unit u, PathNode path) { Location loc = path.getLastNode().getLocation(); Settlement settlement = loc.getSettlement(); if (settlement != null && settlement.getOwner().owns(u)) { float value = ((settlement.isConnectedPort()) ? 2.0f : 1.0f) / (path.getTotalTurns() + 1); if (bestValue < value) { bestValue = value; bestPath = path; return true; } } return false; } }; } /** * Gets a GoalDecider to find the closest high seas tile to a target. * Used when arriving on the map from Europe. * * @return The high seas goal decider. */ public static GoalDecider getHighSeasGoalDecider() { return new GoalDecider() { private PathNode best = null; public PathNode getGoal() { return best; } public boolean hasSubGoals() { return false; } public boolean check(Unit u, PathNode path) { if (path.getTile() != null && path.getTile().isDirectlyHighSeasConnected()) { if (best == null || path.getCost() < best.getCost()) { best = path; } return true; } return false; } }; } /** * Builds a simple goal decider to find a single target location. * * @param target The target <code>Location</code>. * @return A <code>GoalDecider</code> that only succeeds for the * target location. */ public static GoalDecider getLocationGoalDecider(final Location target) { return new GoalDecider() { private PathNode best = null; public PathNode getGoal() { return best; } public boolean hasSubGoals() { return false; } public boolean check(Unit u, PathNode path) { if (Map.isSameLocation(path.getLocation(), target)) { best = path; return true; } return false; } }; } /** * Builds a goal decider to find an adjacent tile to a target location. * * @param target The target <code>Location</code>. * @return A <code>GoalDecider</code> that only succeeds for tiles adjacent * to the target location. */ public static GoalDecider getAdjacentLocationGoalDecider(Location target) { final Tile tile = target.getTile(); if (tile == null) return null; return new GoalDecider() { private PathNode best = null; public PathNode getGoal() { return best; } public boolean hasSubGoals() { return false; } public boolean check(Unit u, PathNode path) { Tile t = path.getTile(); if (t != null && t.isAdjacent(tile)) { best = path; return true; } return false; } }; } }