package net.sf.colossus.server; import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import net.sf.colossus.game.BattleCritter; import net.sf.colossus.game.Creature; import net.sf.colossus.game.Game; import net.sf.colossus.variant.BattleHex; /** * Holds the information for one possible strike penalty, including * the null no-penalty option. * * @author David Ripton */ final class PenaltyOption implements Comparable<PenaltyOption> { private static final Logger LOGGER = Logger.getLogger(PenaltyOption.class .getName()); private final Game game; // Use BattleCritter instead? private final Creature striker; private final Creature target; private final Set<BattleHex> carryTargets = new HashSet<BattleHex>(); private final int dice; private final int strikeNumber; PenaltyOption(Game game, Creature striker, Creature target, int dice, int strikeNumber) { this.game = game; this.striker = striker; this.target = target; this.dice = dice; this.strikeNumber = strikeNumber; if (striker == target) { LOGGER.log(Level.SEVERE, "Penalty option with striker and target identical!"); } } Creature getStriker() { return striker; } Creature getTarget() { return target; } int getDice() { return dice; } int getStrikeNumber() { return strikeNumber; } // TODO use critters instead of hexes? // Then we would not even need game as instance variable here void addCarryTarget(BattleHex carryTarget) { carryTargets.add(carryTarget); } // TODO use critters instead of hexes? void addCarryTargets(Set<BattleHex> targets) { carryTargets.addAll(targets); } Set<BattleHex> getCarryTargets() { return Collections.unmodifiableSet(carryTargets); } int numCarryTargets() { return carryTargets.size(); } /** Sort first by ascending dice, then by descending strike number, * then by striker and target. Do not consider carryTargets. */ public int compareTo(PenaltyOption other) { if (dice < other.dice) { return -1; } else if (dice > other.dice) { return 1; } else if (strikeNumber > other.strikeNumber) { return -1; } else if (strikeNumber < other.strikeNumber) { return 1; } else if (Creature.IMPORTANCE_ORDER.compare(striker, other.striker) != 0) { return Creature.IMPORTANCE_ORDER.compare(striker, other.striker); } else { return Creature.IMPORTANCE_ORDER.compare(target, other.target); } } /** Do not consider carryTargets. */ @Override public boolean equals(Object object) { if (!(object instanceof PenaltyOption)) { return false; } PenaltyOption other = (PenaltyOption)object; return (dice == other.dice && strikeNumber == other.strikeNumber && striker.equals(other.striker) && target.equals(other.target)); } /** Do not consider carryTargets. */ @Override public int hashCode() { return dice + 100 * strikeNumber + striker.hashCode(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(striker.getDescription()); sb.append(" strikes "); sb.append(target.getDescription()); sb.append(" with "); sb.append(dice); sb.append(" dice and strike number "); sb.append(strikeNumber); if (!carryTargets.isEmpty()) { sb.append(", able to carry to "); boolean first = true; for (BattleHex hex : carryTargets) { if (!first) { sb.append(", "); } first = false; BattleCritter target = game.getBattle().getCritter(hex); sb.append(target.getDescription()); } } return sb.toString(); } }