// // @(#)OrderState.java 1.00 4/1/2002 // // Copyright 2002 Zachary DelProposto. All rights reserved. // Use is subject to license terms. // // // This program 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. // // This program 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 this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // Or from http://www.gnu.org/ // package dip.process; import dip.order.Order; import dip.order.Move; import dip.order.Support; import dip.world.Province; import dip.world.Location; import dip.world.Power; import dip.world.Unit; import java.util.*; /** * OrderState objects keep track of the state of an order, during adjudication. * OrderStates are not designed to be serialized. * <p> * Each OrderState represents a decision. All OrderStates initially start out with an evaluation state * of Tristate.UNCERTAIN. Once a decision has been made, based upon the internal state, the evaluation * state is finalized (Tristate.SUCCESS or Tristate.FAILURE). Ince finalized, a decision can never be reversed. * Irreversibility is enforced by the OrderState object. * <p> * _max values only become smaller.<br> * _certain values only become larger.<br> * <p> * defense: the strength to stay in the same position (hold strength) <br> * attack: the strength required to dislodge a defender from it's position; a separate value * is computed for "self" attacks. * <p> * Dependent lists include OrderStates representing: * <ul> * <li> Support</li> * <li> Moves to Destination province</li> * <li> Moves to this (source) province</li> * </ul> * <p> * In Java code, OrderState variables typically have the suffix "OS". * <p> * NOTE: <b>When debugging, assertions should be enabled.</b> * <p> * DESIGN NOTE: this class is currently marked final but may not be in future versions. * */ public final class OrderState { /** * NOTE: 'max' values start at an arbitrarily high value (something that is so large * that it could never occur in a game) and move down. Note that setting the value * to Integer.MAX_VALUE is NOT a good idea, because if we add two max values together * (e.g., when calculating support), we will overflow (to negative values) * So, we will use our own MAX_VALUE, which is still quite high. */ public static final int MAX_VALUE = 9999; /** MINIMUM value for a strength. Only used for Retreat Strength. */ public static final int MIN_VALUE = -9999; /** Internal constant: Empty orderstate array */ private static final OrderState[] OS_EMPTY = new OrderState[0]; private Order order = null; private int defense_max = MAX_VALUE; private int defense_certain = 1; // always can defend at 1 private int attack_max = MAX_VALUE; private int attack_certain = 0; // can't always can attack at 1. E.g DPB private int selfsupport_atk_max = MAX_VALUE; private int selfsupport_atk_certain = 0; // we may not be self-supporting, so start at 0 private int retreatStr = MIN_VALUE; // retreat strength (for DPB support) private boolean isCircular = false; private boolean isLegal = true; // assume order is legal private Tristate evalState = Tristate.UNCERTAIN; private Tristate dislodged = Tristate.NO; // not-dislodged is default private OrderState[] dependentSelfSupports = OS_EMPTY; // only contains Support orders private OrderState[] dependentSupports = OS_EMPTY; // only contains Support orders private OrderState[] dependentMovesToSource = OS_EMPTY; // only contains Move orders private OrderState[] dependentMovesToDestination = OS_EMPTY; // only contains Move orders private OrderState headToHead = null; // if it's a head-to-head move private OrderState dislodgedBy = null; // orderstate which dislodged this unit private boolean foundConvoyPath = false; // if move found a convoy path private boolean isVerified = false; // has this order been verified() yet? /** * Create an OrderState. This is protected, because only subclasses of * this and adjudicators should be able to create new OrderState objects, * although other classes can definately use them. */ protected OrderState(Order order) { if(order == null) { throw new IllegalArgumentException("null order"); } this.order = order; }// OrderState() // GET methods /** Get the Order for this OrderState. */ public Order getOrder() { return order; } /** Get if we are part of a circular movement chain. */ public boolean isCircular() { return isCircular; } /** Get the evaluation state. */ public Tristate getEvalState() { return evalState; } /** Get dislodged state. */ public Tristate getDislodgedState() { return dislodged; } /** Get maximum defense value */ public int getDefMax() { return defense_max; } /** Get certain defense value */ public int getDefCertain() { return defense_certain; } /** Get maximum attack value */ public int getAtkMax() { return attack_max; } /** Get certain attack value */ public int getAtkCertain() { return attack_certain; } /** Get maximum self-support attack value */ public int getAtkSelfSupportMax() { return selfsupport_atk_max; } /** Get certain self-support attack value. */ public int getAtkSelfSupportCertain() { return selfsupport_atk_certain; } /** Determines if this is part of a head-to-head Move. */ public boolean isHeadToHead() { return (headToHead != null); } /** Get the order that we are in a head-to-head Move with. */ public OrderState getHeadToHead() { return headToHead; } /** Get the order legality (default is true). */ public boolean isLegal() { return isLegal; } /** Get the dislodger, if any. */ public OrderState getDislodger() { return dislodgedBy; } /** Get if we have found a convoy path. */ public boolean hasFoundConvoyPath() { return foundConvoyPath; } /** Get retreat strength */ public int getRetreatStrength() { return retreatStr; } /** Indicates if the retreat strength has been set. */ public boolean isRetreatStrengthSet() { return(retreatStr != MIN_VALUE); } /** Indicate if Order has been Verified */ public boolean isVerified() { return isVerified; } /** Gets the dependent Support orders for this order */ public OrderState[] getDependentSupports() { return dependentSupports; } /** Get the Move orders that are moving to the Source Location of this order. */ public OrderState[] getDependentMovesToSource() { return dependentMovesToSource; } /** Get the Move orders that are moving to the Destination Location of this order. */ public OrderState[] getDependentMovesToDestination() { return dependentMovesToDestination; } /** Gets the dependent self-Support orders for this order */ public OrderState[] getDependentSelfSupports() { return dependentSelfSupports; } /** Set the Order. NOTE: this may be eliminated/deprecated, as it must be used with extreme care.*/ protected void setOrder(Order value) { order = value; } // consider eliminating /** Set if this is part of a chain of circular movements. */ public void setCircular(boolean value) { isCircular = value; } /** Set the dislodged state. */ public void setDislodgedState(Tristate value) { dislodged = value; } /** Set the maximum defense. */ public void setDefMax(int value) { defense_max = value; } /** Set the certain defense. */ public void setDefCertain(int value) { defense_certain = value; } /** Set the maximum attack value. */ public void setAtkMax(int value) { attack_max = value; } /** Set the certain attack value. */ public void setAtkCertain(int value) { attack_certain = value; } /** Set the attack max including self-support */ public void setAtkSelfSupportMax(int value) { selfsupport_atk_max = value; } /** Set the attack certain including self-support */ public void setAtkSelfSupportCertain(int value) { selfsupport_atk_certain = value; } /** Set if we have found a convoy path */ public void setFoundConvoyPath(boolean value) { foundConvoyPath = value; } /** Set the retreat strength */ public void setRetreatStrength(int value) { retreatStr = value; } /** Sets if an Order is legal. By default, orders are legal. */ public void setLegal(boolean value) { isLegal = value; } /** Set if an order has been verified. Once set to true, cannot be set to false. */ public void setVerified(boolean value) { if(!value && isVerified) { throw new IllegalStateException("setVerified() is irreversible, once set to true."); } isVerified = value; }// setVerified() /** * Set the evaluation state. Note that once set (e.g., value != UNCERTAIN), * it cannot be altered. */ public void setEvalState(Tristate value) { // ENSURE irreversibility if(evalState != Tristate.UNCERTAIN) { throw new IllegalStateException("EvalState is irreversible, once set."); } evalState = value; }// setEvalState() /** if move is a head-to-head move, set which move we are moving head-to-head against here. */ public void setHeadToHead(OrderState os) { if(os != null && !(os.order instanceof Move)) { throw new IllegalArgumentException("h2h orderstate must be set with a Move order"); } headToHead = os; }// setHeadToHead() /** * Set the dislodger. We do some sanity checks; this can only * be set if dislodged == MAYBE or YES. Furthermore, dislodger * must be a Move order. */ public void setDislodger(OrderState os) { assert(os.order instanceof Move && dislodged != Tristate.NO); dislodgedBy = os; }// setDislodger() /** * Adds the given list, which must only contain Dependent Support OrderStates. * <p> * If assertions are enabled, the list is verified to contain only Support * OrderStates */ public void setDependentSupports(List osList) { assert(verifyListSupport(osList)); dependentSupports = (OrderState[]) osList.toArray(new OrderState[osList.size()]); }// setDependentSupports() /** * Criteria: * <ol> * <li>Support order * <li>Supported MOVE (not any other) [supportedSrc != supportedDest] * <li>unit in supportedDest must be present * <li>power of unit in supported dest == power of support order * </ol> * <b>NOTE:</b> OrderState only checks criteria #1 and #2, and only if * asserts are enabled. */ public void setDependentSelfSupports(List osList) { assert(verifyListSelfSupport(osList)); dependentSelfSupports = (OrderState[]) osList.toArray(new OrderState[osList.size()]); }// addDependentSupport() /** * Adds a List of the Dependent Move Orderstates to the Source Province of this Orderstate. * <p>If asserts are enabled, all OrderStates are verified to contain only Move orders. */ public void setDependentMovesToSource(List osList) { assert(verifyListMove(osList)); dependentMovesToSource = (OrderState[]) osList.toArray(new OrderState[osList.size()]); }// addDependentMoveToSource() /** * Adds a List of the Dependent Move Orderstates to the Destination Province of this Orderstate * <p>If asserts are enabled, all OrderStates are verified to contain only Move orders. */ public void setDependentMovesToDestination(List osList) { assert(verifyListMove(osList)); dependentMovesToDestination = (OrderState[]) osList.toArray(new OrderState[osList.size()]); }// addDependentMoveToDestination() /** Convenicent method: get the order source Location */ public Location getSource() { return order.getSource(); } /** Convenicent method: get the order source Province */ public Province getSourceProvince() { return getSource().getProvince(); } /** Convenicent method: get the order Power */ public Power getPower() { return order.getPower(); } /** * For each support in the dependent list, the total support is * determined in the following manner: * <ul> * <li>if isCertain == true: * <ul> * <li>+1 if support evalState == TriSTate.SUCCESS * <li>+0 if evalState is UNCERTAIN or FAILURE * </ul> * * <li>if isCertain == false; [calculates 'max' support] * <ul> * <li>+1 if support evalState == SUCCESS or UNCERTAIN * <li>+0 if support evalState == FAILURE * </ul> * </ul> * <p> * <b>Note:</b><br> * It is assumed that all support is 'appropriate'; and that invalid supports have * already been marked as such (e.g., if order is Move A-B, and we have to supports: * support 1: C sup A-B, and support 2: C sup A) that support 2 (illegal for a Move order) * is marked FAILURE with it's evalstate. * <p> * If there is NO support, we return 1 (since all units have a default strength of 1), * unless the base move modifier (due to a difficult passable border) changes this amount. * */ public int getSupport(boolean isCertain) { // Determine support, but based on the fact that provinces could have special borders int mod; // Just figuring out how to get each border, and what its BaseMoveModifier is. if(this.getOrder() instanceof Move) { Move order = (Move) this.getOrder(); mod = order.getDest().getProvince().getBaseMoveModifier(order.getSource()); } else if(this.getOrder() instanceof Support) { Support order = (Support) this.getOrder(); mod = order.getSupportedDest().getProvince().getBaseMoveModifier(order.getSource()); // If the order is a convoy, hold,etc there is not BaseMoveModifier } else { mod = 0; } // Get the strength int strength = getSupport(isCertain, dependentSupports, 1 + mod); // if it is 0 or above, great! If not, make it 0! if (strength >= 0) { return strength; } else { return 0; } }// getSupport() /** * Similar to getSupport(), but, determines self-support (if any). * If there is no self support, returns '0'. */ public int getSelfSupport(boolean isCertain) { return getSupport(isCertain, dependentSelfSupports, 0); }// getSelfSupport() /** * Helper method, used by other getSupport() and getSelfSupport() methods. * */ protected int getSupport(boolean isCertain, OrderState[] supportList, int defaultStrength) { int strength = defaultStrength; for(int i=0; i<supportList.length; i++) { OrderState os = supportList[i]; if( os.getEvalState() == Tristate.SUCCESS || (!isCertain && os.getEvalState() == Tristate.UNCERTAIN) ) { strength++; } } assert (strength >= 0); // negative strength is not allowed! return strength; }// getSupport() /** Verifies that given list ONLY contains Move orderstates */ private boolean verifyListMove(List list) { Iterator iter = list.iterator(); while(iter.hasNext()) { OrderState os = (OrderState) iter.next(); if( !(os.getOrder() instanceof Move) ) { return false; } } return true; }// verifyListMove() /** Verifies that given list ONLY contains Support orderstates */ private boolean verifyListSupport(List list) { Iterator iter = list.iterator(); while(iter.hasNext()) { OrderState os = (OrderState) iter.next(); if( !(os.getOrder() instanceof Support) ) { return false; } } return true; }// verifyListSupport() /** Verifies that given list ONLY contains Self Support orderstates */ private boolean verifyListSelfSupport(List list) { Iterator iter = list.iterator(); while(iter.hasNext()) { OrderState os = (OrderState) iter.next(); if(os.getOrder() instanceof Support) { Support support = (Support) os.getOrder(); if(support.isSupportingHold()) { return false; } } else { return false; } } return true; }// verifyListSelfSupport() }// class OrderState