/** * 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; import net.sf.freecol.common.model.Location; import net.sf.freecol.common.model.Map.Direction; import net.sf.freecol.common.model.Tile; /** * Represents a single <code>Location</code> in a path. * * You will most likely be using: {@link #next}, {@link #getDirection}, * {@link #getTile} and {@link #getTotalTurns}, when * evaluating/following a path. */ public class PathNode { /** * The location this node refers to. Usually a Tile. */ private Location location; /** * The number of moves left at this node for the unit traversing * this path. */ private int movesLeft; /** * The number of turns used to get to this node by the unit * traversing the path. */ private int turns; /** * Whether the unit traversing this path is on a carrier at this node. */ private boolean onCarrier = false; /** * The next node in the path. */ public PathNode next = null; /** * The previous node in the path. */ public PathNode previous = null; /** * Creates a new <code>PathNode</code>. * * @param location The <code>Location</code> this * <code>PathNode</code> represents in the path. * @param movesLeft The number of moves remaining at this point in * the path. * @param turns The number of turns it takes to reach this * <code>PathNode</code>'s <code>Tile</code> from the start * of the path. * @param onCarrier Whether the path is still using a carrier. * @param previous The previous <code>PathNode</code> in the path. * @param next The next <code>PathNode</code> in the path. */ public PathNode(Location location, int movesLeft, int turns, boolean onCarrier, PathNode previous, PathNode next) { this.location = location; this.movesLeft = movesLeft; this.turns = turns; this.onCarrier = onCarrier; this.previous = previous; this.next = next; } /** * Gets the location of this path. * * @return The <code>Location</code>. */ public Location getLocation() { return location; } /** * Gets the <code>Tile</code> of this <code>PathNode</code>. * * @return The <code>Tile</code> this <code>PathNode</code> * represents in the path, if any. */ public Tile getTile() { return (location == null) ? null : location.getTile(); } /** * Gets the number of moves remaining at this point in the path. * * @return The number of moves remaining. <code>-1</code> is * returned if the number of moves left has not been calculated. */ public int getMovesLeft() { return movesLeft; } /** * Sets the number of moves remaining at this point in the path. * * @param movesLeft The number of moves remaining. */ public void setMovesLeft(int movesLeft) { this.movesLeft = movesLeft; } /** * Gets the number of turns it will take to reach this * <code>PathNode</code>'s <code>Tile</code> in the path. * * @return The number of turns, using zero for the first * move. <code>-1</code> is returned if the number of turns * has not been calculated. */ public int getTurns() { return turns; } /** * Sets the number of turns it will take to reach this * <code>PathNode</code>'s <code>Tile</code> in the path. * * @param turns The new number of turns. */ public void setTurns(int turns) { this.turns = turns; } /** * Adds turns to the turns on this path. * * @param turns The number of turns to add. */ public void addTurns(int turns) { for (PathNode p = this; p != null; p = p.next) { p.setTurns(p.getTurns() + turns); } } /** * Checks if the unit using this path is still onboard its transport. * * @return <code>true</code> if the unit is still onboard a * carrier when using this path. * @see #getTransportDropTurns */ public boolean isOnCarrier() { return onCarrier; } /** * Sets if the unit using this path is still onboard its transport. * * @param onCarrier Should be set to <code>true</code> in order to * indicate that the unit using this path is still onboard the * carrier on this path node. * @see #getTransportDropTurns */ public void setOnCarrier(boolean onCarrier) { this.onCarrier = onCarrier; } /** * Gets the direction to move in order to get to this path node. * * @return The direction to move on the map in order to get to the * <code>Tile</code> returned by this <code>PathNode</code>'s * {@link #getTile}, or null if there is no previous node or either * this or the previous node location is not on the map. */ public Direction getDirection() { if (previous == null || previous.getTile() == null || getTile() == null) return null; Tile prev = previous.getTile(); return prev.getMap().getDirection(prev, getTile()); } /** * Gets the node where the unit using this path should leave its * transport. * * @return The node where the unit leaves it's carrier. */ public PathNode getTransportDropNode() { PathNode temp = this; while (temp.next != null && temp.isOnCarrier()) { temp = temp.next; } return temp; } /** * Gets the first node of this path. * * @return The first <code>PathNode</code>. */ public PathNode getFirstNode() { PathNode path; for (path = this; path.previous != null; path = path.previous); return path; } /** * Gets the last node of this path. * * @return The last <code>PathNode</code>. */ public PathNode getLastNode() { PathNode path; for (path = this; path.next != null; path = path.next); return path; } /** * Gets the number of turns it will take to move the entire path, * from the starting <code>PathNode</code> until the end. * * @return The number of turns, using zero for the first move. */ public int getTotalTurns() { return getLastNode().getTurns(); } /** * Gets the number of turns it takes to reach the * {@link #getTransportDropNode transport node}. * * @return The number of turns in takes to get to the node where * the unit using this path should leave it's transport. */ public int getTransportDropTurns() { return getTransportDropNode().getTurns(); } /** * Standard function to get the cost of moving to a <code>PathNode</code>. * Static version provided for path calculation comparisons. * * @param turns The number of turns taken. * @param movesLeft The number of moves left for the moving unit. * @return The cost of moving to a <code>PathNode</code>. */ public static int getCost(int turns, int movesLeft) { return 100 * turns + (100 - movesLeft); } /** * Gets the cost of moving to this <code>PathNode</code>. * * @return The cost of moving to this <code>PathNode</code>. */ public int getCost() { return getCost(turns, movesLeft); } /** * Gets the next carrier move on this path. * * @return The first node along the path which is a carrier move, or null * if the path does not use a carrier. */ public PathNode getCarrierMove() { for (PathNode path = this; path != null; path = path.next) { if (path.isOnCarrier()) return path; } return null; } /** * Does this path us a carrier at any point? * * @return True if there is an onCarrier move in this path. */ public boolean usesCarrier() { return getFirstNode().getCarrierMove() != null; } /** * {@inheritDoc} */ public String toString() { return "PathNode loc=" + ((FreeColGameObject)location).toString() + " movesLeft=" + Integer.toString(movesLeft) + " turns=" + Integer.toString(turns) + " onCarrier=" + Boolean.toString(onCarrier) + " direction=" + getDirection() + " cost=" + getCost(); } /** * Another debug helper. * * @return A string describing the whole path. */ public String fullPathToString() { StringBuilder sb = new StringBuilder(500); PathNode p; for (p = this; p != null; p = p.next) { sb.append(p.toString()); sb.append("\n"); } return sb.toString(); } }