From: Stefan F. <ste...@us...> - 2012-09-08 07:09:27
|
junit/rails/game/state/BooleanStateTest.java | 4 junit/rails/game/state/CountableItemImpl.java | 13 junit/rails/game/state/GenericStateTest.java | 4 junit/rails/game/state/HashSetStateTest.java | 3 junit/rails/game/state/IntegerStateTest.java | 2 junit/rails/game/state/ModelImpl.java | 2 junit/rails/game/state/ObservableTest.java | 61 -- junit/rails/game/state/StateManagerTest.java | 4 junit/rails/game/state/StateTest.java | 12 junit/rails/game/state/StringStateTest.java | 8 junit/rails/game/state/WalletBagTest.java | 53 + junit/rails/game/state/WalletManagerTest.java | 110 ++++ src/rails/algorithms/NetworkGraphBuilder.java | 2 src/rails/game/Bank.java | 36 - src/rails/game/BaseToken.java | 1 src/rails/game/GameManager.java | 26 src/rails/game/MapHex.java | 353 ++++++------- src/rails/game/OperatingRound.java | 54 + src/rails/game/Player.java | 4 src/rails/game/PublicCompany.java | 141 ++--- src/rails/game/Round.java | 7 src/rails/game/ShareSellingRound.java | 3 src/rails/game/StartItem.java | 8 src/rails/game/StartRound.java | 3 src/rails/game/StartRound_1830.java | 5 src/rails/game/StartRound_1835.java | 3 src/rails/game/Station.java | 94 +-- src/rails/game/StationHolder.java | 15 src/rails/game/StockRound.java | 12 src/rails/game/Stop.java | 86 +-- src/rails/game/Tile.java | 77 +- src/rails/game/TileManager.java | 2 src/rails/game/Track.java | 27 src/rails/game/TreasuryShareRound.java | 7 src/rails/game/action/BuyCertificate.java | 15 src/rails/game/action/BuyTrain.java | 22 src/rails/game/action/DiscardTrain.java | 2 src/rails/game/action/LayTile.java | 48 - src/rails/game/action/PossibleORAction.java | 4 src/rails/game/action/StartCompany.java | 9 src/rails/game/correct/CashCorrectionManager.java | 3 src/rails/game/correct/CorrectionManager.java | 3 src/rails/game/correct/MapCorrectionAction.java | 4 src/rails/game/correct/MapCorrectionManager.java | 7 src/rails/game/model/BaseTokensModel.java | 45 + src/rails/game/model/PortfolioModel.java | 36 - src/rails/game/model/PresidentModel.java | 6 src/rails/game/model/WalletMoneyModel.java | 1 src/rails/game/specific/_1835/OperatingRound_1835.java | 3 src/rails/game/specific/_1835/PrussianFormationRound.java | 13 src/rails/game/specific/_1856/CGRFormationRound.java | 33 - src/rails/game/specific/_1880/StartRound_1880.java | 5 src/rails/game/specific/_1889/OperatingRound_1889.java | 9 src/rails/game/specific/_18AL/OperatingRound_18AL.java | 3 src/rails/game/specific/_18EU/FinalMinorExchangeRound.java | 3 src/rails/game/specific/_18EU/StartCompany_18EU.java | 4 src/rails/game/specific/_18EU/StartRound_18EU.java | 7 src/rails/game/specific/_18EU/StockRound_18EU.java | 9 src/rails/game/specific/_18GA/OperatingRound_18GA.java | 4 src/rails/game/state/ArrayListChange.java | 1 src/rails/game/state/Change.java | 2 src/rails/game/state/ChangeSet.java | 16 src/rails/game/state/ChangeStack.java | 14 src/rails/game/state/CountableItem.java | 4 src/rails/game/state/DelayedItem.java | 8 src/rails/game/state/HashMapState.java | 17 src/rails/game/state/Model.java | 30 - src/rails/game/state/Observable.java | 59 -- src/rails/game/state/PortfolioChange.java | 4 src/rails/game/state/PortfolioManager.java | 4 src/rails/game/state/Root.java | 15 src/rails/game/state/State.java | 17 src/rails/game/state/StateManager.java | 150 ++++- src/rails/game/state/TileMove.java | 70 -- src/rails/game/state/Trigger.java | 11 src/rails/game/state/UnknownOwner.java | 2 src/rails/game/state/Wallet.java | 6 src/rails/game/state/WalletBag.java | 7 src/rails/game/state/WalletManager.java | 4 src/rails/game/state/WalletSet.java | 5 src/rails/ui/swing/GameSetupWindow.java | 1 src/rails/ui/swing/RemainingTilesWindow.java | 2 src/rails/ui/swing/hexmap/GUIHex.java | 28 - src/rails/ui/swing/hexmap/GUITile.java | 2 src/rails/ui/swing/hexmap/HexMap.java | 2 src/rails/util/GameFileIO.java | 3 86 files changed, 1042 insertions(+), 982 deletions(-) New commits: commit 40392cca7044d06affcefc3fa6506194be0eff9d Author: Stefan Frey <ste...@we...> Date: Sat Sep 8 06:01:47 2012 +0200 adding Trigger interface, Bank's MoneyModel diff --git a/src/rails/game/Bank.java b/src/rails/game/Bank.java index 2bb285a..2e9d90d 100644 --- a/src/rails/game/Bank.java +++ b/src/rails/game/Bank.java @@ -12,6 +12,9 @@ import rails.common.parser.ConfigurationException; import rails.common.parser.Tag; import rails.game.model.WalletMoneyModel; import rails.game.state.BooleanState; +import rails.game.state.Change; +import rails.game.state.Observable; +import rails.game.state.Trigger; import rails.game.state.UnknownOwner; import rails.util.Util; @@ -44,7 +47,23 @@ public class Bank extends RailsManager implements MoneyOwner, Configurable { /** Is the bank broken */ private final BooleanState broken = BooleanState.create(this, "broken"); - + + // Instance initializer to create a BankBroken model + { + new Trigger() { + {// instance initializer + cash.addTrigger(this); + } + public void triggered(Observable obs, Change change) { + if (cash.value() <= 0 && !broken.value()) { + broken.set(true); + cash.setText(LocalText.getText("BROKEN")); + GameManager.getInstance().registerBrokenBank(); + } + } + }; + } + protected static Logger log = LoggerFactory.getLogger(Bank.class); @@ -137,16 +156,6 @@ public class Bank extends RailsManager implements MoneyOwner, Configurable { return scrapHeap; } - /* FIXME: Add broken check somewhere - * Check if the bank has broken. In some games <0 could apply, so this - * will become configurable. - if (cash.value() <= 0 && !broken.booleanValue()) { - broken.set(true); - cash.setText(LocalText.getText("BROKEN")); - GameManager.getInstance().registerBrokenBank(); - } - */ - /** * @return Portfolio of stock in Bank Pool */ @@ -161,10 +170,10 @@ public class Bank extends RailsManager implements MoneyOwner, Configurable { return unavailable; } - public String getId() { + public String toText() { return LocalText.getText("BANK"); } - + // MoneyOwner interface public int getCash() { return cash.value(); @@ -174,4 +183,5 @@ public class Bank extends RailsManager implements MoneyOwner, Configurable { return cash; } + } diff --git a/src/rails/game/model/WalletMoneyModel.java b/src/rails/game/model/WalletMoneyModel.java index 4cbbf75..1d58f6e 100644 --- a/src/rails/game/model/WalletMoneyModel.java +++ b/src/rails/game/model/WalletMoneyModel.java @@ -17,6 +17,7 @@ public class WalletMoneyModel extends MoneyModel { private WalletMoneyModel(MoneyOwner parent, String id, Boolean init, Currency currency) { super(parent, id, currency); wallet = WalletBag.create(parent, "wallet", Currency.class, currency); + wallet.addModel(this); initialised = BooleanState.create(this, "initialised", init); } diff --git a/src/rails/game/state/ChangeSet.java b/src/rails/game/state/ChangeSet.java index 2203de5..5395dde 100644 --- a/src/rails/game/state/ChangeSet.java +++ b/src/rails/game/state/ChangeSet.java @@ -45,7 +45,7 @@ public class ChangeSet { log.debug("Add " + change); // immediate execution and information of models change.execute(); - change.getState().sendChangeToModels(change); + change.getState().informTriggers(change); } /** diff --git a/src/rails/game/state/Model.java b/src/rails/game/state/Model.java index 5bad3d9..5f3c727 100644 --- a/src/rails/game/state/Model.java +++ b/src/rails/game/state/Model.java @@ -16,12 +16,4 @@ public abstract class Model extends Observable { super(parent, id); } - /** - * Calling of update informs the model that some state has changed - * Overriding this does not require a call, as it usually does nothing - */ - public void update(Change change) { - // Standard behavior is do nothing - } - } diff --git a/src/rails/game/state/Observable.java b/src/rails/game/state/Observable.java index cab77d9..08ae14d 100644 --- a/src/rails/game/state/Observable.java +++ b/src/rails/game/state/Observable.java @@ -69,6 +69,18 @@ public abstract class Observable implements Item { return getStateManager().getModels(this); } + public void addTrigger(Trigger m) { + getStateManager().addTrigger(m, this); + } + + public boolean removeTrigger(Trigger m) { + return getStateManager().removeTrigger(m, this); + } + + public ImmutableSet<Trigger> getTriggers() { + return getStateManager().getTriggers(this); + } + /** * Text to delivered to Observers * Default is defined to be identical with toString() diff --git a/src/rails/game/state/State.java b/src/rails/game/state/State.java index ed4a580..c69b480 100644 --- a/src/rails/game/state/State.java +++ b/src/rails/game/state/State.java @@ -26,8 +26,8 @@ public abstract class State extends Observable { } } - void sendChangeToModels(Change change) { - this.getStateManager().sendChangeToModels(this, change); + void informTriggers(Change change) { + this.getStateManager().informTriggers(this, change); } } \ No newline at end of file diff --git a/src/rails/game/state/StateManager.java b/src/rails/game/state/StateManager.java index 18a12b1..26648a1 100644 --- a/src/rails/game/state/StateManager.java +++ b/src/rails/game/state/StateManager.java @@ -27,6 +27,9 @@ public final class StateManager extends Manager{ HashSetState.create(this, "allStates"); private final HashMultimapState<Observable, Model> models = HashMultimapState.create(this, "models"); + private final HashMultimapState<Observable, Trigger> triggers = + HashMultimapState.create(this, "triggers"); + // observers is not a state variable (as the have to register and de-register themselves) // gui eleemnts do not have a state of their own (with respect to the game engine) @@ -102,7 +105,7 @@ public final class StateManager extends Manager{ /** * Adds the combination of model to observable - * @param Model the model that tracks the observable + * @param Model the model that is updated by the observable * @param Observable the observable to monitor */ void addModel(Model model, Observable observable) { @@ -117,16 +120,42 @@ public final class StateManager extends Manager{ return models.get(observable); } + /** + * Adds the combination of trigger to observable + * @param Trigger the trigger that tracks the observable + * @param Observable the observable to monitor + */ + void addTrigger(Trigger trigger, Observable observable) { + triggers.put(observable, trigger); + } + + boolean removeTrigger(Trigger trigger, Observable observable) { + return triggers.remove(observable, trigger); + } - void sendChangeToModels(State state, Change change) { + ImmutableSet<Trigger> getTriggers(Observable observable) { + return triggers.get(observable); + } + + void informTriggers(State state, Change change) { + + // Inform direct triggers + for (Trigger t:getTriggers(state)) { + t.triggered(state, change); + log.debug("State " + state + " sends change to Trigger " + t); + } + // check if there are models - ImmutableSet<Model> initModels = state.getModels(); + ImmutableSet<Model> initModels = getModels(state); if (initModels.isEmpty()) return; ImmutableList<Model> allModels = getModelsToUpdate(initModels); + // Inform indirect triggers for (Model m:allModels) { - m.update(change); - log.debug("State " + state + " sends change to Model " + m); + for (Trigger t:getTriggers(m)) { + t.triggered(m, change); + log.debug("Model " + m + " sends change to Trigger " + t); + } } } @@ -155,7 +184,7 @@ public final class StateManager extends Manager{ private static enum Color {WHITE, GREY, BLACK}; private void topoSort(final Observable v, final Map<Observable, Color> colors, final LinkedList<Model> topoList) { colors.put(v, Color.GREY); - for (Model m:v.getModels()) { + for (Model m:getModels(v)) { if (!colors.containsKey(m)) { topoSort(m, colors, topoList); } else if (colors.get(m) == Color.GREY) { @@ -170,7 +199,7 @@ public final class StateManager extends Manager{ void updateObservers(Set<State> states) { // all direct observers for (State s:states){ - Set<Observer> observers = s.getObservers(); + Set<Observer> observers = getObservers(s); if (observers.isEmpty()) continue; // cache StateText String stateText = s.toText(); @@ -182,7 +211,7 @@ public final class StateManager extends Manager{ // all indirect observers for (Model m:getModelsToUpdate(states)) { - Set<Observer> observers = m.getObservers(); + Set<Observer> observers = getObservers(m); if (observers.isEmpty()) continue; // cache ModelText String modelText = m.toText(); diff --git a/src/rails/game/state/Trigger.java b/src/rails/game/state/Trigger.java new file mode 100644 index 0000000..6d98021 --- /dev/null +++ b/src/rails/game/state/Trigger.java @@ -0,0 +1,11 @@ +package rails.game.state; + +public interface Trigger { + + /** + * Method that is called if something has changed + */ + public void triggered(Observable observable, Change change); + + +} commit 7e1968117743a8cff1d809da5381dc499061b1a7 Author: Stefan Frey <ste...@we...> Date: Fri Sep 7 12:48:10 2012 +0200 fixed several minor bugs diff --git a/src/rails/game/GameManager.java b/src/rails/game/GameManager.java index a108723..defc765 100644 --- a/src/rails/game/GameManager.java +++ b/src/rails/game/GameManager.java @@ -767,9 +767,10 @@ public class GameManager extends RailsManager implements Configurable, Owner { interruptedRound = getCurrentRound(); + // An id basd on interruptedRound and company id + String id = "SSR_" + interruptedRound.getId() + "_" + cashNeedingCompany.getId(); // check if other companies can be dumped - // FIXME: This ID will not work, as it will create duplication - createRound(shareSellingRoundClass, "ShareSellingRound").start( + createRound(shareSellingRoundClass, id).start( interruptedRound, player, cashToRaise, cashNeedingCompany, !problemDumpOtherCompanies || forcedSellingCompanyDump); // the last parameter indicates if the dump of other companies is allowed, either this is explicit or diff --git a/src/rails/game/MapHex.java b/src/rails/game/MapHex.java index 3d0a8f4..7714ff8 100644 --- a/src/rails/game/MapHex.java +++ b/src/rails/game/MapHex.java @@ -20,8 +20,6 @@ import rails.game.Stop.RunTo; import rails.game.Stop.Score; import rails.game.Stop.Type; import rails.game.action.LayTile; -import rails.game.model.WalletMoneyModel; -import rails.game.model.PortfolioModel; import rails.game.state.BooleanState; import rails.game.state.GenericState; @@ -1278,8 +1276,8 @@ public class MapHex extends Model implements RailsItem, Owner, Configurable { * * @TODO include tokens?? */ - public String getData() { - return currentTile.value().getNb() + "/" + currentTileRotation; + public String toText() { + return currentTile.value().getNb() + "/" + currentTileRotation.value(); } /** @@ -1352,27 +1350,4 @@ public class MapHex extends Model implements RailsItem, Owner, Configurable { return scoreType; } - // Owner interface - - public boolean hasPortfolio() { - return false; - } - - public PortfolioModel getPortfolioModel() { - return null; - } - - public boolean hasCash() { - return false; - } - - public WalletMoneyModel getCash() { - return null; - } - - public void update() { - // TODO Auto-generated method stub - - } - } diff --git a/src/rails/game/OperatingRound.java b/src/rails/game/OperatingRound.java index aa0e49b..d0b5631 100644 --- a/src/rails/game/OperatingRound.java +++ b/src/rails/game/OperatingRound.java @@ -308,7 +308,7 @@ public class OperatingRound extends Round implements Observer { result = done(nullAction); break; case NullAction.SKIP: - skip(); + skip(nullAction); result = true; break; } @@ -703,10 +703,11 @@ public class OperatingRound extends Round implements Observer { } while (++stepIndex < steps.length) { step = steps[stepIndex]; - log.debug("Step " + step); + log.debug("OR considers step " + step); if (step == GameDef.OrStep.LAY_TOKEN && company.getNumberOfFreeBaseTokens() == 0) { + log.debug("OR skips " + step + ": No freeBaseTokens"); continue; } @@ -714,6 +715,7 @@ public class OperatingRound extends Round implements Observer { if (!company.canRunTrains()) { // No trains, then the revenue is zero. + log.debug("OR skips " + step + ": Cannot run trains"); executeSetRevenueAndDividend ( new SetDividend (0, false, new int[] {SetDividend.NO_TRAIN})); // TODO: This probably does not handle share selling correctly @@ -723,6 +725,7 @@ public class OperatingRound extends Round implements Observer { if (step == GameDef.OrStep.PAYOUT) { // This step is now obsolete + log.debug("OR skips " + step + ": Always skipped"); continue; } @@ -767,7 +770,10 @@ public class OperatingRound extends Round implements Observer { } - if (!gameSpecificNextStep (step)) continue; + if (!gameSpecificNextStep (step)) { + log.debug("OR skips " + step + ": Not game specific"); + continue; + } // No reason found to skip this step break; @@ -808,10 +814,10 @@ public class OperatingRound extends Round implements Observer { * 3.1. NOOPS *=======================================*/ - public void skip() { + public void skip(NullAction action) { log.debug("Skip step " + stepObject.value()); // TODO: Check if this is ok - // FIXME: changeStack.start(true); + ChangeStack.start(this, action); nextStep(); } @@ -2742,7 +2748,7 @@ public class OperatingRound extends Round implements Observer { operatingCompany.value().buyTrain(train, price); - if (oldOwner == ipo.getTrainsModel()) { + if (oldOwner == ipo.getParent()) { train.getCertType().addToBoughtFromIPO(); trainManager.setAnyTrainBought(true); // Clone the train if infinitely available @@ -2751,7 +2757,7 @@ public class OperatingRound extends Round implements Observer { } } - if (oldOwner instanceof Bank) { + if (oldOwner instanceof BankPortfolio) { trainsBoughtThisTurn.add(train.getCertType()); } diff --git a/src/rails/game/action/BuyCertificate.java b/src/rails/game/action/BuyCertificate.java index 4401351..a6f400c 100644 --- a/src/rails/game/action/BuyCertificate.java +++ b/src/rails/game/action/BuyCertificate.java @@ -7,9 +7,6 @@ import rails.game.*; import rails.game.model.PortfolioModel; import rails.game.model.PortfolioOwner; -/** - * @author Erik Vos - */ public class BuyCertificate extends PossibleAction { // Server-side settings diff --git a/src/rails/game/action/BuyTrain.java b/src/rails/game/action/BuyTrain.java index a15a02f..518c32a 100644 --- a/src/rails/game/action/BuyTrain.java +++ b/src/rails/game/action/BuyTrain.java @@ -5,6 +5,8 @@ import java.io.ObjectInputStream; import java.util.HashSet; import java.util.Set; +import com.google.common.base.Objects; + import rails.game.CompanyManager; import rails.game.Currency; import rails.game.GameManager; @@ -218,7 +220,7 @@ public class BuyTrain extends PossibleORAction { } b.append("train (").append(trainUniqueId).append(") from ").append(from.getId()); if (fixedCost > 0) { - b.append(" for ").append(Currency.format(train, fixedCost)); + b.append(" for ").append(Currency.format(company, fixedCost)); } else { b.append(" for any amount"); } @@ -229,14 +231,14 @@ public class BuyTrain extends PossibleORAction { b.append(forcedExchange ? " (forced exchange)" : " (exchange)"); } if (presidentMustAddCash) { - b.append(" must add cash ").append(Currency.format(train, presidentCashToAdd)); + b.append(" must add cash ").append(Currency.format(company, presidentCashToAdd)); } else if (presidentMayAddCash) { b.append(" may add cash up to ").append( - Currency.format(train, presidentCashToAdd)); + Currency.format(company, presidentCashToAdd)); } if (acted) { - b.append(" - paid: ").append(Currency.format(train, pricePaid)); - if (addedCash > 0) b.append(" pres.cash added: "+Currency.format(train, addedCash)); + b.append(" - paid: ").append(Currency.format(company, pricePaid)); + if (addedCash > 0) b.append(" pres.cash added: "+Currency.fo |