From: <ste...@us...> - 2010-09-17 21:24:20
|
Revision: 1424 http://rails.svn.sourceforge.net/rails/?rev=1424&view=rev Author: stefanfrey Date: 2010-09-17 21:24:13 +0000 (Fri, 17 Sep 2010) Log Message: ----------- Added support for 1825 revenue calculation Modified Paths: -------------- trunk/18xx/rails/algorithms/NetworkTrain.java trunk/18xx/rails/algorithms/RevenueAdapter.java trunk/18xx/rails/algorithms/RevenueDynamicModifier.java trunk/18xx/rails/algorithms/RevenueManager.java trunk/18xx/rails/algorithms/RevenueTrainRun.java trunk/18xx/rails/game/specific/_18AL/NamedTrainRevenueModifier.java trunk/18xx/rails/game/specific/_18EU/PullmanRevenueModifier.java trunk/18xx/rails/game/state/ArrayListState.java Added Paths: ----------- trunk/18xx/rails/game/specific/_1825/DoubleHeadingModifier.java trunk/18xx/rails/game/specific/_1825/TerminateAtMajorModifier.java Modified: trunk/18xx/rails/algorithms/NetworkTrain.java =================================================================== --- trunk/18xx/rails/algorithms/NetworkTrain.java 2010-09-17 18:39:08 UTC (rev 1423) +++ trunk/18xx/rails/algorithms/NetworkTrain.java 2010-09-17 21:24:13 UTC (rev 1424) @@ -19,7 +19,7 @@ private final TrainI railsTrain; - NetworkTrain(int majors, int minors, boolean ignoreMinors, + public NetworkTrain(int majors, int minors, boolean ignoreMinors, int multiplyMajors, int multiplyMinors, String trainName, TrainI train) { this.majors = majors; this.minors = minors; @@ -110,6 +110,10 @@ return ignoreMinors; } + public String getTrainName() { + return trainName; + } + public TrainI getRailsTrain() { return railsTrain; } Modified: trunk/18xx/rails/algorithms/RevenueAdapter.java =================================================================== --- trunk/18xx/rails/algorithms/RevenueAdapter.java 2010-09-17 18:39:08 UTC (rev 1423) +++ trunk/18xx/rails/algorithms/RevenueAdapter.java 2010-09-17 21:24:13 UTC (rev 1424) @@ -75,7 +75,7 @@ private List<NetworkVertex> rcVertices; private List<NetworkEdge> rcEdges; private List<RevenueTrainRun> optimalRun; - private Set<RevenueDynamicModifier> dynamicModifiers; + private List<RevenueDynamicModifier> dynamicModifiers; // revenue listener to communicate results @@ -163,6 +163,10 @@ } } + public void addTrain(NetworkTrain train) { + trains.add(train); + } + public void removeTrain(NetworkTrain train) { trains.remove(train); } @@ -285,7 +289,7 @@ if (gameManager.getRevenueManager() != null) { dynamicModifiers = gameManager.getRevenueManager().callDynamicModifiers(this); } else { - dynamicModifiers = new HashSet<RevenueDynamicModifier>(); + dynamicModifiers = new ArrayList<RevenueDynamicModifier>(); } // define optimized graph @@ -573,6 +577,10 @@ public List<RevenueTrainRun> getOptimalRun() { if (optimalRun == null) { optimalRun = convertRcRun(rc.getOptimalRun()); + // allow dynamic modifiers to change the optimal run + for (RevenueDynamicModifier modifier:dynamicModifiers) { + modifier.adjustOptimalRun(optimalRun); + } } return optimalRun; } @@ -587,7 +595,7 @@ int dynamicEvaluation() { int value = 0; for (RevenueDynamicModifier modifier:dynamicModifiers) { - value += modifier.evaluationValue(this.getCurrentRun()); + value += modifier.evaluationValue(this.getCurrentRun(), false); } return value; } @@ -641,12 +649,15 @@ } if (includeDetails) { for (RevenueDynamicModifier modifier:dynamicModifiers) { - runPrettyPrint.append(modifier.prettyPrint(this)); + String modifierText = modifier.prettyPrint(this); + if (modifierText != null) { + runPrettyPrint.append(modifierText); + } } } else { int dynamicBonuses = 0; for (RevenueDynamicModifier modifier:dynamicModifiers) { - dynamicBonuses += modifier.evaluationValue(this.getOptimalRun()); + dynamicBonuses += modifier.evaluationValue(this.getOptimalRun(), true); } if (dynamicBonuses != 0) { runPrettyPrint.append("; " + Modified: trunk/18xx/rails/algorithms/RevenueDynamicModifier.java =================================================================== --- trunk/18xx/rails/algorithms/RevenueDynamicModifier.java 2010-09-17 18:39:08 UTC (rev 1423) +++ trunk/18xx/rails/algorithms/RevenueDynamicModifier.java 2010-09-17 21:24:13 UTC (rev 1424) @@ -20,9 +20,12 @@ /** returns the value used for prediction */ public int predictionValue(); - /** returns the value used for evaluation (at the run supplied) */ - public int evaluationValue(List<RevenueTrainRun> runs); + /** returns the value used for evaluation (at the runs supplied) */ + public int evaluationValue(List<RevenueTrainRun> runs, boolean optimalRuns); + /** allows to adjust the run list of the optimal train run output */ + public void adjustOptimalRun(List<RevenueTrainRun> optimalRuns); + /** returns the results as pretty prints */ public String prettyPrint(RevenueAdapter adapter); Modified: trunk/18xx/rails/algorithms/RevenueManager.java =================================================================== --- trunk/18xx/rails/algorithms/RevenueManager.java 2010-09-17 18:39:08 UTC (rev 1423) +++ trunk/18xx/rails/algorithms/RevenueManager.java 2010-09-17 21:24:13 UTC (rev 1424) @@ -1,8 +1,8 @@ package rails.algorithms; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Set; import org.apache.log4j.Logger; @@ -10,7 +10,7 @@ import rails.game.ConfigurableComponentI; import rails.game.ConfigurationException; import rails.game.GameManagerI; -import rails.game.state.HashSetState; +import rails.game.state.ArrayListState; import rails.util.LocalText; import rails.util.Tag; @@ -30,15 +30,15 @@ Logger.getLogger(RevenueManager.class.getPackage().getName()); - private final HashSetState<NetworkGraphModifier> graphModifiers; - private final HashSetState<RevenueStaticModifier> staticModifiers; - private final HashSetState<RevenueDynamicModifier> dynamicModifiers; + private final ArrayListState<NetworkGraphModifier> graphModifiers; + private final ArrayListState<RevenueStaticModifier> staticModifiers; + private final ArrayListState<RevenueDynamicModifier> dynamicModifiers; private final HashSet<ConfigurableComponentI> configurableModifiers; public RevenueManager() { - graphModifiers = new HashSetState<NetworkGraphModifier>("NetworkGraphModifiers"); - staticModifiers = new HashSetState<RevenueStaticModifier>("RevenueStaticModifiers"); - dynamicModifiers = new HashSetState<RevenueDynamicModifier>("RevenueDynamicModifiers"); + graphModifiers = new ArrayListState<NetworkGraphModifier>("NetworkGraphModifiers"); + staticModifiers = new ArrayListState<RevenueStaticModifier>("RevenueStaticModifiers"); + dynamicModifiers = new ArrayListState<RevenueDynamicModifier>("RevenueDynamicModifiers"); configurableModifiers = new HashSet<ConfigurableComponentI>(); } @@ -145,20 +145,20 @@ } void callGraphModifiers(NetworkGraphBuilder graphBuilder) { - for (NetworkGraphModifier modifier:graphModifiers.viewSet()) { + for (NetworkGraphModifier modifier:graphModifiers.viewList()) { modifier.modifyGraph(graphBuilder); } } void callStaticModifiers(RevenueAdapter revenueAdapter) { - for (RevenueStaticModifier modifier:staticModifiers.viewSet()) { + for (RevenueStaticModifier modifier:staticModifiers.viewList()) { modifier.modifyCalculator(revenueAdapter); } } - Set<RevenueDynamicModifier> callDynamicModifiers(RevenueAdapter revenueAdapter) { - Set<RevenueDynamicModifier> activeModifiers = new HashSet<RevenueDynamicModifier>(); - for (RevenueDynamicModifier modifier:dynamicModifiers.viewSet()) { + List<RevenueDynamicModifier> callDynamicModifiers(RevenueAdapter revenueAdapter) { + List<RevenueDynamicModifier> activeModifiers = new ArrayList<RevenueDynamicModifier>(); + for (RevenueDynamicModifier modifier:dynamicModifiers.viewList()) { if (modifier.prepareModifier(revenueAdapter)) activeModifiers.add(modifier); } Modified: trunk/18xx/rails/algorithms/RevenueTrainRun.java =================================================================== --- trunk/18xx/rails/algorithms/RevenueTrainRun.java 2010-09-17 18:39:08 UTC (rev 1423) +++ trunk/18xx/rails/algorithms/RevenueTrainRun.java 2010-09-17 21:24:13 UTC (rev 1424) @@ -3,6 +3,7 @@ import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -20,10 +21,9 @@ /** * Links the results from the revenue calculator to the rails program * Each object defines the run of one train - * @author freystef * */ -public class RevenueTrainRun { +public class RevenueTrainRun implements Comparable<RevenueTrainRun> { private static final int PRETTY_PRINT_LENGTH = 100; private static final int PRETTY_PRINT_INDENT = 10; @@ -49,16 +49,44 @@ public List<NetworkVertex> getRunVertices() { return vertices; } + + /** + * returns true if train has a valid run (at least two vertices) + */ + public boolean hasAValidRun() { + return vertices.size() >= 2; + } + /** + * returns the first vertex of a train run + */ + public NetworkVertex getFirstVertex() { + NetworkVertex startVertex = null; + NetworkVertex firstVertex = null; + for (NetworkVertex vertex:vertices) { + if (startVertex == vertex) return firstVertex; + if (startVertex == null) startVertex = vertex; + firstVertex = vertex; + } + return startVertex; + } + + /** + * returns the last vertex of a train run + */ + public NetworkVertex getLastVertex() { + return vertices.get(vertices.size()-1); + } + public Set<NetworkVertex> getUniqueVertices() { return new HashSet<NetworkVertex>(vertices); } - + public NetworkTrain getTrain() { return train; } - int getRunValue() { + public int getRunValue() { int value = 0; NetworkVertex startVertex = null; for (NetworkVertex vertex:vertices) { @@ -288,4 +316,9 @@ } return path; } + + public int compareTo(RevenueTrainRun other) { + return ((Integer)this.getRunValue()).compareTo(other.getRunValue()); + } + } \ No newline at end of file Added: trunk/18xx/rails/game/specific/_1825/DoubleHeadingModifier.java =================================================================== --- trunk/18xx/rails/game/specific/_1825/DoubleHeadingModifier.java (rev 0) +++ trunk/18xx/rails/game/specific/_1825/DoubleHeadingModifier.java 2010-09-17 21:24:13 UTC (rev 1424) @@ -0,0 +1,123 @@ +package rails.game.specific._1825; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.apache.log4j.Logger; + +import rails.algorithms.NetworkTrain; +import rails.algorithms.RevenueAdapter; +import rails.algorithms.RevenueDynamicModifier; +import rails.algorithms.RevenueTrainRun; +/** + * 1825 modifiers: + * Trains have to start and end in a major station + * Allows two 2-trains to run as a 3-train (double heading) + */ +public class DoubleHeadingModifier implements RevenueDynamicModifier { + + protected static Logger log = + Logger.getLogger(DoubleHeadingModifier.class.getPackage().getName()); + + private final static String TRAIN_2_NAME = "2"; + private final static String DUALHEAD_NAME = "2&2"; + + public boolean prepareModifier(RevenueAdapter revenueAdapter) { + int nbTrain2 = 0; + for (NetworkTrain train:revenueAdapter.getTrains()) { + // checks name of traintype + if (train.getRailsTrainType().getName().equals(TRAIN_2_NAME)) { + nbTrain2 ++; + } + } + + // add dualhead 3 train for each of a pair of 2-trains + boolean hasDualHead = false; + while (nbTrain2 >= 2) { + NetworkTrain dualHead = new NetworkTrain(3, 0, false, 1, 1, DUALHEAD_NAME, null); + revenueAdapter.addTrain(dualHead); + hasDualHead = true; + nbTrain2 -= 2; + } + + return hasDualHead; + } + + /** + * the prediction value itself is zero, as the add value stems from the train above + */ + public int predictionValue() { + return 0; + } + + /** + * returns the runs of the of the double heading trains + */ + private List<RevenueTrainRun> identifyDoubleHeadingTrains(List<RevenueTrainRun> runs) { + // find and sort the train2Revenues + List<RevenueTrainRun> train2Runs = new ArrayList<RevenueTrainRun>(); + for (RevenueTrainRun run:runs) { + if (run.getTrain().getTrainName().equals(TRAIN_2_NAME)) { + train2Runs.add(run); + } + } + Collections.sort(train2Runs); + + log.debug("Train2Runs=" + train2Runs); + + // keep index on train2Runs + int index2Runs = 0; + // find DualHeads and remove two 2-train revenues + for (RevenueTrainRun run:runs) { + // only if train has non zero value + if (run.getTrain().getTrainName().equals(DUALHEAD_NAME) && run.getRunValue() !=0) { + // two trains get removed + index2Runs += 2; + } + } + return train2Runs.subList(0, index2Runs); + } + + + /** + * - checks if runs start and end at major stations + * - allows doubleheading + */ + public int evaluationValue(List<RevenueTrainRun> runs, boolean optimalRuns) { + + + if (optimalRuns) return 0; // optimalRuns are adjusted + + // count the adjustments + int changeRevenues = 0; + for (RevenueTrainRun run:identifyDoubleHeadingTrains(runs)) { + changeRevenues -= run.getRunValue(); + } + return changeRevenues; + } + + public void adjustOptimalRun(List<RevenueTrainRun> optimalRuns) { + // remove the double heading runs from the revenue list + optimalRuns.removeAll(identifyDoubleHeadingTrains(optimalRuns)); + + // remove double heading trains that do not generate value + List<RevenueTrainRun> removeDoubleHeading = new ArrayList<RevenueTrainRun>(); + for (RevenueTrainRun run:optimalRuns) { + if (run.getTrain().getTrainName().equals(DUALHEAD_NAME) && run.getRunValue() == 0) { + removeDoubleHeading.add(run); + } + } + optimalRuns.removeAll(removeDoubleHeading); + } + + public String prettyPrint(RevenueAdapter adapter) { + // nothing to print + return null; + } + +} Property changes on: trunk/18xx/rails/game/specific/_1825/DoubleHeadingModifier.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: trunk/18xx/rails/game/specific/_1825/TerminateAtMajorModifier.java =================================================================== --- trunk/18xx/rails/game/specific/_1825/TerminateAtMajorModifier.java (rev 0) +++ trunk/18xx/rails/game/specific/_1825/TerminateAtMajorModifier.java 2010-09-17 21:24:13 UTC (rev 1424) @@ -0,0 +1,55 @@ +package rails.game.specific._1825; + +import java.util.ArrayList; +import java.util.List; + +import rails.algorithms.RevenueAdapter; +import rails.algorithms.RevenueDynamicModifier; +import rails.algorithms.RevenueTrainRun; + +public class TerminateAtMajorModifier implements RevenueDynamicModifier { + + public boolean prepareModifier(RevenueAdapter revenueAdapter) { + // always active + return true; + } + + public int predictionValue() { + // cannot be predicted + return 0; + } + + private List<RevenueTrainRun> identifyInvalidRuns(List<RevenueTrainRun> runs) { + // check if runs end and start at major stations + List<RevenueTrainRun> invalidRuns = new ArrayList<RevenueTrainRun>(); + for (RevenueTrainRun run:runs) { + if (!run.hasAValidRun()) continue; + if (!run.getFirstVertex().isMajor() || !run.getLastVertex().isMajor()) { + invalidRuns.add(run); + } + } + return invalidRuns; + } + + public int evaluationValue(List<RevenueTrainRun> runs, boolean optimalRuns) { + // optimal runs is already adjusted + if (optimalRuns) return 0; + // otherwise check invalid runs + int changeRevenues = 0; + for (RevenueTrainRun run:identifyInvalidRuns(runs)) { + changeRevenues -= run.getRunValue(); + } + return changeRevenues; + } + + public void adjustOptimalRun(List<RevenueTrainRun> optimalRuns) { + // remove invalid runs + optimalRuns.removeAll(identifyInvalidRuns(optimalRuns)); + } + + public String prettyPrint(RevenueAdapter adapter) { + // nothing to do + return null; + } + +} Property changes on: trunk/18xx/rails/game/specific/_1825/TerminateAtMajorModifier.java ___________________________________________________________________ Added: svn:mime-type + text/plain Modified: trunk/18xx/rails/game/specific/_18AL/NamedTrainRevenueModifier.java =================================================================== --- trunk/18xx/rails/game/specific/_18AL/NamedTrainRevenueModifier.java 2010-09-17 18:39:08 UTC (rev 1423) +++ trunk/18xx/rails/game/specific/_18AL/NamedTrainRevenueModifier.java 2010-09-17 21:24:13 UTC (rev 1424) @@ -102,7 +102,7 @@ return bonusMaximum; } - public int evaluationValue(List<RevenueTrainRun> runs) { + public int evaluationValue(List<RevenueTrainRun> runs, boolean optimalRuns) { int bonusValue = 0; // due to the geography (off-map areas!) each train can only score one bonus for (RevenueBonus bonus:bonuses) { @@ -116,6 +116,10 @@ return bonusValue; } + public void adjustOptimalRun(List<RevenueTrainRun> optimalRuns) { + // do nothing here (all is done by changing the evaluation value) + } + public String prettyPrint(RevenueAdapter revenueAdapter) { List<RevenueTrainRun> runs = revenueAdapter.getOptimalRun(); StringBuffer prettyPrint = new StringBuffer(); @@ -131,4 +135,5 @@ } + } Modified: trunk/18xx/rails/game/specific/_18EU/PullmanRevenueModifier.java =================================================================== --- trunk/18xx/rails/game/specific/_18EU/PullmanRevenueModifier.java 2010-09-17 18:39:08 UTC (rev 1423) +++ trunk/18xx/rails/game/specific/_18EU/PullmanRevenueModifier.java 2010-09-17 21:24:13 UTC (rev 1424) @@ -32,7 +32,7 @@ return true; } - public int evaluationValue(List<RevenueTrainRun> runs) { + public int evaluationValue(List<RevenueTrainRun> runs, boolean optimalRuns) { return pullmanValue(runs); } @@ -49,6 +49,10 @@ return maxValue; } + public void adjustOptimalRun(List<RevenueTrainRun> optimalRuns) { + // do nothing here (all is done by changing the evaluation value) + } + public String prettyPrint(RevenueAdapter revenueAdapter) { return LocalText.getText("Pullman") + " = " + pullmanValue(revenueAdapter.getOptimalRun()); } @@ -61,4 +65,5 @@ } return maximum; } + } Modified: trunk/18xx/rails/game/state/ArrayListState.java =================================================================== --- trunk/18xx/rails/game/state/ArrayListState.java 2010-09-17 18:39:08 UTC (rev 1423) +++ trunk/18xx/rails/game/state/ArrayListState.java 2010-09-17 21:24:13 UTC (rev 1424) @@ -7,6 +7,7 @@ import rails.game.move.AddToList; import rails.game.move.RemoveFromList; +import rails.game.move.SetChange; /** * State class that wraps an ArrayList @@ -49,8 +50,13 @@ new AddToList<E>(list, element, listName).atIndex(index); } - public void remove(E element) { - new RemoveFromList<E>(list, element, listName); + public boolean remove(E element) { + if (list.contains(element)) { + new RemoveFromList<E>(list, element, listName); + return true; + } else { + return false; + } } public void clear() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |