diff --git a/src/main/java/net/sf/rails/algorithms/NetworkVertex.java b/src/main/java/net/sf/rails/algorithms/NetworkVertex.java index 8c871d00f..e3be59525 100644 --- a/src/main/java/net/sf/rails/algorithms/NetworkVertex.java +++ b/src/main/java/net/sf/rails/algorithms/NetworkVertex.java @@ -49,6 +49,7 @@ public enum StationType { // only for station objects private final Stop stop; + private RevenueManager revenueManager; /** constructor for station on mapHex */ public NetworkVertex(MapHex hex, Station station) { @@ -64,6 +65,8 @@ public NetworkVertex(MapHex hex, Station station) { this.virtual = false; this.virtualId = null; + + this.revenueManager = hex.getRoot().getRevenueManager(); } /** constructor for side on mapHex */ @@ -157,6 +160,7 @@ public int getValue() { return value; } + /* public int getValueByTrain(NetworkTrain train) { int valueByTrain; if (isMajor()) { @@ -174,6 +178,41 @@ public int getValueByTrain(NetworkTrain train) { valueByTrain = value; } return valueByTrain; + }*/ + public int getValueByTrain (NetworkTrain train) { + /* + int valueByTrain = 0; + switch (stop.getType()) { + case CITY: + valueByTrain = value * train.getMultiplyMajors(); + break; + case TOWN: + if (!train.ignoresMinors()) { + valueByTrain = value * train.getMultiplyMinors(); + } + break; + case OFFMAP: + valueByTrain = hex.getCurrentValueForPhase( + hex.getRoot().getPhaseManager().getCurrentPhase()); + break; + case MINE: + // For 18VA (see GameManager_18VA). Default return value is 0. + valueByTrain = hex.getValuePerTrain(train.getRailsTrain()); + break; + case PASS: + valueByTrain = 0; + break; + default: + valueByTrain = value; + break; + } + return valueByTrain;*/ + Train railsTrain= train.getRailsTrain(); + PublicCompany company = (PublicCompany)railsTrain.getOwner(); + int revenue = revenueManager.getActualAsInteger(stop, railsTrain, + company); + log.debug("+++++ Vertex {} has value {} for train {} of {}", this, revenue, train, company); + return revenue; } public NetworkVertex setValue(int value) { @@ -244,7 +283,7 @@ public boolean initRailsVertex(PublicCompany company, boolean running) { // if company == null, then no vertex gets removed if (company != null && !stop.isRunToAllowedFor(company, running) && !stop.isRunThroughAllowedFor(company)) { - log.info("Vertex is removed"); + log.debug("Vertex is removed"); return false; } @@ -252,7 +291,11 @@ public boolean initRailsVertex(PublicCompany company, boolean running) { if (stop.getScoreType() == Access.Score.MAJOR) { setStationType(StationType.MAJOR); } else if (stop.getScoreType() == Access.Score.MINOR) { - setStationType(StationType.MINOR); + //if (stop.getAccess() != null && stop.getAccess().getType() == Stop.Type.MINE) { + // setStationType(StationType.COALMINE); + //} else { + setStationType(StationType.MINOR); + //} } else if (stop.getScoreType() == Access.Score.NO) { // Used in 18EU Alpine variant setStationType(StationType.PASS); // Not sure if this is sensible for 18EU } @@ -285,8 +328,6 @@ public boolean initRailsVertex(PublicCompany company, boolean running) { public void setRailsVertexValue(Phase phase) { // side vertices and virtuals cannot use this function if (virtual || type == VertexType.SIDE) return; - - // define value value = stop.getValueForPhase(phase); } @@ -524,6 +565,7 @@ public static Rectangle getVertexMapCoverage(HexMap map, Collection getOptimalRun() { if (optimalRun == null) { optimalRun = convertRcRun(rc.getOptimalRun()); diff --git a/src/main/java/net/sf/rails/algorithms/RevenueManager.java b/src/main/java/net/sf/rails/algorithms/RevenueManager.java index f05b63c62..d7e45f5b3 100644 --- a/src/main/java/net/sf/rails/algorithms/RevenueManager.java +++ b/src/main/java/net/sf/rails/algorithms/RevenueManager.java @@ -8,9 +8,7 @@ import net.sf.rails.common.parser.Configurable; import net.sf.rails.common.parser.ConfigurationException; import net.sf.rails.common.parser.Tag; -import net.sf.rails.game.PublicCompany; -import net.sf.rails.game.RailsManager; -import net.sf.rails.game.RailsRoot; +import net.sf.rails.game.*; import net.sf.rails.game.state.ArrayListState; import org.slf4j.Logger; @@ -18,14 +16,16 @@ /** - * Coordinates and stores all elements related to revenue calulcation, + * Coordinates and stores all elements related to revenue calculation, * which are permanent. * The conversion of Rails elements is in the responsibility of the RevenueAdapter. * For each GameManager instance only one RevenueManager is created. */ -public final class RevenueManager extends RailsManager implements Configurable { +public class RevenueManager extends RailsManager implements Configurable { - private int specialRevenue; + protected int specialRevenue; + protected RailsRoot root; + protected PhaseManager phaseManager; private static final Logger log = LoggerFactory.getLogger(RevenueManager.class); @@ -49,6 +49,8 @@ public final class RevenueManager extends RailsManager implements Configurable { */ public RevenueManager(RailsRoot parent, String id) { super(parent, id); + this.root = parent; + this.phaseManager = root.getPhaseManager(); } public void configureFromXML(Tag tag) throws ConfigurationException { @@ -206,7 +208,7 @@ boolean initDynamicModifiers(RevenueAdapter revenueAdapter) { * @return revenue from active calculator */ // FIXME: This does not fully cover all cases that needs the revenue from the calculator - // EV: indeed, it used in a different way in 1837, so beware! + // EV: indeed, it is used in a different way in 1837, so beware! // See RunToCoalMineModifier. int revenueFromDynamicCalculator(RevenueAdapter revenueAdapter) { return calculatorModifier.calculateRevenue(revenueAdapter); @@ -271,7 +273,7 @@ int predictionValue(List run) { * @param revenueAdapter * @return pretty print output from all modifiers (both static and dynamic) */ - String prettyPrint(RevenueAdapter revenueAdapter) { + protected String prettyPrint(RevenueAdapter revenueAdapter) { StringBuilder prettyPrint = new StringBuilder(); for (RevenueStaticModifier modifier : activeStaticModifiers) { @@ -291,5 +293,84 @@ String prettyPrint(RevenueAdapter revenueAdapter) { return prettyPrint.toString(); } + /*--------------------------- + * The below new section of RevenueManager provides a generic interface + * to obtain the actual revenue values of stops of any kind. + * Game-specific subclasses can provide special cases. + * + * These methods are used by + * - NetworkVertex, to initialise stop values per train + * in getValueByTrain(). + * - Dynamic modifiers (currently 18VA only, TBD). + * + * The methods getBaseRevenue() and getExtraRevenue() can be + * overridden in subclasses of RevenueManager (which is no longer final). + * This allows to specify the actual revenue value of stops + * per stop type, train type en company details, as needed. + * + * Method getExtraRevenue() was intended to return any extra values + * that should be returned by predictionValue() in dynamic modifiers. + * However, the flexibility of getBaseRevenue() should allow + * getExtraRevenue to return zero at all times. + * + * Revenues are returned as objects of the new Revenue class, + * which can carry both normal and special revenue values. + * Special values include the direct-to-treasury amounts + * of 1837 and 18VA (revenue from mines). + * + * Created 04/2023 by Erik Vos + */ + + /* 'Actual revenue' is the final value of a stop for a given + * train and company. This is the value with which NetworkVertex + * objects can b e initialized. + * + * @param stop The stop for which a revenue value is requested + * @param train A specific train that may affect the revenue, + * or null if the train does not matter + * @param company A specific company that may affect the revenue, + * or null if the company does not matter + * @return A new Revenue object + */ + public final Revenue getActualRevenue(Stop stop, Train train, PublicCompany company) { + return getBaseRevenue (stop, train, company) + .addRevenue (getExtraRevenue(stop, train, company)); + } + + public final int getActualAsInteger (Stop stop, Train train, PublicCompany company) { + Revenue rev = getActualRevenue(stop, train, company); + return rev.getNormalRevenue() + rev.getSpecialRevenue(); + } + + /** Same as getRevenue(), but intended to get + * additional revenue vales, as are needed for + * the predictionValue() methods in dynamic modifiers. + * + * This method may not be really needed anymore, as getActualRevenue + * now provides the final value per NetworkVertex, rather than a loosely + * predicted one. + */ + public Revenue getExtraRevenue (Stop stop, Train train, PublicCompany company) { + + return new Revenue (0, 0); + } + + public final int getExtraAsInteger (Stop stop, Train train, PublicCompany company) { + Revenue rev = getExtraRevenue(stop, train, company); + return rev.getNormalRevenue() + rev.getSpecialRevenue(); + } + + /** Return the revenue insofar it could be configured. + * This probably represents the former initial NetworkVertex revenue, + * and it still is the default for the new actual revenue. + * + * @param stop + * @param train + * @param company + * @return + */ + protected Revenue getBaseRevenue (Stop stop, Train train, PublicCompany company) { + return new Revenue (stop.getValueForPhase(phaseManager.getCurrentPhase()),0); + } } diff --git a/src/main/java/net/sf/rails/game/GameManager.java b/src/main/java/net/sf/rails/game/GameManager.java index 485ff8703..9c574d1f5 100644 --- a/src/main/java/net/sf/rails/game/GameManager.java +++ b/src/main/java/net/sf/rails/game/GameManager.java @@ -594,7 +594,7 @@ public void nextRound(Round round) { if (currentPhase.getNumberOfOperatingRounds() != numOfORs.value()) { numOfORs.set(currentPhase.getNumberOfOperatingRounds()); } - log.info("Phase={} ORs={}", currentPhase.toText(), numOfORs); + log.debug("Phase={} ORs={}", currentPhase.toText(), numOfORs); // Create a new OperatingRound (never more than one Stock Round) // OperatingRound.resetRelativeORNumber(); @@ -1935,6 +1935,16 @@ public boolean isTrainBlocked (Train train) { return blockedTrains.contains(train); } + /** Stub for train-type dependent stop values. + * Used in 18VA for CMD value (see GameManager_18VA). + * The given default value of 0 is correct for 1837. + * @param train The train + * @return The train-dependent value of a stop + */ + public int getValuePerTrain (Train train) { + return 0; + } + //------------------------------------ // Random generator diff --git a/src/main/java/net/sf/rails/game/MapHex.java b/src/main/java/net/sf/rails/game/MapHex.java index 0f39d813c..98b74cd03 100644 --- a/src/main/java/net/sf/rails/game/MapHex.java +++ b/src/main/java/net/sf/rails/game/MapHex.java @@ -35,6 +35,12 @@ */ public class MapHex extends RailsModel implements RailsOwner, Configurable { + public enum ValueType { + PERTILE, // Default + PERPHASE, // Default for offmap tiles + PERTRAIN // So far for 18VA CMD only + } + private static final Logger log = LoggerFactory.getLogger(MapHex.class); public static class Coordinates { @@ -166,6 +172,7 @@ public String toString() { * Values if this is an off-board hex */ private List valuesPerPhase = null; + private ValueType valueType = ValueType.PERTILE; /* * Temporary storage for impassable hexsides. Once neighbours has been set @@ -254,6 +261,9 @@ public enum BlockedToken { private final PortfolioSet bonusTokens = PortfolioSet.create(this, "bonusTokens", BonusToken.class); + private final PortfolioSet offStationBaseTokens + = PortfolioSet.create(this, "offStationBaseTokens", BaseToken.class); + /** * Parameters for extra text to be printed at a specified position on the hex. * Added for 1837 to print coal mine names @@ -295,7 +305,10 @@ public void configureFromXML(Tag tag) throws ConfigurationException { label = tag.getAttributeAsString("label", ""); // Off-board revenue values + String valueTypeString = tag.getAttributeAsString("valueType", "perTile"); + valueType = ValueType.valueOf(valueTypeString.toUpperCase()); valuesPerPhase = tag.getAttributeAsIntegerList("value"); + if (!valuesPerPhase.isEmpty()) valueType = ValueType.PERPHASE; // Location name stopName = tag.getAttributeAsString("city", ""); @@ -829,6 +842,12 @@ public boolean layBaseToken(PublicCompany company, Stop stop) { } } + /** Lay an off-station base token, as in 18VA */ + public boolean layOffStationBaseToken (BaseToken token) { + offStationBaseTokens.add(token); + return true; + } + /** * Lay a bonus token. * @@ -856,6 +875,10 @@ public PortfolioSet getBonusTokens() { return bonusTokens; } + public PortfolioSet getOffStationBaseTokens() { + return offStationBaseTokens; + } + public boolean hasTokenSlotsLeft(Station station) { // FIXME: Is this still required // if (station == 0) station = 1; // Temp. fix for old save files @@ -1099,6 +1122,10 @@ public List getValuesPerPhase() { return valuesPerPhase; } + public ValueType getValueType() { + return valueType; + } + public int getCurrentValueForPhase(Phase phase) { if (hasValuesPerPhase() && phase != null) { return valuesPerPhase.get(Math.min(valuesPerPhase.size(), @@ -1108,6 +1135,10 @@ public int getCurrentValueForPhase(Phase phase) { } } + public int getValuePerTrain (Train train) { + return getRoot().getGameManager().getValuePerTrain(train); + } + public String getStopName() { return stopName; } diff --git a/src/main/java/net/sf/rails/game/OperatingRound.java b/src/main/java/net/sf/rails/game/OperatingRound.java index a6f005dab..2175ba75e 100644 --- a/src/main/java/net/sf/rails/game/OperatingRound.java +++ b/src/main/java/net/sf/rails/game/OperatingRound.java @@ -11,7 +11,6 @@ import net.sf.rails.game.state.Observer; import net.sf.rails.game.state.*; import net.sf.rails.util.SequenceUtil; -import net.sf.rails.util.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import rails.game.action.*; @@ -910,10 +909,14 @@ protected void nextStep(GameDef.OrStep step) { log.debug("OR considers newStep {}", newStep); if (newStep == GameDef.OrStep.LAY_TRACK) { + if (noMapMode) continue; initNormalTileLays(); } if (newStep == GameDef.OrStep.LAY_TOKEN) { + + if (noMapMode) continue; + log.debug ("No normal token laid yet"); /* List bonuses = gameManager.getCommonSpecialProperties(); boolean bonusTokensForSale = @@ -2152,6 +2155,8 @@ public boolean layBaseToken(LayBaseToken action) { PublicCompany company = action.getCompany(); String companyName = company.getId(); + boolean nonCity = (action.getType() == LayBaseToken.NON_CITY); + // Dummy loop to enable a quick jump out. while (true) { @@ -2162,7 +2167,8 @@ public boolean layBaseToken(LayBaseToken action) { && action.getType() != LayBaseToken.HOME_CITY && action.getType() != LayBaseToken.SPECIAL_PROPERTY && action.getType() != LayBaseToken.CORRECTION - && action.getType() != LayBaseToken.FORCED_LAY) { + && action.getType() != LayBaseToken.FORCED_LAY + && !nonCity) { errMsg = LocalText.getText("WrongActionNoTokenLay"); break; } @@ -2172,12 +2178,12 @@ public boolean layBaseToken(LayBaseToken action) { break; } - if (!isTokenLayAllowed(company, hex, stop)) { + if (!nonCity && !isTokenLayAllowed(company, hex, stop)) { errMsg = LocalText.getText("BaseTokenSlotIsReserved"); break; } - if (!stop.hasTokenSlotsLeft()) { + if (!nonCity && !stop.hasTokenSlotsLeft()) { errMsg = LocalText.getText("CityHasNoEmptySlots"); break; } @@ -2238,8 +2244,14 @@ public boolean layBaseToken(LayBaseToken action) { } /* End of validation, start of execution */ + boolean result; - if (hex.layBaseToken(company, stop)) { + if (nonCity) { + result = hex.layOffStationBaseToken(BaseToken.create(company)); + } else { + result = hex.layBaseToken(company, stop); + } + if (result) { /* TODO: the false return value must be impossible. */ company.layBaseToken(hex, cost); @@ -2286,7 +2298,7 @@ public boolean layBaseToken(LayBaseToken action) { if (currentNormalTokenLays.isEmpty()) { log.debug("No more normal token lays are allowed"); } else if (operatingCompany.value().getNumberOfFreeBaseTokens() == 0) { - log.debug("Normal token lay allowed by no more tokens"); + log.debug("Normal token lay allowed but no more tokens"); currentNormalTokenLays.clear(); } else { log.debug("A normal token lay is still allowed"); @@ -2295,7 +2307,8 @@ public boolean layBaseToken(LayBaseToken action) { log.debug("There are now {} special token lay objects", currentSpecialTokenLays.size()); // Can more tokens be laid? Otherwise, next step - if (!canLayAnyTokens(false)) { + //if (!canLayAnyTokens(false)) { + if (currentNormalTokenLays.isEmpty() && currentSpecialTokenLays.isEmpty()) { nextStep(); } @@ -2550,11 +2563,16 @@ protected void setBonusTokenLays() { */ protected boolean canLayAnyTokens (boolean resetTokenLays) { + if (resetTokenLays) setNormalTokenLays(); if (!currentNormalTokenLays.isEmpty()) return true; if (resetTokenLays) setSpecialTokenLays(); if (!currentSpecialTokenLays.isEmpty()) return true; if (!getSpecialProperties(SpecialBonusTokenLay.class).isEmpty()) return true; + for (SpecialBaseTokenLay sbtl : getSpecialProperties(SpecialBaseTokenLay.class)) { + if (operatingCompany.value().getNumberOfFreeBaseTokens() > 0 + || sbtl.isCreate()) return true; + } return false; } @@ -2790,13 +2808,26 @@ protected void executeSetRevenueAndDividend(SetDividend action, String report) { /** * Process any special revenue, adapting the dividend as required. * Default version: dividend = earnings. - * To be overridden if any special revenue must be processed. + * Should not be called if specialRevenue = 0. * @param earnings The total income from train runs. * @param specialRevenue Any income that needs special processing. * @return The resulting dividend (default: equal to the earnings). */ protected int processSpecialRevenue(int earnings, int specialRevenue) { - return earnings; + int dividend = earnings; + PublicCompany company = operatingCompany.value(); + if (specialRevenue > 0) { + dividend -= specialRevenue; + company.setLastDirectIncome(specialRevenue); + ReportBuffer.add(this, LocalText.getText("CompanyDividesEarnings", + company, + Bank.format(this, earnings), + Bank.format(this, dividend), + Bank.format(this, specialRevenue))); + Currency.fromBank(specialRevenue, company); + } + company.setLastDividend(dividend); + return dividend; } /* @@ -2838,7 +2869,7 @@ public void payout(int amount) { } // Move the token - operatingCompany.value().payout(amount); + operatingCompany.value().adjustPriceOnPayout(amount); } protected Map countSharesPerRecipient() { @@ -2871,14 +2902,17 @@ protected MoneyOwner getBeneficiary(PublicCertificate cert) { MoneyOwner beneficiary; // Special cases apply if the holder is the IPO or the Pool + beneficiary = bank; // Default if (operatingCompany.value().paysOutToTreasury(cert)) { beneficiary = operatingCompany.value(); + } else if (cert.getOwner().equals(operatingCompany.value())) { + if (operatingCompany.value().treasurySharesPayOut(cert)) { + beneficiary = operatingCompany.value(); + } } else if (cert.getOwner() instanceof MoneyOwner) { beneficiary = (MoneyOwner) cert.getOwner(); - } else { // TODO: check if this is a correct assumption that otherwise - // the money goes to the bank - beneficiary = bank; } + return beneficiary; } diff --git a/src/main/java/net/sf/rails/game/PrivateCompany.java b/src/main/java/net/sf/rails/game/PrivateCompany.java index f7d5e0565..f8b9f4a0c 100644 --- a/src/main/java/net/sf/rails/game/PrivateCompany.java +++ b/src/main/java/net/sf/rails/game/PrivateCompany.java @@ -174,7 +174,7 @@ public void configureFromXML(Tag tag) throws ConfigurationException { String ifAttribute = spTag.getAttributeAsString("condition"); if (ifAttribute != null) { closeIfAllExercised = "ifExercised".equalsIgnoreCase(ifAttribute) - || ifAttribute.equalsIgnoreCase("ifAllExercised"); + || "ifAllExercised".equalsIgnoreCase(ifAttribute); closeIfAnyExercised = "ifAnyExercised".equalsIgnoreCase(ifAttribute); } String whenAttribute = spTag.getAttributeAsString("when"); diff --git a/src/main/java/net/sf/rails/game/PublicCompany.java b/src/main/java/net/sf/rails/game/PublicCompany.java index 6a92d55a1..20e41fe71 100644 --- a/src/main/java/net/sf/rails/game/PublicCompany.java +++ b/src/main/java/net/sf/rails/game/PublicCompany.java @@ -12,6 +12,7 @@ import net.sf.rails.game.state.Currency; import net.sf.rails.game.state.Observable; import net.sf.rails.game.state.*; +import net.sf.rails.game.state.Observer; import net.sf.rails.util.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -139,7 +140,7 @@ public static BaseCostMethod get(String configName) { */ protected int publicNumber = -1; // For internal use - protected int numberOfBaseTokens = 0; + protected IntegerState numberOfBaseTokens = IntegerState.create(this, "noOfBaseTokens"); /** * In case of distance-dependent token lay cost, @@ -296,9 +297,7 @@ public static BaseCostMethod get(String configName) { protected boolean poolPaysOut = false; - /* not used - protected boolean treasuryPaysOut = false; - */ + protected boolean treasuryPaysOut = true; // Used by 18VA: false protected boolean canHoldOwnShares = false; @@ -560,8 +559,6 @@ public PublicCompany(RailsItem parent, String id, boolean hasStockPrice) { currentPrice = PriceModel.create(this, "currentPrice", true); canSharePriceVary = new BooleanState(this, "canSharePriceVary", true); } - - } /** @@ -597,7 +594,7 @@ public void configureFromXML(Tag tag) throws ConfigurationException { fixedPrice = tag.getAttributeAsInteger("price", 0); - numberOfBaseTokens = tag.getAttributeAsInteger("tokens", 1); + numberOfBaseTokens.set(tag.getAttributeAsInteger("tokens", 1)); certsAreInitiallyAvailable = tag.getAttributeAsBoolean("available", certsAreInitiallyAvailable); @@ -646,8 +643,9 @@ public void configureFromXML(Tag tag) throws ConfigurationException { parentInfoText += SpecialProperty.configure(this, tag); poolPaysOut = poolPaysOut || tag.getChild("PoolPaysOut") != null; - ipoPaysOut = ipoPaysOut || tag.getChild("IPOPaysOut") != null; + treasuryPaysOut = treasuryPaysOut + && tag.getChild("TreasuryDoesNotPayOut") == null; Tag floatTag = tag.getChild("Float"); if (floatTag != null) { @@ -1167,15 +1165,57 @@ public void setReachedDestination(boolean value) { hasReachedDestination.set(value); } - /** Stub to trigger a company to make more shares available, - * in other words: become a higher-number-of-shares company. - * @return false if conversion is not allowed or fails. - * - * Used by overriding in 1826 (perhaps that code could be put here) - */ - public boolean grow() { - return validateGrow(); + /** Convert company from a 5-share to a 10-share company */ + /* The intention is to make this code usable for other games as well. */ + public boolean grow () { + + if (!validateGrow()) return false; + + growStep.add(1); + setShareUnit(shareUnitSizes.get(growStep.value())); + + BankPortfolio reserved = getRoot().getBank().getUnavailable(); + BankPortfolio ipo = getRoot().getBank().getIpo(); + Set last5Shares = reserved.getPortfolioModel().getCertificates(this); + for (PublicCertificate cert : last5Shares) { + if (hasStarted()) { + cert.moveTo(this); + } else { + // Still in IPO, put the reserved shares there too + cert.moveTo(ipo); + } + } + + ReportBuffer.add(this, LocalText.getText("CompanyHasGrown", + this, getActiveShareCount())); + + currentTrainLimits.setTo(trainLimits.get(growStep.value())); + ReportBuffer.add(this, + LocalText.getText("PhaseDependentTrainLimitsSetTo", + this, currentTrainLimits.view(), getCurrentTrainLimit())); + + + // For some reason the shareUnit change does not update + // the percentages shown in the GameStatus window. + // E.g. 60% should become 30%, etc. + // There must be a nicer way to accomplish that, + // but for now the below code works. + Set modelsToUpdate = new HashSet<>(); + PortfolioOwner owner; + Model model; + for (PublicCertificate cert : getCertificates()) { + owner = (PortfolioOwner) cert.getOwner(); + model = owner.getPortfolioModel().getShareModel(this); + if (!modelsToUpdate.contains(model)) modelsToUpdate.add(model); + } + for (Model m : modelsToUpdate) { + for (Observer obs : m.getObservers()) { + obs.update(m.toText()); + } + } + return true; } + /** Stub, to be extended or overridden by specific games if needed. */ protected boolean validateGrow() { return growStep.value() < shareUnitSizes.size() - 1; @@ -1637,11 +1677,9 @@ public StringState getLastRevenueAllocationModel() { * Determine if the price token must be moved after a dividend payout, * and with how many jumps. * - * TODO: Will be renamed to adjustPriceOnPayout - * * @param amount The total revenue that has been paid out */ - public void payout(int amount) { + public void adjustPriceOnPayout(int amount) { if (!hasStockPrice || amount == 0) return; @@ -1671,6 +1709,11 @@ public void payout(int amount) { */ } + /** Do IPO or Pool pay out to the company? + * Default = false + * @param cert The certificate + * @return whether it pays out to the company if opwned by the Bank + */ public boolean paysOutToTreasury(PublicCertificate cert) { Owner owner = cert.getOwner(); @@ -1678,6 +1721,16 @@ public boolean paysOutToTreasury(PublicCertificate cert) { || owner == getRoot().getBank().getPool() && poolPaysOut; } + /** Do treasury shares pay out to the company? + * Default = true + * @param cert The certificate + * @return whether it pays out to its owning company + */ + public boolean treasurySharesPayOut (PublicCertificate cert) { + Owner owner = cert.getOwner(); + return owner == cert.getCompany() && treasuryPaysOut; + } + /** * Determine if the price token must be moved after a withheld dividend. * @@ -2253,7 +2306,7 @@ public boolean hasLaidHomeBaseTokens() { */ protected void initBaseTokens() { SortedSet newTokens = new TreeSet<>(); - for (int i = 0; i < numberOfBaseTokens; i++) { + for (int i = 0; i < numberOfBaseTokens.value(); i++) { BaseToken token = BaseToken.create(this); newTokens.add(token); } diff --git a/src/main/java/net/sf/rails/game/Revenue.java b/src/main/java/net/sf/rails/game/Revenue.java new file mode 100644 index 000000000..78864f607 --- /dev/null +++ b/src/main/java/net/sf/rails/game/Revenue.java @@ -0,0 +1,76 @@ +package net.sf.rails.game; + +/** Class Revenue is a wrapper around different revenue values. + * Specifically, it is intended for the 'direct' revenue amounts + * of 1837 and 18VA that go directly into the company treasury + * rather than being paid out as dividends. + * + * Currently, this class is not yet being applied in the whole + * algorithms tombola, but only by the other new class Stops + * and the 18VA TrainRunModifier. + * + * Created 04/2023 by Erik Vos + */ +public class Revenue { + + private int normalRevenue = 0; + private int specialRevenue = 0; + + public Revenue(int normalRevenue, int specialRevenue) { + this.normalRevenue = normalRevenue; + this.specialRevenue = specialRevenue; + } + + public Revenue (int normalRevenue) { + this.normalRevenue = normalRevenue; + } + + public int getNormalRevenue() { + return normalRevenue; + } + + public void setNormalRevenue(int normalRevenue) { + this.normalRevenue = normalRevenue; + } + + public int getSpecialRevenue() { + return specialRevenue; + } + + public void setSpecialRevenue(int specialRevenue) { + this.specialRevenue = specialRevenue; + } + + public Revenue addNormalRevenue (int normalRevenue) { + this.normalRevenue += normalRevenue; + return this; + } + + public Revenue addSpecialRevenue (int specialRevenue) { + this.specialRevenue += specialRevenue; + return this; + } + + public Revenue addRevenue (int normalRevenue, int specialRevenue) { + this.normalRevenue += normalRevenue; + this.specialRevenue += specialRevenue; + return this; + } + + public Revenue addRevenue (Revenue revenue) { + this.normalRevenue += revenue.normalRevenue; + this.specialRevenue += revenue.specialRevenue; + return this; + } + + public Revenue multiplyRevenue (int factor) { + normalRevenue *= factor; + specialRevenue *= factor; + return this; + } + + public String toString() { + return "{" + normalRevenue + "," + specialRevenue + "}"; + } + +} diff --git a/src/main/java/net/sf/rails/game/Routes.java b/src/main/java/net/sf/rails/game/Routes.java index fcfbaf85e..ec6812087 100644 --- a/src/main/java/net/sf/rails/game/Routes.java +++ b/src/main/java/net/sf/rails/game/Routes.java @@ -1,7 +1,6 @@ package net.sf.rails.game; import net.sf.rails.algorithms.*; -import org.jgrapht.graph.SimpleGraph; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/net/sf/rails/game/Station.java b/src/main/java/net/sf/rails/game/Station.java index 9acedd831..1b16a9afb 100644 --- a/src/main/java/net/sf/rails/game/Station.java +++ b/src/main/java/net/sf/rails/game/Station.java @@ -4,6 +4,7 @@ import net.sf.rails.common.parser.ConfigurationException; import net.sf.rails.common.parser.Tag; +import net.sf.rails.game.state.IntegerState; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,7 +34,7 @@ public class Station extends TrackPoint implements Comparable { private final Stop.Type type; private final int number; private final int value; - private final int baseSlots; + private IntegerState baseSlots; private final Tile tile; private final int position; private final String stopName; @@ -52,7 +53,7 @@ private Station(Tile tile, int number, String id, Stop.Type type, int value, this.id = id; this.type = type; this.value = value; - this.baseSlots = slots; + this.baseSlots = IntegerState.create (tile, "BTSlots_"+tile.getId()+"_"+number, slots); this.position = position; this.stopName = cityName; @@ -106,6 +107,10 @@ public static Station create(Tile tile, Tag stationDefTag, Tag stationSetTag) return station; } + // Add an off-station base slot + public void addVirtualBaseSlot() { + baseSlots.add(1); + } public String getName() { return "Station " + id + " on " + tile.getClass().getSimpleName() + " " @@ -140,7 +145,7 @@ public int getNumber() { * @return Returns the baseSlots. */ public int getBaseSlots() { - return baseSlots; + return baseSlots.value(); } /** diff --git a/src/main/java/net/sf/rails/game/Stop.java b/src/main/java/net/sf/rails/game/Stop.java index 859665ce5..386e6edb8 100644 --- a/src/main/java/net/sf/rails/game/Stop.java +++ b/src/main/java/net/sf/rails/game/Stop.java @@ -264,6 +264,8 @@ public String getMutexId() { return mutexId; } + public int getValue() { return getRelatedStation().getValue(); } + public boolean isRunToAllowedFor(PublicCompany company, boolean running) { diff --git a/src/main/java/net/sf/rails/game/Stops.java b/src/main/java/net/sf/rails/game/Stops.java new file mode 100644 index 000000000..bc455565f --- /dev/null +++ b/src/main/java/net/sf/rails/game/Stops.java @@ -0,0 +1,126 @@ +package net.sf.rails.game; + +import java.util.HashMap; +import java.util.Map; + +/** + * Stops is a class intended to provide a central place + * for calculation of revenues per stop, possibly dependent + * on phase, tokening and train type. + * + * It was created out of frustration with the existing train run + * calculation code, that made handling train run revenues in 18VA + * a matter of building a very complex dynamic modifier. + * + * Another factor was the mine revenue in 1837 and 18VA, which + * wholly or partly went directly to the company treasury, + * completely separate from normal revenue. This has led to + * add another class called Revenue, which can transport both + * normal and special revenues, and is extendable. + * + * This class is a default version, that returns the fixed + * stop values that are sufficient in most games, an exception + * being the phase-dependent offmap revenues. + * + * Game-specific subclasses can be created to handle the kind + * of special cases that are so abundant in 18VA. + * + * The main usage of the methods of this class is expected to be + * by NetworkVertex and dynamic modifier objects. + * + * The results can be obtained in two ways: + * - as TOTAL REVENUE, which is the total revenue of a stop; + * - as EXTRA REVENUE, which is the correction to the standard + * revenue that is configured for tiles and offmap hexes. + * That correction (default zero) must be returned by the method + * predictionValue() of any dynamic modifier. + * + * Created 04/2023 by Erik Vos + */ +public class Stops { + + protected GameManager gameManager; + protected PhaseManager phaseManager; + protected MapManager mapManager; + + protected static Map instances = new HashMap<>(); + + protected Stops (RailsRoot root) { + gameManager = root.getGameManager(); + phaseManager = root.getPhaseManager(); + mapManager = root.getMapManager(); + } + + protected static Stops getInstance (RailsRoot root) { + if (!instances.containsKey(root)) { + instances.put(root, new Stops(root)); + } + return instances.get(root); + } + + public static Revenue getValue(Stop stop) { + return getInstance (stop.getRoot()).getRevenue(stop, null, null); + } + + public static Revenue getValueForTrain(Stop stop, Train train) { + return getInstance (stop.getRoot()).getRevenue(stop, train, null); + } + + public static Revenue getValueForTrainAndCompany (Stop stop, Train train, PublicCompany company) { + return getInstance (stop.getRoot()).getRevenue(stop, train, company); + } + + public static Revenue getExtraValue(Stop stop) { + return getInstance (stop.getRoot()).getExtraRevenue(stop, null, null); + } + + public static Revenue getExtraValueForTrain(Stop stop, Train train) { + return getInstance (stop.getRoot()).getExtraRevenue(stop, train, null); + } + + public static Revenue getExtraValueForTrainAndCompany (Stop stop, Train train, PublicCompany company) { + return getInstance (stop.getRoot()).getExtraRevenue(stop, train, company); + } + + public static int getTotalRevenue (Stop stop, Train train, PublicCompany company) { + Revenue revenue = getValueForTrainAndCompany (stop, train, company); + return revenue.getNormalRevenue() + revenue.getSpecialRevenue(); + } + + public static int getTotalExtraRevenue (Stop stop, Train train, PublicCompany company) { + Revenue revenue = getExtraValueForTrainAndCompany (stop, train, company); + return revenue.getNormalRevenue() + revenue.getSpecialRevenue(); + } + + + /* This default method can be overridden for any game + * in a game-specific subclass + * + * @param stop The stop for which a revenue value is requested + * @param train A specific train that may affect the revenue, + * or null if the train does not matter + * @param company A specific company that may affect the revenue, + * or null if the company does not matter + * @return A new Revenue object + */ + protected Revenue getRevenue (Stop stop, Train train, PublicCompany company) { + //if (stop.getType() == Stop.Type.OFFMAP) { + return new Revenue ( + stop.getValueForPhase(phaseManager.getCurrentPhase()), + 0); + //} else { + // return new Revenue (stop.getValue(), + // 0); + //} + + } + + /** Same as getRevenue(), but intended to get + * additional revenue vales, as are needed for + * the predictionValue() methods in dynamic modifiers. + */ + protected Revenue getExtraRevenue (Stop stop, Train train, PublicCompany company) { + return new Revenue (0, 0); + } + +} diff --git a/src/main/java/net/sf/rails/game/model/BaseTokensModel.java b/src/main/java/net/sf/rails/game/model/BaseTokensModel.java index 66ed6d79f..2d90a1c9f 100644 --- a/src/main/java/net/sf/rails/game/model/BaseTokensModel.java +++ b/src/main/java/net/sf/rails/game/model/BaseTokensModel.java @@ -46,7 +46,7 @@ public void initBaseTokens(SortedSet tokens) { /** * Add more tokens than the initially configured number. - * This is required for 1826. + * This is required for 1826 and 18VA * @param token A newly created token * @param laid True if the new token will immediately be laid, * i.e. it will never be a freely layable token. diff --git a/src/main/java/net/sf/rails/game/model/PortfolioModel.java b/src/main/java/net/sf/rails/game/model/PortfolioModel.java index f10c352ab..f2988acdd 100644 --- a/src/main/java/net/sf/rails/game/model/PortfolioModel.java +++ b/src/main/java/net/sf/rails/game/model/PortfolioModel.java @@ -467,9 +467,8 @@ public List getSpecialProperties(Class clazz, if ((clazz == null || clazz.isAssignableFrom(sp.getClass())) && sp.isExecutionable() && (!sp.isExercised() || includeExercised) - && (getParent() instanceof Company - && sp.isUsableIfOwnedByCompany() || getParent() instanceof Player - && sp.isUsableIfOwnedByPlayer())) { + && (getParent() instanceof Company && sp.isUsableIfOwnedByCompany() + || getParent() instanceof Player && sp.isUsableIfOwnedByPlayer())) { log.debug("Portfolio {} has SP {}", getParent().getId(), sp); result.add((T) sp); } @@ -481,9 +480,8 @@ public List getSpecialProperties(Class clazz, if ((clazz == null || clazz.isAssignableFrom(sp.getClass())) && sp.isExecutionable() && (!sp.isExercised() || includeExercised) - && (getParent() instanceof Company - && sp.isUsableIfOwnedByCompany() || getParent() instanceof Player - && sp.isUsableIfOwnedByPlayer())) { + && (getParent() instanceof Company && sp.isUsableIfOwnedByCompany() + || getParent() instanceof Player && sp.isUsableIfOwnedByPlayer())) { log.debug("Portfolio {} has persistent SP {}", getParent().getId(), sp); result.add((T) sp); } diff --git a/src/main/java/net/sf/rails/game/special/SpecialBaseTokenLay.java b/src/main/java/net/sf/rails/game/special/SpecialBaseTokenLay.java index 05ab1009a..7bbb108f4 100644 --- a/src/main/java/net/sf/rails/game/special/SpecialBaseTokenLay.java +++ b/src/main/java/net/sf/rails/game/special/SpecialBaseTokenLay.java @@ -22,6 +22,9 @@ public class SpecialBaseTokenLay extends SpecialProperty { private boolean requiresTile = false; private boolean requiresNoTile = false; private Forced forced = Forced.NO; + // Two specials for 18VA, where both will be set to true + private boolean create = false; + private boolean offCity = false; public enum Forced { NO, @@ -57,6 +60,9 @@ public void configureFromXML(Tag tag) throws ConfigurationException { requiresTile = tokenLayTag.getAttributeAsBoolean("requiresTile", requiresTile); requiresNoTile = tokenLayTag.getAttributeAsBoolean("requiresNoTile", requiresNoTile); forcedText = tokenLayTag.getAttributeAsString("forced", null); + // For 18VA + create = tokenLayTag.getAttributeAsBoolean("create", create); + offCity = tokenLayTag.getAttributeAsBoolean("offCity", offCity); description = LocalText.getText("LayBaseTokenInfo", connected ? LocalText.getText("aconnected") @@ -111,6 +117,22 @@ public String getLocationCodeString() { return locationCodes; } + public boolean isCreate() { + return create; + } + + public void setCreate(boolean create) { + this.create = create; + } + + public boolean isOffCity() { + return offCity; + } + + public void setOffCity(boolean offCity) { + this.offCity = offCity; + } + // That's rather overdoing revealing descriptions, here below. @Override public String toText() { diff --git a/src/main/java/net/sf/rails/game/special/SpecialRight.java b/src/main/java/net/sf/rails/game/special/SpecialRight.java index 31f74e9e9..cca09f7e2 100644 --- a/src/main/java/net/sf/rails/game/special/SpecialRight.java +++ b/src/main/java/net/sf/rails/game/special/SpecialRight.java @@ -96,10 +96,7 @@ public int getCost() { } public boolean isExecutionable() { - // FIXME: Check if this works correctly - // IT is better to rewrite this check - // see ExchangeForShare - return ((PrivateCompany)originalCompany).getOwner() instanceof Player; + return true; } /** diff --git a/src/main/java/net/sf/rails/game/special/SpecialTrainBuy.java b/src/main/java/net/sf/rails/game/special/SpecialTrainBuy.java index d49e13e1b..74bbe5573 100644 --- a/src/main/java/net/sf/rails/game/special/SpecialTrainBuy.java +++ b/src/main/java/net/sf/rails/game/special/SpecialTrainBuy.java @@ -52,6 +52,7 @@ public void configureFromXML(Tag tag) throws ConfigurationException { relativeDeduction = true; deductionAmountString = deductionString.replaceAll("%", ""); } else { + absoluteDeduction = true; deductionAmountString = deductionString; } try { diff --git a/src/main/java/net/sf/rails/game/specific/_1825/PublicCompany_1825.java b/src/main/java/net/sf/rails/game/specific/_1825/PublicCompany_1825.java index 5c6001a80..5bb11d597 100644 --- a/src/main/java/net/sf/rails/game/specific/_1825/PublicCompany_1825.java +++ b/src/main/java/net/sf/rails/game/specific/_1825/PublicCompany_1825.java @@ -21,7 +21,7 @@ public void setFormationOrderIndex(int formationOrderIndex) { } @Override - public void payout(int amount) { + public void adjustPriceOnPayout(int amount) { if (amount == 0) return; //Get current price int curSharePrice = currentPrice.getPrice().getPrice(); diff --git a/src/main/java/net/sf/rails/game/specific/_1826/OperatingRound_1826.java b/src/main/java/net/sf/rails/game/specific/_1826/OperatingRound_1826.java index 589a87c82..24ad47e51 100644 --- a/src/main/java/net/sf/rails/game/specific/_1826/OperatingRound_1826.java +++ b/src/main/java/net/sf/rails/game/specific/_1826/OperatingRound_1826.java @@ -180,7 +180,7 @@ protected void setGameSpecificPossibleActions() { } } - if (getStep() == GameDef.OrStep.REPAY_LOANS) { + if (getStep() == GameDef.OrStep.REPAY_LOANS) { // The possibility has already been checked in gameSpecificNextStep() if (!repayableLoans.isEmpty()) { diff --git a/src/main/java/net/sf/rails/game/specific/_1826/PublicCompany_1826.java b/src/main/java/net/sf/rails/game/specific/_1826/PublicCompany_1826.java index 4a7cf589e..e17af92f2 100644 --- a/src/main/java/net/sf/rails/game/specific/_1826/PublicCompany_1826.java +++ b/src/main/java/net/sf/rails/game/specific/_1826/PublicCompany_1826.java @@ -114,7 +114,7 @@ public void setFloated() { for (int i = 0; i < extraTokens; i++) { baseTokens.addBaseToken(BaseToken.create(this), false); } - numberOfBaseTokens += extraTokens; + numberOfBaseTokens.add(extraTokens); super.setFloated(); @@ -149,49 +149,7 @@ public boolean grow (boolean checkDestination) { if (!validateGrow(checkDestination)) return false; - growStep.add(1); - setShareUnit(shareUnitSizes.get(growStep.value())); - - BankPortfolio reserved = getRoot().getBank().getUnavailable(); - BankPortfolio ipo = getRoot().getBank().getIpo(); - Set last5Shares = reserved.getPortfolioModel().getCertificates(this); - for (PublicCertificate cert : last5Shares) { - if (hasStarted()) { - cert.moveTo(this); - } else { - // Still in IPO, put the reserved shares there too - cert.moveTo(ipo); - } - } - - ReportBuffer.add(this, LocalText.getText("CompanyHasGrown", - this, getActiveShareCount())); - - currentTrainLimits.setTo(trainLimits.get(growStep.value())); - ReportBuffer.add(this, - LocalText.getText("PhaseDependentTrainLimitsSetTo", - this, currentTrainLimits.view(), getCurrentTrainLimit())); - - - // For some reason the shareUnit change does not update - // the percentages shown in the GameStatus window. - // E.g. 60% should become 30%, etc. - // There must be a nicer way to accomplish that, - // but for now the below code works. - Set modelsToUpdate = new HashSet<>(); - PortfolioOwner owner; - Model model; - for (PublicCertificate cert : getCertificates()) { - owner = (PortfolioOwner) cert.getOwner(); - model = owner.getPortfolioModel().getShareModel(this); - if (!modelsToUpdate.contains(model)) modelsToUpdate.add(model); - } - for (Model m : modelsToUpdate) { - for (Observer obs : m.getObservers()) { - obs.update(m.toText()); - } - } - return true; + return super.grow(); } protected boolean validateGrow(boolean checkDestination) { diff --git a/src/main/java/net/sf/rails/game/specific/_1837/OperatingRound_1837.java b/src/main/java/net/sf/rails/game/specific/_1837/OperatingRound_1837.java index 2566f36fb..470677207 100644 --- a/src/main/java/net/sf/rails/game/specific/_1837/OperatingRound_1837.java +++ b/src/main/java/net/sf/rails/game/specific/_1837/OperatingRound_1837.java @@ -326,6 +326,7 @@ protected int calculateShareholderPayout (double payoutPerShare, int numberOfSha /* (non-Javadoc) * @see net.sf.rails.game.OperatingRound#gameSpecificTileLayAllowed(net.sf.rails.game.PublicCompany, net.sf.rails.game.MapHex, int) */ + /* @Override protected int processSpecialRevenue(int earnings, int specialRevenue) { int dividend = earnings; @@ -342,7 +343,7 @@ protected int processSpecialRevenue(int earnings, int specialRevenue) { } company.setLastDividend(dividend); return dividend; - } + }*/ @Override protected boolean gameSpecificTileLayAllowed(PublicCompany company, diff --git a/src/main/java/net/sf/rails/game/specific/_1880/OperatingRound_1880.java b/src/main/java/net/sf/rails/game/specific/_1880/OperatingRound_1880.java index fd1c8d75f..d405c3161 100644 --- a/src/main/java/net/sf/rails/game/specific/_1880/OperatingRound_1880.java +++ b/src/main/java/net/sf/rails/game/specific/_1880/OperatingRound_1880.java @@ -585,7 +585,7 @@ public void payout(int amount) { } // Move the token - operatingCompany.value().payout(amount); + operatingCompany.value().adjustPriceOnPayout(amount); } diff --git a/src/main/java/net/sf/rails/game/specific/_1880/PublicCompany_1880.java b/src/main/java/net/sf/rails/game/specific/_1880/PublicCompany_1880.java index 998dade75..a8b46cf87 100644 --- a/src/main/java/net/sf/rails/game/specific/_1880/PublicCompany_1880.java +++ b/src/main/java/net/sf/rails/game/specific/_1880/PublicCompany_1880.java @@ -130,7 +130,7 @@ public void withhold(int amount) { } @Override - public void payout(int amount) { + public void adjustPriceOnPayout(int amount) { if (canStockPriceMove.value() == true) { getRoot().getStockMarket().payOut(this); } diff --git a/src/main/java/net/sf/rails/game/specific/_18EU/AlpineTokenRevenueModifier.java b/src/main/java/net/sf/rails/game/specific/_18EU/AlpineTokenRevenueModifier.java index d72269ef9..b491959e6 100644 --- a/src/main/java/net/sf/rails/game/specific/_18EU/AlpineTokenRevenueModifier.java +++ b/src/main/java/net/sf/rails/game/specific/_18EU/AlpineTokenRevenueModifier.java @@ -68,9 +68,6 @@ public int evaluationValue(List runs, boolean optimalRuns) { //log.info("+++++ Checking run of train {} (optimal={})", run.getTrain(), optimalRuns); for (NetworkVertex vertex : run.getRunVertices()) { hex = vertex.getHex(); - if (hex == null) { - log.info ("????? Hex = null"); - } if (alpineTokenHexes.contains(hex)) { runHasAlpineToken = true; //log.info ("+++++ {} has an Alpine token on hex {}, tile={}", company, hex, hex.getCurrentTile()); diff --git a/src/main/java/net/sf/rails/game/specific/_18VA/GameDef_18VA.java b/src/main/java/net/sf/rails/game/specific/_18VA/GameDef_18VA.java index 4368c55d4..6314f1d93 100644 --- a/src/main/java/net/sf/rails/game/specific/_18VA/GameDef_18VA.java +++ b/src/main/java/net/sf/rails/game/specific/_18VA/GameDef_18VA.java @@ -1,5 +1,7 @@ package net.sf.rails.game.specific._18VA; +import java.util.Map; + /** * Externalised constants for 18VA */ @@ -7,5 +9,20 @@ public class GameDef_18VA { public final static String GOODS = "GOODS"; + public final static String BO = "B&O"; + + // Phases + public final static String PHASE_5 = "5"; + + // Port cities + // Note: this only works because all involved hexes have only one stop + public final static Map citiesWithPorts = Map.of ( + "C8","D9", + "E8","F9", + "M8","N9", + "O8","P9" + ); + + } diff --git a/src/main/java/net/sf/rails/game/specific/_18VA/GameManager_18VA.java b/src/main/java/net/sf/rails/game/specific/_18VA/GameManager_18VA.java index c514bd0d2..66edfa91e 100644 --- a/src/main/java/net/sf/rails/game/specific/_18VA/GameManager_18VA.java +++ b/src/main/java/net/sf/rails/game/specific/_18VA/GameManager_18VA.java @@ -3,6 +3,7 @@ import net.sf.rails.common.GuiDef; import net.sf.rails.game.GameManager; import net.sf.rails.game.RailsRoot; +import net.sf.rails.game.Train; public class GameManager_18VA extends GameManager { @@ -18,4 +19,13 @@ public void setGuiParameters() { } + /** Calculate value of a CMD */ + public int getValuePerTrain (Train train) { + if (train.getType().getCategory().equalsIgnoreCase("goods")) { + return 20 * train.getType().getMajorStops(); + } else { + return 0; + } + } + } diff --git a/src/main/java/net/sf/rails/game/specific/_18VA/OperatingRound_18VA.java b/src/main/java/net/sf/rails/game/specific/_18VA/OperatingRound_18VA.java new file mode 100644 index 000000000..a38320504 --- /dev/null +++ b/src/main/java/net/sf/rails/game/specific/_18VA/OperatingRound_18VA.java @@ -0,0 +1,102 @@ +package net.sf.rails.game.specific._18VA; + +import net.sf.rails.game.*; +import net.sf.rails.game.special.SpecialBaseTokenLay; +import net.sf.rails.game.special.SpecialRight; +import net.sf.rails.game.specific._1826.PublicCompany_1826; +import rails.game.action.GrowCompany; +import rails.game.action.LayBaseToken; +import rails.game.action.UseSpecialProperty; + +import java.util.ArrayList; +import java.util.List; + +public class OperatingRound_18VA extends OperatingRound { + + /** + * Constructed via Configure + */ + public OperatingRound_18VA(GameManager parent, String id) { + super(parent, id); + + } + + @Override + protected void setGameSpecificPossibleActions() { + + PublicCompany_18VA company = (PublicCompany_18VA) getOperatingCompany(); + + // From phase 3, 5-share companies may grow to 10-share companies + if (company.getShareUnit() == 20 + && getRoot().getPhaseManager().hasReachedPhase("3")) { + possibleActions.add(new GrowCompany(getRoot(), 10)); + } + + // Check if the operating company can use the extra train right + List srs = company.getPortfolioModel() + .getSpecialProperties(SpecialRight.class, false); + if (srs != null && !srs.isEmpty()) { + possibleActions.add(new UseSpecialProperty(srs.get(0))); + } + } + + @Override + protected void setSpecialTokenLays() { + + /* Special-property base token lays */ + currentSpecialTokenLays.clear(); + + PublicCompany company = operatingCompany.value(); + if (!company.canUseSpecialProperties()) return; + List remainingLocations = new ArrayList<>(); + + for (SpecialBaseTokenLay stl : getSpecialProperties(SpecialBaseTokenLay.class)) { + // in 18VA, below settings must be true, but check anyway + if (stl.isExtra() && stl.isCreate() && stl.isOffCity()) { + + // This STL is location specific. Check if there + // isn't already a token of this company + List locations = stl.getLocations(); + if (locations != null && !locations.isEmpty()) { + for (MapHex location : locations) { + if (location.hasTokenOfCompany(company)) { + continue; + } + remainingLocations.add(location); + } + } + LayBaseToken action = new LayBaseToken(getRoot(), stl); + action.setType(LayBaseToken.NON_CITY); + currentSpecialTokenLays.add(action); + } + } + } + + public boolean layBaseToken(LayBaseToken action) { + + if (action.getType() == LayBaseToken.NON_CITY) { + // Create an extra (virtual) token spot (in 18VA only 1 station per hex) + action.getChosenHex().getStation(1).addVirtualBaseSlot(); + // Create an extra token + //getOperatingCompany().getBaseTokensModel().addBaseToken(BaseToken.create(getOperatingCompany()), true); + ((PublicCompany_18VA)getOperatingCompany()).addBaseToken(); + } + + return super.layBaseToken(action); + } + + protected void newPhaseChecks() { + Phase phase = Phase.getCurrent(this); + String phaseId = phase.getId(); + + if (phaseId.equals("5")) { + // Convert all remaining 5-share companies to 10-share + for (PublicCompany company : companyManager.getAllPublicCompanies()) { + if (!company.isClosed() && company.getShareUnit() == 20) { + company.grow(); + } + } + } + } + +} diff --git a/src/main/java/net/sf/rails/game/specific/_18VA/PublicCompany_18VA.java b/src/main/java/net/sf/rails/game/specific/_18VA/PublicCompany_18VA.java new file mode 100644 index 000000000..4450a302d --- /dev/null +++ b/src/main/java/net/sf/rails/game/specific/_18VA/PublicCompany_18VA.java @@ -0,0 +1,186 @@ +package net.sf.rails.game.specific._18VA; + +import net.sf.rails.common.LocalText; +import net.sf.rails.common.ReportBuffer; +import net.sf.rails.common.parser.ConfigurationException; +import net.sf.rails.common.parser.Tag; +import net.sf.rails.game.BaseToken; +import net.sf.rails.game.PublicCompany; +import net.sf.rails.game.RailsItem; +import net.sf.rails.game.RailsRoot; +import net.sf.rails.game.financial.Bank; +import net.sf.rails.game.financial.BankPortfolio; +import net.sf.rails.game.financial.PublicCertificate; +import net.sf.rails.game.model.PortfolioOwner; +import net.sf.rails.game.special.ExtraTrainRight; +import net.sf.rails.game.specific._1826.GameDef_1826; +import net.sf.rails.game.state.Model; +import net.sf.rails.game.state.Observer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashSet; +import java.util.Set; + +public class PublicCompany_18VA extends PublicCompany { + + private static final Logger log = LoggerFactory.getLogger(PublicCompany_18VA.class); + + public PublicCompany_18VA(RailsItem parent, String id) { + super (parent, id, true); + } + + public PublicCompany_18VA(RailsItem parent, String id, boolean hasStockPrice) { + super(parent, id, hasStockPrice); + } + + // Probably redundant + public void configureFromXML(Tag tag) throws ConfigurationException { + + super.configureFromXML(tag); + + } + + + // Really needed? + public void finishConfiguration(RailsRoot root) + throws ConfigurationException { + + super.finishConfiguration(root); + + // 5-share companies have an initial share unit of 20% + if (isPotentialFiveShareCompany()) { + setShareUnit(20); + } + } + + private boolean isPotentialFiveShareCompany() { + return getType().getId().equals("Public") && !getId().equals(GameDef_18VA.BO); + } + + /** Check if a company must get more tokens that the configured minimal number.*/ + @Override + public void setFloated() { + + int extraTokens = 0; + boolean reachedPhase5 = getType().getId().equals("Public") + && getRoot().getPhaseManager().hasReachedPhase(GameDef_18VA.PHASE_5); + + if (reachedPhase5) { + extraTokens += 2; + } + + for (int i = 0; i < extraTokens; i++) { + baseTokens.addBaseToken(BaseToken.create(this), false); + } + numberOfBaseTokens.add (extraTokens); + + super.setFloated(); + Set certs = getRoot().getBank().getIpo() + .getPortfolioModel().getCertificates(this); + for (PublicCertificate cert : certs) { + cert.moveTo(this); + }; + + + // TODO + if (reachedPhase5) { + + + } + } + + public void addBaseToken () { + baseTokens.addBaseToken(BaseToken.create(this), false); + numberOfBaseTokens.add(1); + } + + // Probably not needed + protected void setCapitalizationShares() { + if (getId().equals(GameDef_1826.SNCF)) { + capitalisationShares = getPortfolioModel().getShares(this); + } else if (getId().equals(GameDef_1826.ETAT)) { + capitalisationShares = 0; + } + log.debug("{} CapFactor set to {}", this, capitalisationShares); + } + + @Override // Probably not needed + public int getCapitalisation() { + if (getType().getId().equalsIgnoreCase("Public") + && getRoot().getPhaseManager().hasReachedPhase(GameDef_18VA.PHASE_5)) { + return CAPITALISE_FULL; + } else { + return capitalisation; + } + } + + /** Convert company from a 5-share to a 10-share company */ + /* The intention is to make this code usable for other games as well. */ + public boolean grow (boolean checkDestination) { + + if (!validateGrow(checkDestination)) return false; + + growStep.add(1); + setShareUnit(shareUnitSizes.get(growStep.value())); + + BankPortfolio reserved = getRoot().getBank().getUnavailable(); + BankPortfolio ipo = getRoot().getBank().getIpo(); + Set last5Shares = reserved.getPortfolioModel().getCertificates(this); + for (PublicCertificate cert : last5Shares) { + if (hasStarted()) { + cert.moveTo(this); + } else { + // Still in IPO, put the reserved shares there too + cert.moveTo(ipo); + } + } + + ReportBuffer.add(this, LocalText.getText("CompanyHasGrown", + this, getActiveShareCount())); + + currentTrainLimits.setTo(trainLimits.get(growStep.value())); + ReportBuffer.add(this, + LocalText.getText("PhaseDependentTrainLimitsSetTo", + this, currentTrainLimits.view(), getCurrentTrainLimit())); + + + // For some reason the shareUnit change does not update + // the percentages shown in the GameStatus window. + // E.g. 60% should become 30%, etc. + // There must be a nicer way to accomplish that, + // but for now the below code works. + Set modelsToUpdate = new HashSet<>(); + PortfolioOwner owner; + Model model; + for (PublicCertificate cert : getCertificates()) { + owner = (PortfolioOwner) cert.getOwner(); + model = owner.getPortfolioModel().getShareModel(this); + if (!modelsToUpdate.contains(model)) modelsToUpdate.add(model); + } + for (Model m : modelsToUpdate) { + for (Observer obs : m.getObservers()) { + obs.update(m.toText()); + } + } + return true; + } + + protected boolean validateGrow(boolean checkDestination) { + return super.validateGrow() + && (!checkDestination || hasReachedDestination()); + } + + @Override + protected int getTrainLimit(int phaseIndex) { + + int limit = super.getTrainLimit(phaseIndex); + if (rightsModel == null || rightsModel.isEmpty()) return limit; + + ExtraTrainRight etr = rightsModel.getRightType(ExtraTrainRight.class); + if (etr != null) limit += etr.getExtraTrains(); + + return limit; + } + +} \ No newline at end of file diff --git a/src/main/java/net/sf/rails/game/specific/_18VA/RevenueManager_18VA.java b/src/main/java/net/sf/rails/game/specific/_18VA/RevenueManager_18VA.java new file mode 100644 index 000000000..8312ff830 --- /dev/null +++ b/src/main/java/net/sf/rails/game/specific/_18VA/RevenueManager_18VA.java @@ -0,0 +1,119 @@ +package net.sf.rails.game.specific._18VA; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import net.sf.rails.algorithms.RevenueAdapter; +import net.sf.rails.algorithms.RevenueManager; +import net.sf.rails.common.LocalText; +import net.sf.rails.common.parser.ConfigurationException; +import net.sf.rails.game.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** This is a subclass of RevenueManager, only meant to adapt + * ultimate revenue calculation to games with non-standard rules. + * 18VA is an extreme case of such special rules. + * + * I believe that this way of calculating revenue obviates + * the need for providing additional 'prediction values' + * in dynamic modifiers. + * + * Created by Erik Vos 04/2023 + * */ +public class RevenueManager_18VA extends RevenueManager { + + private BiMap portCities; + private MapManager mapManager; + + private static final Logger log = LoggerFactory.getLogger(RevenueManager_18VA.class); + + public RevenueManager_18VA (RailsRoot parent, String id) { + + super(parent, id); + } + + public void finishConfiguration(RailsRoot parent) + throws ConfigurationException { + portCities = HashBiMap.create(); + mapManager = parent.getMapManager(); + Stop port, city; + for (String cityName : GameDef_18VA.citiesWithPorts.keySet()) { + city = mapManager.getHex(cityName).getStops().asList().get(0); + port = mapManager.getHex(GameDef_18VA.citiesWithPorts.get(cityName)).getStops().asList().get(0); + portCities.put (port, city); + } + log.debug("Related cities of ports {}", portCities); + } + + @Override + protected Revenue getBaseRevenue(Stop stop, Train train, PublicCompany company) { + + Revenue baseRev = new Revenue (0,0); + boolean isGoods = train.getCategory().equalsIgnoreCase("goods"); + boolean isTokened = stop.hasTokenOf(company); + Phase phase = phaseManager.getCurrentPhase(); + + switch (stop.getType()) { + case TOWN: // 'Mine' in 18VA parlance + if (isGoods) { + baseRev.addNormalRevenue(stop.getValue()); + } + break; + case CITY: + baseRev.addNormalRevenue(stop.getValueForPhase(phase)) + .multiplyRevenue(train.getCityScoreFactor()); + break; + case OFFMAP: + baseRev.addNormalRevenue(stop.getValueForPhase(phase)) + .multiplyRevenue(train.getCityScoreFactor()); // 4D scores double + if (isTokened) { + baseRev.multiplyRevenue(2); + } + break; + case MINE: // 'CMD' in 18VA parlance + if (isGoods) { // CMD must have configured value 20 - does not work?? + // FIXME: Why does stop.getValue() return 0 rather than the configured 20? + baseRev.addNormalRevenue (20 * train.getMajorStops()); + if (isTokened + && !phaseManager.hasReachedPhase("4D")) { + // Add treasury revenue as special revenue + baseRev.addSpecialRevenue(baseRev.getNormalRevenue()); + } + } + break; + case PORT: + Stop relatedCity = portCities.get(stop); + // No port revenue without a token in the connected city + if (relatedCity.hasTokenOf(company)) { + baseRev.addNormalRevenue(stop.getValueForPhase(phase)); + if (isGoods) { + baseRev.multiplyRevenue (2) + .addRevenue(relatedCity.getValue(), 0); + } + } + } + return baseRev; + } + + // Currently not used. + public Stop getCityOfPort (Stop port) { + return portCities.get(port); + } + + protected String prettyPrint(RevenueAdapter revenueAdapter) { + + String prettyPrint = super.prettyPrint (revenueAdapter); + + if (specialRevenue > 0){ + // Remove a redundant newline (source unknown) + // .replace() does not work (for unknown reasons) + prettyPrint = prettyPrint.stripTrailing() + "\n"; + int normalRevenue = revenueAdapter.getTotalRevenue() - specialRevenue; + prettyPrint += LocalText.getText("DivideEarnings", specialRevenue, normalRevenue); + } + return prettyPrint; + } + +} + + diff --git a/src/main/java/net/sf/rails/game/specific/_18VA/StartRound_18VA.java b/src/main/java/net/sf/rails/game/specific/_18VA/StartRound_18VA.java new file mode 100644 index 000000000..18ac3361a --- /dev/null +++ b/src/main/java/net/sf/rails/game/specific/_18VA/StartRound_18VA.java @@ -0,0 +1,368 @@ +package net.sf.rails.game.specific._18VA; + +import net.sf.rails.common.DisplayBuffer; +import net.sf.rails.common.LocalText; +import net.sf.rails.common.ReportBuffer; +import net.sf.rails.game.*; +import net.sf.rails.game.financial.Bank; +import net.sf.rails.game.financial.Certificate; +import net.sf.rails.game.financial.PublicCertificate; +import net.sf.rails.game.special.SpecialProperty; +import net.sf.rails.game.state.Currency; +import net.sf.rails.game.state.GenericState; +import net.sf.rails.game.state.MoneyOwner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import rails.game.action.*; + +import java.util.Set; + +/** + * Implements an 1830-style initial auction. + */ +public class StartRound_18VA extends StartRound { + private static final Logger log = LoggerFactory.getLogger(net.sf.rails.game.specific._18VA.StartRound_18VA.class); + + protected final int bidIncrement; + protected Player firstPasser = null; + + public static final String boName = "B&O"; + public final PublicCompany bo = companyManager.getPublicCompany(boName); + Player boBuyer; + StartItem boItem; + + private final GenericState auctionItemState = + new GenericState<>(this, "auctionItemState"); + + /** + * Constructed via Configure + */ + public StartRound_18VA(GameManager parent, String id) { + super(parent, id); + bidIncrement = startPacket.getModulus(); + } + + @Override + public void start() { + super.start(); + auctionItemState.set(null); + setPossibleActions(); + } + + /* + public boolean process(PossibleAction action) { + + if (!super.process(action)) return false; + + if (action instanceof BuyStartItem && action.getPlayer().equals(boBuyer)) { + BuyStartItem bsi = (BuyStartItem) action; + int price = bsi.getAssociatedSharePrice(); + PublicCompany bo = ((PublicCertificate)bsi.getStartItem().getPrimary()).getCompany(); + log.info("B&O share price = {}", price); + } + return true; + }*/ + + /** + * In 1826, starting the B&O involves two steps: + * 1. The certificate, as a part of the Start Packet, is bought + * but not yet started. + * In this step, the action attribute 'companyNeedingSharePrice' + * is set to null, so no price request happens. + * This needs no further action here. + * 2. Only if the whole Start Packet has been sold, the price is + * requested and set. The B&O starts when this is complete. + * In this step, the B&O is started after setting the price. + */ + @Override + protected void checksOnBuying(Certificate cert, int sharePrice) { + if (cert instanceof PublicCertificate) { + PublicCertificate pubCert = (PublicCertificate) cert; + PublicCompany comp = pubCert.getCompany(); + if (!comp.equals(bo)) return; // Impossible + + // Step 1 + if (sharePrice == 0) return; + // Step 2 + comp.start(sharePrice); + } + } + + @Override + public boolean setPossibleActions() { + + boolean passAllowed = true; + + possibleActions.clear(); + + if (playerManager.getCurrentPlayer() == startPlayer) ReportBuffer.add(this, ""); + + // FIXME: Rails 2.0 Could be an infinite loop if there if no player has enough money to buy an item + while (possibleActions.isEmpty()) { + Player currentPlayer = playerManager.getCurrentPlayer(); + + for (StartItem item : itemsToSell.view()) { + + if (item.isSold()) { + // Don't include + } else if (item.getStatus() == StartItem.NEEDS_SHARE_PRICE) { + /* B&O */ + playerManager.setCurrentPlayer(item.getBidder()); + possibleActions.add(new BuyStartItem(item, item.getBid(), false, true)); + passAllowed = false; + break; // No more actions + } else { + int currentBid = item.getBid(); + item.setMinimumBid(currentBid > 0 ? currentBid + bidIncrement : item.getBasePrice()); + item.setStatus(StartItem.BIDDABLE); + if (currentPlayer.getFreeCash() + + item.getBid(currentPlayer) >= item.getMinimumBid()) { + BidStartItem possibleAction = + new BidStartItem(item, item.getMinimumBid(), + startPacket.getModulus(), false); + possibleActions.add(possibleAction); + } + } + + } + + if (possibleActions.isEmpty()) { + numPasses.add(1); + if (auctionItemState.value() == null) { + playerManager.setCurrentToNextPlayer(); + } else { + setNextBiddingPlayer(auctionItemState.value()); + } + } + } + + if (passAllowed) { + possibleActions.add(new NullAction(getRoot(), NullAction.Mode.PASS)); + } + + return true; + } + + /*----- moveStack methods -----*/ + + /** + * The current player bids on a given start item. + * + * @param playerName The name of the current player (for checking purposes). + * @param bidItem The start item on which the bid is placed. + */ + @Override + protected boolean bid(String playerName, BidStartItem bidItem) { + + StartItem item = bidItem.getStartItem(); + String errMsg = null; + Player player = playerManager.getCurrentPlayer(); + int previousBid = 0; + int bidAmount = bidItem.getActualBid(); + + while (true) { + + // Check player + if (!playerName.equals(player.getId())) { + errMsg = LocalText.getText("WrongPlayer", playerName, player.getId()); + break; + } + // Check item + boolean validItem = false; + for (StartItemAction activeItem : possibleActions.getType(StartItemAction.class)) { + if (bidItem.equalsAsOption(activeItem)) { + validItem = true; + break; + } + + } + if (!validItem) { + errMsg = LocalText.getText("ActionNotAllowed", + bidItem.toString()); + break; + } + + // Is the item buyable? + if (bidItem.getStatus() != StartItem.BIDDABLE + && bidItem.getStatus() != StartItem.AUCTIONED) { + errMsg = LocalText.getText("NotForSale"); + break; + } + + // Bid must be at least 5 above last bid + if (bidAmount < item.getMinimumBid()) { + errMsg = LocalText.getText("BidTooLow", "" + + item.getMinimumBid()); + break; + } + + // Bid must be a multiple of the modulus + if (bidAmount % startPacket.getModulus() != 0) { + errMsg = LocalText.getText("BidMustBeMultipleOf", + bidAmount, + startPacket.getMinimumIncrement()); + break; + } + + // Has the buyer enough cash? + previousBid = item.getBid(player); + int available = player.getFreeCash() + previousBid; + if (bidAmount > available) { + errMsg = LocalText.getText("BidTooHigh", Bank.format(this, available)); + break; + } + + break; + } + + if (errMsg != null) { + DisplayBuffer.add(this, LocalText.getText("InvalidBid", + playerName, + item.getId(), + errMsg)); + return false; + } + + + item.setBid(bidAmount, player); + if (previousBid > 0) player.unblockCash(previousBid); + player.blockCash(bidAmount); + ReportBuffer.add(this, LocalText.getText("BID_ITEM_LOG", + playerName, + Bank.format(this, bidAmount), + item.getId(), + Bank.format(this, player.getFreeCash()))); + + playerManager.setCurrentToNextPlayer(); + + numPasses.set(0); + + return true; + + } + + /** + * Process a player's pass. + * + * @param playerName The name of the current player (for checking purposes). + */ + @Override + protected boolean pass(NullAction action, String playerName) { + + String errMsg = null; + Player player = playerManager.getCurrentPlayer(); + + while (true) { + + // Check player + if (!playerName.equals(player.getId())) { + errMsg = LocalText.getText("WrongPlayer", playerName, player.getId()); + break; + } + break; + } + + if (errMsg != null) { + DisplayBuffer.add(this, LocalText.getText("InvalidPass", + playerName, + errMsg)); + return false; + } + + ReportBuffer.add(this, LocalText.getText("PASSES", playerName)); + + numPasses.add(1); + if (numPasses.value() == 1) firstPasser = player; + + if (numPasses.value() >= playerManager.getNumberOfPlayers()) { + // All players have passed. + gameManager.reportAllPlayersPassed(); + playerManager.setPriorityPlayer(firstPasser); + + // Assign all biddable items that have at least one bid + for (StartItem item : startPacket.getUnsoldItems()) { + log.debug("Unsold item: {} bid={}", item, item.getBid()); + player = item.getBidder(); + if (item.getBidder() != null) { + int price = item.getBid(); + assignItem(player, item, price, 0); + + } + } + if (!startPacket.getUnsoldItems().isEmpty()) { + // If any item has not been bid upon, reduce its price by 10. + for (StartItem item : startPacket.getUnsoldItems()) { + item.reduceBasePriceBy(10); + ReportBuffer.add(this, LocalText.getText( + "ITEM_PRICE_REDUCED", + startPacket.getFirstUnsoldItem().getId(), + Bank.format(this, startPacket.getFirstUnsoldItem().getBasePrice()))); + numPasses.set(0); + if (item.getBasePrice() == 0) { + // Assign it to the priority holder + assignItem(playerManager.getPriorityPlayer(), item, 0, 0); + playerManager.setPriorityPlayerToNext(); + } + } + } + if (startPacket.getUnsoldItems().isEmpty()) { + // Finish start round. B&O owner must now set the share price. + if (bo.hasFloated()) { + finishRound(); + } else { + playerManager.setCurrentPlayer(boBuyer); + boItem.setStatus(StartItem.NEEDS_SHARE_PRICE); + } + } + } else { + playerManager.setCurrentToNextPlayer(); + } + + return true; + } + + + private void setNextBiddingPlayer(StartItem item, Player biddingPlayer) { + for (Player player : playerManager.getNextPlayersAfter(biddingPlayer, false, false)) { + if (item.isActive(player)) { + playerManager.setCurrentPlayer(player); + break; + } + } + } + + private void setNextBiddingPlayer(StartItem item) { + setNextBiddingPlayer(item, playerManager.getCurrentPlayer()); + } + + /** See Javadoc of checksOnBuying() */ + protected void assignItem(Player player, StartItem item, int price, + int sharePrice) { + + if (item.getDisplayName().equals(boName)) { + if (sharePrice == 0) { + // Step 1 + boBuyer = player; + boItem = item; + super.assignItem(player, item, price, sharePrice); + //item.setStatus(StartItem.NEEDS_SHARE_PRICE); + log.debug ("B&O step 1 done"); + } else { + // Step 2 + bo.start(sharePrice); + Currency.fromBank(2 * sharePrice, bo); + bo.setFloated(); + boBuyer = null; + item.setStatus(StartItem.SOLD); + log.debug ("B&O step 2 is done"); + } + } else { + super.assignItem(player, item, price, sharePrice); + log.debug ("Item {} assigned to {}", item, player); + } + } +} + + + + diff --git a/src/main/java/net/sf/rails/game/specific/_18VA/StockRound_18VA.java b/src/main/java/net/sf/rails/game/specific/_18VA/StockRound_18VA.java new file mode 100644 index 000000000..834a0c3d9 --- /dev/null +++ b/src/main/java/net/sf/rails/game/specific/_18VA/StockRound_18VA.java @@ -0,0 +1,49 @@ +package net.sf.rails.game.specific._18VA; + +import net.sf.rails.common.LocalText; +import net.sf.rails.common.ReportBuffer; +import net.sf.rails.game.GameManager; +import net.sf.rails.game.PublicCompany; +import net.sf.rails.game.financial.PublicCertificate; +import net.sf.rails.game.financial.StockRound; +import net.sf.rails.game.state.Currency; +import rails.game.action.BuyCertificate; + +public class StockRound_18VA extends StockRound { + + public StockRound_18VA(GameManager parent, String id) { + super(parent, id); + } + + @Override + public boolean buyShares(String playerName, BuyCertificate action) { + + boolean result = super.buyShares (playerName, action); + + /* When the 6th share of a 10-share company is bought, + * all remaining shares go to the Pool, and the company + * is fully capitalised. + * + * Note: as this is part of a one-time player action, + * and companies cannot trade their own shares, + * there is no danger that this buy follow-up will be repeated. + */ + PublicCompany company = action.getCompany(); + if (company.getShareUnit() == 10 && company.getPortfolioModel().getShares(company) == 4) { + for (PublicCertificate cert : company.getPortfolioModel().getCertificates(company)) { + cert.moveTo(pool); + } + int cash = 4 * company.getMarketPrice(); + String cashText = Currency.fromBank(cash, company); + ReportBuffer.add(this, LocalText.getText("SELL_SHARES_LOG", + company, + 4, + company.getShareUnit(), + (4 * company.getShareUnit()), + company, + cashText)); + + } + return result; + } +} diff --git a/src/main/java/net/sf/rails/game/specific/_18VA/Stops_18VA.java b/src/main/java/net/sf/rails/game/specific/_18VA/Stops_18VA.java new file mode 100644 index 000000000..2f6b2e519 --- /dev/null +++ b/src/main/java/net/sf/rails/game/specific/_18VA/Stops_18VA.java @@ -0,0 +1,65 @@ +package net.sf.rails.game.specific._18VA; + +import net.sf.rails.game.*; + +import java.util.HashMap; +import java.util.Map; + +public class Stops_18VA extends Stops { + + private Map cityPorts = new HashMap<>(); + + protected Stops_18VA (RailsRoot root) { + super (root); + + Stop port, city; + for (String cityName : GameDef_18VA.citiesWithPorts.keySet()) { + city = mapManager.getHex(cityName).getStops().asList().get(0); + port = mapManager.getHex(GameDef_18VA.citiesWithPorts.get(cityName)).getStops().asList().get(0); + cityPorts.put (city, port); + } + } + + @Override + protected Revenue getRevenue(Stop stop, Train train, PublicCompany company) { + return super.getRevenue(stop, train, company) + .addRevenue(getExtraRevenue(stop, train, company)); + } + + @Override + protected Revenue getExtraRevenue(Stop stop, Train train, PublicCompany company) { + Revenue extraRev = new Revenue(0, 0); + boolean isGoods = train.getCategory().equalsIgnoreCase("goods"); + boolean isTokened = stop.hasTokenOf(company); + Phase phase = phaseManager.getCurrentPhase(); + switch (stop.getType()) { + case PORT: + // The port revenue is added to the neighbouring city + extraRev.addNormalRevenue(-stop.getValue()); + break; + case MINE: // CMD + if (isGoods) { + int factor = stop.hasTokenOf(company) ? 2 : 1; + extraRev.addSpecialRevenue (factor * 20 * train.getMajorStops()); + } + break; + case OFFMAP: + if (stop.hasTokenOf(company)) { + extraRev.addNormalRevenue(stop.getValueForPhase(phase)); + } + break; + case TOWN: // mine + if (isGoods) extraRev.addNormalRevenue(stop.getValue()); + break; + case CITY: + if (cityPorts.containsKey(stop) && isTokened) { + Stop port = cityPorts.get(stop); + int portValue = port.getValueForPhase(phase); + extraRev.addNormalRevenue(stop.getValue() + portValue * (isGoods ? 2 : 1)); + } + break; + default: + } + return extraRev; + } +} diff --git a/src/main/java/net/sf/rails/game/specific/_18VA/TrainRunModifier.java b/src/main/java/net/sf/rails/game/specific/_18VA/TrainRunModifier.java index efb7a4299..ab4f1278d 100644 --- a/src/main/java/net/sf/rails/game/specific/_18VA/TrainRunModifier.java +++ b/src/main/java/net/sf/rails/game/specific/_18VA/TrainRunModifier.java @@ -20,85 +20,24 @@ public class TrainRunModifier private static final Logger log = LoggerFactory.getLogger(TrainRunModifier.class); - private int cmdValue; - private int cmdDirectValue; - private int portExtraValue; - private int offMapExtraValue; private PublicCompany company; - private Phase phase; + private int cmdDirectValue; @Override public boolean prepareModifier(RevenueAdapter revenueAdapter) { company = revenueAdapter.getCompany(); - phase = revenueAdapter.getPhase(); cmdDirectValue = 0; return true; } - @Override public int predictionValue(List runs) { - int predictionValue = 0; - for (RevenueTrainRun run : runs) { - Train train = run.getTrain().getRailsTrain(); - boolean isGoods = train.getCategory().equalsIgnoreCase("goods"); - int majors = 0; - int value = 0; - for (NetworkVertex v : run.getRunVertices()) { - switch (v.getStop().getRelatedStation().getType()) { - case PORT: - NetworkVertex port = v; - NetworkVertex city = getCityOfPort(v, run); - //value += port.getValue(); - if (isGoods) { - value += port.getValue() + city.getValue(); - } - break; - case MINE: // CMD - if (isGoods) { - //int factor = v.getStop().hasTokenOf(company) ? 2 : 1; - if (v.getStop().hasTokenOf(company)) { - value += 20 * train.getMajorStops(); - } - } - break; - case OFFMAP: - //int factor = v.getStop().hasTokenOf(company) ? 2 : 1; - if (v.getStop().hasTokenOf(company)) { - value += v.getValue(); - } - majors++; - break; - case TOWN: // mine - //if (isGoods) value += v.getValue(); - break; - case CITY: - majors++; - default: - //value += v.getValue(); - } - } - if (majors >= (isGoods ? 1 : 2)) { // Otherwise no valid run - log.debug("Prediction for {} {} is {}", - run.getTrain().getRailsTrain(), run.getRunVertices(), value); - - predictionValue += value; - } else { - log.debug ("Prediction for {} {} is 0 - not a valid run", - run.getTrain().getRailsTrain(), run.getRunVertices()); - } - } - log.debug ("Total extra prediction={}", predictionValue); - return predictionValue; + return 0; } + // FIXME The value calculations should use RevenueManager_18VA. private List identifyInvalidRuns(List runs) { - cmdValue = 0; - //cmdDirectValue = 0; - portExtraValue = 0; - offMapExtraValue = 0; - List vertices; List invalidRuns = new ArrayList<>(); int i = 0; @@ -122,11 +61,7 @@ private List identifyInvalidRuns(List runs) { log.debug("Skipped: no run"); continue; } - /* - log.debug(">>> Run {} {}: {}", i, t, - run.prettyPrint(true) - .replaceAll("\\n+", "") - .replaceAll("\\s+", " "));*/ + String trainCategory = run.getTrain().getRailsTrain().getCategory(); if (!Util.hasValue(trainCategory)) { invalidRuns.add(run); @@ -165,7 +100,7 @@ private List identifyInvalidRuns(List runs) { if (firstStationType == Stop.Type.PORT || lastStationType == Stop.Type.PORT) { boolean portReached = false; NetworkVertex port = firstStationType == Stop.Type.PORT ? firstVertex : lastVertex; - NetworkVertex city = getCityOfPort (port, run); + NetworkVertex city = getCityOfPort(port, run); if (city != null && city.getStop().hasTokenOf(company) && majors >= 2) { // An 1G-train cannot reach a port, which does not count as a separate station portReached = true; @@ -174,9 +109,6 @@ private List identifyInvalidRuns(List runs) { invalidRuns.add(run); log.debug("Skipped: port not reached"); continue; - } else if (isGoods && port != null && city != null) { - // Calculate extra port value - portExtraValue += port.getValue() + city.getValue(); } } @@ -189,14 +121,11 @@ private List identifyInvalidRuns(List runs) { continue; } cmdDirectValue = 0; - log.debug(">>>>> DirRev set to 0"); directValueReset = false; } Stop cmdStop = (firstStationType == Stop.Type.MINE ? firstStop : lastStop); int trainLevel = run.getTrain().getRailsTrain().getMajorStops(); - //int baseValue = trainLevel * cmdStop.getHex().getCurrentValueForPhase(phase); // 20 int baseValue = trainLevel * 20; - cmdValue += baseValue; if (isGoods && cmdStop.hasTokenOf(company)) { // Calculate CMD direct value (i.e. what goes into treasury) cmdDirectValue += baseValue; @@ -205,24 +134,11 @@ private List identifyInvalidRuns(List runs) { // Temporary fixture to keep passenger trains off towns (i.e. mines) if (!isGoods && (firstStationType == Stop.Type.TOWN || lastStationType == Stop.Type.TOWN)) { - invalidRuns.add (run); + invalidRuns.add(run); log.debug("Skipped: {} wrong category to mine (town)", trainCategory); continue; } - - // Calculate extra OffMap value - if (firstStationType == Stop.Type.OFFMAP || lastStationType == Stop.Type.OFFMAP - && !phase.getId().equalsIgnoreCase("4D")) { - Stop offMapStop = (firstStationType == Stop.Type.OFFMAP ? firstStop : lastStop); - if (offMapStop.hasTokenOf(company)) { - // Calculate offmap extra value - offMapExtraValue += offMapStop.getHex().getCurrentValueForPhase(phase); - } - } } - log.debug("After run validation: port={} cmd={} cmdDirect={} offmap={}", - portExtraValue, cmdValue, cmdDirectValue, offMapExtraValue); - return invalidRuns; } @@ -235,10 +151,7 @@ public int evaluationValue(List runs, boolean optimalRuns) { for (RevenueTrainRun run:identifyInvalidRuns(runs)) { changeRevenues -= run.getRunValue(); } - log.debug("Eval: inv={} port={} cmd={} direct={} off={}", - changeRevenues, portExtraValue, cmdValue, cmdDirectValue, offMapExtraValue); - // Note: total revenue must include direct revenue, which will be subtracted later - return changeRevenues + portExtraValue + cmdValue + cmdDirectValue + offMapExtraValue; + return 0; } @Override @@ -273,36 +186,29 @@ public int getSpecialRevenue () { @Override public String prettyPrint(RevenueAdapter adapter) { - StringBuilder b = new StringBuilder(""); - if (portExtraValue != 0) b.append("Port bonus = ").append(portExtraValue); - if (cmdValue != 0) b.append(b.length() > 0 ? ", " : "") - .append("CMD value = ").append(cmdValue); - if (cmdDirectValue != 0) b.append(b.length() > 0 ? ", " : "") - .append("CMD treasury income = ").append(cmdDirectValue); - if (offMapExtraValue != 0) b.append(b.length() > 0 ? ", " : "") - .append("OffMap bonus = ").append(offMapExtraValue); - return b.length() > 0 ? b.toString() : null; + return ""; } + + // Should if possible be merged with the similar method in RevenueManager_18VA. + // That one uses stops, this one vertices. Not sure what is better. private NetworkVertex getCityOfPort (NetworkVertex port, RevenueTrainRun run) { - if (port.getStop().getRelatedStation().getType() != Stop.Type.PORT) { + if (port.getStop().getType() != Stop.Type.PORT) { log.debug ("Error: {} is not a Port!", port); return null; } List portVertices = new ArrayList<>(run.getRunVertices()); - NetworkVertex city = null; + if (run.getLastVertex() == port) { Collections.reverse(portVertices); } for (NetworkVertex vertex : portVertices) { if (!vertex.isSide() - && vertex.getStop().getRelatedStation().getType() == Stop.Type.CITY) { + && vertex.getStop().getType() == Stop.Type.CITY) { // This must be the city where the port belongs to - city = vertex; - log.debug("Found city {} for port {}", city.getStop(), port.getStop()); - break; + return vertex; } } - return city; + return null; } } diff --git a/src/main/java/net/sf/rails/game/state/Ownable.java b/src/main/java/net/sf/rails/game/state/Ownable.java index fc4151fc2..d958a4e37 100644 --- a/src/main/java/net/sf/rails/game/state/Ownable.java +++ b/src/main/java/net/sf/rails/game/state/Ownable.java @@ -1,6 +1,6 @@ package net.sf.rails.game.state; -public interface Ownable extends Item, Comparable { +public interface Ownable extends Item, Comparable { /** * Moves the ownable (item) to the new owner diff --git a/src/main/java/net/sf/rails/tools/ListAndFixSavedFiles.java b/src/main/java/net/sf/rails/tools/ListAndFixSavedFiles.java index 568fcbe5a..52bc893f6 100644 --- a/src/main/java/net/sf/rails/tools/ListAndFixSavedFiles.java +++ b/src/main/java/net/sf/rails/tools/ListAndFixSavedFiles.java @@ -379,7 +379,9 @@ private void save() { private void edit(int index) { editedAction = gameLoader.getActions().get(index); editedIndex = index; - if (editedAction instanceof BuyTrain) { + if (editedAction instanceof BidStartItem) { + new BidStartItemDialog ((BidStartItem) editedAction); + } else if (editedAction instanceof BuyTrain) { new BuyTrainDialog ((BuyTrain) editedAction); } else if (editedAction instanceof LayTile) { new LayTileDialog((LayTile) editedAction); @@ -473,6 +475,51 @@ public void actionPerformed(ActionEvent arg0) { abstract PossibleAction processInput(); } + private class BidStartItemDialog extends EditDialog { + private static final long serialVersionUID = 1L; + private BidStartItem action; + + BidStartItemDialog (BidStartItem action) { + super ("Edit BidStartItem"); + this.action = action; + addTextField (this, "Minimum bid", + action.getMinimumBid(), + String.valueOf(action.getMinimumBid())); // 0 + addTextField (this, "Bid increment", + action.getBidIncrement(), + String.valueOf(action.getBidIncrement())); // 1 + addTextField (this, "Actual bid", + action.getActualBid(), + String.valueOf(action.getActualBid())); // 2 + finish(); + } + + @Override + PossibleAction processInput() { + log.debug("Action was {}", action); + try { + int minBid = Integer.parseInt(((JTextField)inputElements.get(0)).getText()); + action.setMinimumBid(minBid); + } catch (NumberFormatException e) { + } + try { + int bidIncr = Integer.parseInt(((JTextField)inputElements.get(1)).getText()); + action.setBidIncrement(bidIncr); + } catch (NumberFormatException e) { + } + try { + int actualBid = Integer.parseInt(((JTextField)inputElements.get(2)).getText()); + action.setActualBid(actualBid); + } catch (NumberFormatException e) { + } + + log.debug("Action is {}", action); + return action; + + } + } + + private class BuyTrainDialog extends EditDialog { private static final long serialVersionUID = 1L; private BuyTrain action; diff --git a/src/main/java/net/sf/rails/ui/swing/hexmap/GUIHex.java b/src/main/java/net/sf/rails/ui/swing/hexmap/GUIHex.java index 324ac108c..f6da01e9e 100644 --- a/src/main/java/net/sf/rails/ui/swing/hexmap/GUIHex.java +++ b/src/main/java/net/sf/rails/ui/swing/hexmap/GUIHex.java @@ -17,6 +17,7 @@ import java.util.Map; import java.util.Set; +import net.sf.rails.util.Util; import rails.game.action.LayBaseToken; import rails.game.action.LayBonusToken; import net.sf.rails.algorithms.RevenueBonusTemplate; @@ -37,6 +38,7 @@ import net.sf.rails.ui.swing.GUIToken; import com.google.common.collect.Lists; +import rails.game.action.PossibleORAction; /** @@ -238,8 +240,8 @@ private GeneralPath makePolygon() { private static final int MARKS_DIRTY_MARGIN = 4; // positions of offStation Tokens - private static final int[] offStationTokenX = new int[] { -11, 0 }; - private static final int[] offStationTokenY = new int[] { -19, 0 }; + private static final int[] offStationTokenX = new int[] { 11, -11 }; + private static final int[] offStationTokenY = new int[] { -19, 19 }; // static fields private final HexMap hexMap; @@ -625,21 +627,40 @@ private void paintStationTokens(Graphics2D g2) { } } - // FIXME: Where to paint more than one offStationTokens? private void paintOffStationTokens(Graphics2D g2) { + Util.breakIf(hex.getId(), "M6"); int i = 0; for (BonusToken token : hex.getBonusTokens()) { HexPoint origin = dimensions.center.translate(offStationTokenX[i], offStationTokenY[i]); drawBonusToken(g2, token, origin); if (++i > 1) return; - } // check for temporary token if (upgrade instanceof TokenHexUpgrade && ((TokenHexUpgrade) upgrade).getAction() instanceof LayBonusToken) { HexPoint origin = dimensions.center.translate(offStationTokenX[i], offStationTokenY[i]); BonusToken token = ((LayBonusToken)((TokenHexUpgrade) upgrade).getAction()).getToken(); drawBonusToken(g2, token, origin); + if (++i > 1) return; + } + + // For 18VA: also check for off-station base tokens + for (BaseToken token : hex.getOffStationBaseTokens()) { + HexPoint origin = dimensions.center.translate(offStationTokenX[i], offStationTokenY[i]); + drawBaseToken(g2, token.getParent(), origin, dimensions.tokenDiameter); + if (++i > 1) return; } + // check for temporary token + if (upgrade instanceof TokenHexUpgrade) { + TokenHexUpgrade tokenUpgrade = (TokenHexUpgrade) upgrade; + PossibleORAction action = ((TokenHexUpgrade) upgrade).getAction(); + if (action instanceof LayBaseToken + && ((LayBaseToken)action).getType() == LayBaseToken.NON_CITY) { + HexPoint origin = dimensions.center.translate(offStationTokenX[i], offStationTokenY[i]); + PublicCompany company = tokenUpgrade.getAction().getCompany(); + drawBaseToken(g2, company, origin, dimensions.tokenDiameter); + } + } + } private void drawBaseToken(Graphics2D g2, PublicCompany co, HexPoint center, double diameter) { diff --git a/src/main/java/rails/game/action/BidStartItem.java b/src/main/java/rails/game/action/BidStartItem.java index 2b679b681..28072913a 100644 --- a/src/main/java/rails/game/action/BidStartItem.java +++ b/src/main/java/rails/game/action/BidStartItem.java @@ -70,6 +70,14 @@ public boolean isSelectForAuction() { return selectForAuction; } + public void setMinimumBid(int minimumBid) { + this.minimumBid = minimumBid; + } + + public void setBidIncrement(int bidIncrement) { + this.bidIncrement = bidIncrement; + } + public void setActualBid(int actualBid) { this.actualBid = actualBid; } diff --git a/src/main/java/rails/game/action/DiscardTrain.java b/src/main/java/rails/game/action/DiscardTrain.java index a6d632833..d1e1fd361 100644 --- a/src/main/java/rails/game/action/DiscardTrain.java +++ b/src/main/java/rails/game/action/DiscardTrain.java @@ -191,7 +191,7 @@ protected boolean equalsAs(PossibleAction pa, boolean asOption) { // See the top Javadoc. if (idsChanged) { executedAction.fixIds(this); - log.info("+++ Action corrected to {}", executedAction); + log.info("Action corrected to {}", executedAction); } return options; diff --git a/src/main/resources/LocalisedText.properties b/src/main/resources/LocalisedText.properties index 0346694f1..bef4df7f8 100644 --- a/src/main/resources/LocalisedText.properties +++ b/src/main/resources/LocalisedText.properties @@ -366,6 +366,7 @@ DIRECT_INCOME=Direct Rev. DiscardsBaseToken={0} discards a {1} base token on {2} DiscardingTrain=discarding {0}-train discount=discount of {0} +DivideEarnings=Split: {0} for company treasury, {1} for dividend DoesNotExist=Item does not exist DoesNotForm={0} does not form DoesNotHaveTheShares=Does not have the shares diff --git a/src/main/resources/data/18VA/CompanyManager.xml b/src/main/resources/data/18VA/CompanyManager.xml index 05f3bc159..862cb1b9e 100644 --- a/src/main/resources/data/18VA/CompanyManager.xml +++ b/src/main/resources/data/18VA/CompanyManager.xml @@ -1,14 +1,17 @@ - + - + + + + @@ -22,17 +25,52 @@ - + + + + + + + + + + longname="Tredegar Iron Works"> + + + + + + + + + + + + + + + + - - + + - + @@ -82,7 +82,7 @@ - + @@ -96,7 +96,7 @@ - + @@ -121,7 +121,7 @@ - + diff --git a/src/main/resources/data/18VA/Map.xml b/src/main/resources/data/18VA/Map.xml index 4acd5d640..313fd5485 100644 --- a/src/main/resources/data/18VA/Map.xml +++ b/src/main/resources/data/18VA/Map.xml @@ -6,7 +6,7 @@ - + - + @@ -53,7 +53,7 @@ - + diff --git a/src/main/resources/data/18VA/TileSet.xml b/src/main/resources/data/18VA/TileSet.xml index a6f9b2e7c..f6ea8d16c 100644 --- a/src/main/resources/data/18VA/TileSet.xml +++ b/src/main/resources/data/18VA/TileSet.xml @@ -60,16 +60,16 @@ - + - + - + - + @@ -83,9 +83,9 @@ - - - + + + diff --git a/src/main/resources/data/GamesList.xml b/src/main/resources/data/GamesList.xml index 07d4ef29d..c424fcf6b 100644 --- a/src/main/resources/data/GamesList.xml +++ b/src/main/resources/data/GamesList.xml @@ -281,6 +281,29 @@ Game variants: + + Playable (alpha) + 18VA + (c) David G.D. Hecht 2001-2005 + Rules version 1.00 of 10 May 2005 + + Not yet fully developed or tested: + - Share selling in emergency train buying + (taking loans, bonds and president cash works) + - Bankruptcy + - Passenger trains running through but ignoring + towns (mines). + + Notes: + - When the port and neighbouring city values are doubled, + the extra revenue of the city is added to the port value + in the revenue details display (the blue small-print text). + The reason is, that the doubling only occurs if the port is reached. + + + + + Not yet playable 1870 - Railroading across the Trans Mississippi @@ -327,12 +350,6 @@ Known Issues: - - Prototype - 18VA - - - Prototype - Not Playable 1862 diff --git a/src/test/resources/data/real/18EUK41.rails b/src/test/resources/data/real/18EUK41.rails new file mode 100644 index 000000000..06ed48ca2 Binary files /dev/null and b/src/test/resources/data/real/18EUK41.rails differ diff --git a/src/test/resources/data/real/18EUK41.report b/src/test/resources/data/real/18EUK41.report new file mode 100644 index 000000000..a419ef517 --- /dev/null +++ b/src/test/resources/data/real/18EUK41.report @@ -0,0 +1,1836 @@ +GameIs,18EU +PlayerIs,1,John +PlayerIs,2,Mike +PlayerIs,3,Stephen +PlayerIs,4,Mark +PlayerCash,350 +BankHas,10600 +StartOfPhase,2 +BankSizeIs,10600 +StartOfInitialRound,1 +HasPriority,John + +SelectForAuctioning,John,7 +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,7,90 +BuysItemFor,John,7,90 +Floats,7 + +SelectForAuctioning,Mike,12 +BID_ITEM,Stephen,100,12 +PASSES,Mark +PASSES,John +BID_ITEM,Mike,110,12 +PASSES,Stephen +BuysItemFor,Mike,12,110 +Floats,12 + +SelectForAuctioning,Stephen,2 +BID_ITEM,Stephen,100,2 +PASSES,Mark +BID_ITEM,John,105,2 +BID_ITEM,Mike,110,2 +BID_ITEM,Stephen,115,2 +PASSES,John +BID_ITEM,Mike,120,2 +PASSES,Stephen +BuysItemFor,Mike,2,120 +Floats,2 + +SelectForAuctioning,Mark,8 +DeclinedToBid,John +DeclinedToBid,Mike +DeclinedToBid,Stephen +ITEM_PRICE_REDUCED,8,90 +BuysItemFor,Mark,8,90 +Floats,8 + +SelectForAuctioning,John,13 +DeclinedToBid,Mike +BID_ITEM,Stephen,100,13 +PASSES,Mark +BID_ITEM,John,105,13 +PASSES,Mike +BID_ITEM,Stephen,110,13 +BID_ITEM,John,120,13 +PASSES,Stephen +BuysItemFor,John,13,120 +Floats,13 + +SelectForAuctioning,Mike,5 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +ITEM_PRICE_REDUCED,5,90 +DeclinedToBid,Mike +DeclinedToBid,Stephen +BuysItemFor,Mark,5,90 +Floats,5 + +SelectForAuctioning,Stephen,3 +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,3,90 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,3,80 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,3,70 +BuysItemFor,Stephen,3,70 +Floats,3 + +SelectForAuctioning,Mark,10 +DeclinedToBid,John +DeclinedToBid,Mike +DeclinedToBid,Stephen +ITEM_PRICE_REDUCED,10,90 +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +DeclinedToBid,Stephen +ITEM_PRICE_REDUCED,10,80 +BuysItemFor,Mark,10,80 +Floats,10 + +SelectForAuctioning,John,4 +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,4,90 +DeclinedToBid,John +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,4,80 +DeclinedToBid,John +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,4,70 +DeclinedToBid,John +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,4,60 +BuysItemFor,John,4,60 +Floats,4 + +SelectForAuctioning,Mike,1 +BID_ITEM,Mike,100,1 +BID_ITEM,Stephen,110,1 +PASSES,Mark +PASSES,John +BID_ITEM,Mike,120,1 +PASSES,Stephen +BuysItemFor,Mike,1,120 +Floats,1 + +SelectForAuctioning,Stephen,11 +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,11,90 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,11,80 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,11,70 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,11,60 +BuysItemFor,Stephen,11,60 +Floats,11 + +SelectForAuctioning,Mark,9 +DeclinedToBid,John +DeclinedToBid,Mike +DeclinedToBid,Stephen +ITEM_PRICE_REDUCED,9,90 +BuysItemFor,Mark,9,90 +Floats,9 + +SelectForAuctioning,John,14 +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,14,90 +DeclinedToBid,John +DeclinedToBid,Mike +BuysItemFor,Stephen,14,90 +Floats,14 + +SelectForAuctioning,Mike,6 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +ITEM_PRICE_REDUCED,6,90 +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +ITEM_PRICE_REDUCED,6,80 +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +ITEM_PRICE_REDUCED,6,70 +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +ITEM_PRICE_REDUCED,6,60 +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +ITEM_PRICE_REDUCED,6,50 +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +ITEM_PRICE_REDUCED,6,40 +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +ITEM_PRICE_REDUCED,6,30 +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +ITEM_PRICE_REDUCED,6,20 +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +ITEM_PRICE_REDUCED,6,10 +DeclinedToBid,Mike +DeclinedToBid,Stephen +DeclinedToBid,Mark +BuysItemFor,John,6,10 +Floats,6 + +SelectForAuctioning,Stephen,15 +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,15,90 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,15,80 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,15,70 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,15,60 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,15,50 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,15,40 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,15,30 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,15,20 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,15,10 +DeclinedToBid,Stephen +DeclinedToBid,Mark +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,15,0 +BuysItemFor,Stephen,15,0 +NewTrainAvailable,2,3 +Floats,15 +Has,1,0 +Has,2,0 +Has,3,0 +Has,4,0 +Has,5,0 +Has,6,0 +Has,7,0 +Has,8,0 +Has,9,0 +Has,10,0 +Has,11,0 +Has,12,0 +Has,13,0 +Has,14,0 +Has,15,0 +Has,John,70 +Has,Mike,0 +Has,Stephen,130 +Has,Mark,0 +START_OR,0.1 + +CompanyOperates,1,Mike +LaysTileAt,1,9,I2,SW +LaysTileAt,1,201,H3,NW +CompanyRevenue,1,70 +CompanySplits,1,70 +RECEIVES,1,35 +Payout,Mike,35,1,100 + +CompanyOperates,2,Mike +LaysTileAt,2,3,G2,NE +LaysTileAt,2,4,F3,SW +CompanyRevenue,2,90 +CompanySplits,2,90 +RECEIVES,2,45 +Payout,Mike,45,1,100 + +CompanyOperates,3,Stephen +LaysTileAt,3,8,K2,S +LaysTileAt,3,4,M2,S +CompanyRevenue,3,50 +CompanySplits,3,50 +RECEIVES,3,25 +Payout,Stephen,25,1,100 + +CompanyOperates,4,John +LaysTileAt,4,202,G10,NE +LaysTileAt,4,4,H9,SW +CompanyRevenue,4,40 +CompanySplits,4,40 +RECEIVES,4,20 +Payout,John,20,1,100 + +CompanyOperates,5,Mark +LaysTileAt,5,201,S8,SW +LaysTileAt,5,8,U8,SW +CompanyRevenue,5,60 +CompanySplits,5,60 +RECEIVES,5,30 +Payout,Mark,30,1,100 + +CompanyOperates,6,John +LaysTileAt,6,58,L11,S +LaysTileAt,6,57,K10,NW +CompanyRevenue,6,60 +CompanySplits,6,60 +RECEIVES,6,30 +Payout,John,30,1,100 + +CompanyOperates,7,John +LaysTileAt,7,9,F9,SW +LaysTileAt,7,4,G8,SW +CompanyRevenue,7,40 +CompanySplits,7,40 +RECEIVES,7,20 +Payout,John,20,1,100 + +CompanyOperates,8,Mark +LaysTileAt,8,202,P13,S +LaysTileAt,8,9,N13,S +CompanyRevenue,8,60 +CompanySplits,8,60 +RECEIVES,8,30 +Payout,Mark,30,1,100 + +CompanyOperates,9,Mark +LaysTileAt,9,58,D11,SE +LaysTileAt,9,4,E12,NW +CompanyRevenue,9,50 +CompanySplits,9,50 +RECEIVES,9,25 +Payout,Mark,25,1,100 + +CompanyOperates,10,Mark +LaysTileAt,10,201,R5,S +LaysTileAt,10,57,T5,S +CompanyRevenue,10,60 +CompanySplits,10,60 +RECEIVES,10,30 +Payout,Mark,30,1,100 + +CompanyOperates,11,Stephen +LaysTileAt,11,9,Q10,SW +LaysTileAt,11,57,R9,SW +CompanyRevenue,11,50 +CompanySplits,11,50 +RECEIVES,11,25 +Payout,Stephen,25,1,100 + +CompanyOperates,12,Mike +LaysTileAt,12,201,C4,S +LaysTileAt,12,58,E4,SW +CompanyRevenue,12,90 +CompanySplits,12,90 +RECEIVES,12,45 +Payout,Mike,45,1,100 + +CompanyOperates,13,John +LaysTileAt,13,201,L7,N +LaysTileAt,13,4,J7,S +CompanyRevenue,13,40 +CompanySplits,13,40 +RECEIVES,13,20 +Payout,John,20,1,100 + +CompanyOperates,14,Stephen +LaysTileAt,14,202,M4,SW +LaysTileAt,14,58,O4,SW +CompanyRevenue,14,40 +CompanySplits,14,40 +RECEIVES,14,20 +Payout,Stephen,20,1,100 + +CompanyOperates,15,Stephen +LaysTileAt,15,201,Q2,NE +LaysTileAt,15,4,P3,SW +CompanyRevenue,15,80 +CompanySplits,15,80 +RECEIVES,15,40 +Payout,Stephen,40,1,100 + +EndOfOperatingRound,0.1 +ORWorthIncrease,John,0.1,90 +ORWorthIncrease,Mike,0.1,125 +ORWorthIncrease,Stephen,0.1,110 +ORWorthIncrease,Mark,0.1,115 +Has,1,35 +Has,2,45 +Has,3,25 +Has,4,20 +Has,5,30 +Has,6,30 +Has,7,20 +Has,8,30 +Has,9,25 +Has,10,30 +Has,11,25 +Has,12,45 +Has,13,20 +Has,14,20 +Has,15,40 +Has,John,160 +Has,Mike,125 +Has,Stephen,240 +Has,Mark,115 +START_OR,0.2 + +CompanyOperates,1,Mike +CompanyRevenue,1,70 +CompanySplits,1,70 +RECEIVES,1,35 +Payout,Mike,35,1,100 + +CompanyOperates,2,Mike +CompanyRevenue,2,100 +CompanySplits,2,100 +RECEIVES,2,50 +Payout,Mike,50,1,100 + +CompanyOperates,3,Stephen +LaysTileAt,3,9,O2,S +CompanyRevenue,3,80 +CompanySplits,3,80 +RECEIVES,3,40 +Payout,Stephen,40,1,100 + +CompanyOperates,4,John +LaysTileAt,4,8,I8,NE +CompanyRevenue,4,40 +CompanySplits,4,40 +RECEIVES,4,20 +Payout,John,20,1,100 + +CompanyOperates,5,Mark +LaysTileAt,5,4,T7,SW +CompanyRevenue,5,70 +CompanySplits,5,70 +RECEIVES,5,35 +Payout,Mark,35,1,100 + +CompanyOperates,6,John +CompanyRevenue,6,60 +CompanySplits,6,60 +RECEIVES,6,30 +Payout,John,30,1,100 + +CompanyOperates,7,John +LaysTileAt,7,8,H7,NE +CompanyRevenue,7,80 +CompanySplits,7,80 +RECEIVES,7,40 +Payout,John,40,1,100 + +CompanyOperates,8,Mark +LaysTileAt,8,9,L13,S +CompanyRevenue,8,60 +CompanySplits,8,60 +RECEIVES,8,30 +Payout,Mark,30,1,100 + +CompanyOperates,9,Mark +LaysTileAt,9,8,F13,S +CompanyRevenue,9,50 +CompanySplits,9,50 +RECEIVES,9,25 +Payout,Mark,25,1,100 + +CompanyOperates,10,Mark +LaysTileAt,10,8,S6,S +CompanyRevenue,10,60 +CompanySplits,10,60 +RECEIVES,10,30 +Payout,Mark,30,1,100 + +CompanyOperates,11,Stephen +CompanyRevenue,11,50 +CompanySplits,11,50 +RECEIVES,11,25 +Payout,Stephen,25,1,100 +BuysTrain,11,2,3,50 + +CompanyOperates,12,Mike +LaysTileAt,12,8,D5,NW +CompanyRevenue,12,90 +CompanySplits,12,90 +RECEIVES,12,45 +Payout,Mike,45,1,100 + +CompanyOperates,13,John +LaysTileAt,13,58,K6,N +CompanyRevenue,13,90 +CompanySplits,13,90 +RECEIVES,13,45 +Payout,John,45,1,100 + +CompanyOperates,14,Stephen +LaysTileAt,14,4,L5,SW +CompanyRevenue,14,90 +CompanySplits,14,90 +RECEIVES,14,45 +Payout,Stephen,45,1,100 +BuysTrain,14,2,11,1 + +CompanyOperates,15,Stephen +CompanyRevenue,15,100 +CompanySplits,15,100 +RECEIVES,15,50 +Payout,Stephen,50,1,100 + +EndOfOperatingRound,0.2 +ORWorthIncrease,John,0.2,135 +ORWorthIncrease,Mike,0.2,130 +ORWorthIncrease,Stephen,0.2,160 +ORWorthIncrease,Mark,0.2,120 +Has,1,70 +Has,2,95 +Has,3,115 +Has,4,40 +Has,5,65 +Has,6,60 +Has,7,60 +Has,8,60 +Has,9,50 +Has,10,60 +Has,11,1 +Has,12,90 +Has,13,65 +Has,14,64 +Has,15,90 +Has,John,295 +Has,Mike,255 +Has,Stephen,400 +Has,Mark,235 +StartStockRound,1 +HasPriority,John +START_COMPANY_LOG,John,DR,90,180,2,20,DR +MERGE_MINOR_LOG,John,7,DR,60,1 +GetShareForMinor,John,10,DR,7 +SharesPutInTreasury,70,DR +PaysForTokens,DR,100,5 +START_COMPANY_LOG,Mike,SNCB,82,164,2,20,SNCB +MERGE_MINOR_LOG,Mike,2,SNCB,95,1 +GetShareForMinor,Mike,10,SNCB,2 +SharesPutInTreasury,70,SNCB +PaysForTokens,SNCB,100,5 +START_COMPANY_LOG,Stephen,FS,100,200,2,20,FS +MERGE_MINOR_LOG,Stephen,15,FS,90,1 +GetShareForMinor,Stephen,10,FS,15 +SharesPutInTreasury,70,FS +PaysForTokens,FS,100,5 +BUY_SHARE_LOG,Mark,10,SNCB,SNCB,82 +MERGE_MINOR_LOG,John,13,DR,65,1 +GetShareForMinor,John,10,DR,13 +ExchangesBaseToken,DR,13,L7 +MinorCloses,13 +MERGE_MINOR_LOG,Mike,1,SNCB,70,1 +GetShareForMinor,Mike,10,SNCB,1 +NoBaseTokenExchange,SNCB,1,J1 +MinorCloses,1 +Floats,SNCB +MERGE_MINOR_LOG,Stephen,3,FS,115,0 +GetShareForMinor,Stephen,10,FS,3 +NoBaseTokenExchange,FS,3,J1 +MinorCloses,3 +BUY_SHARE_LOG,Mark,10,DR,DR,90 +Floats,DR +BUY_SHARE_LOG,John,10,DR,DR,90 +BUY_SHARE_LOG,Mike,10,SNCB,SNCB,82 +BUY_SHARE_LOG,Stephen,10,FS,FS,100 +Floats,FS +PASSES,Mark +PASSES,John +PASSES,Mike +BUY_SHARE_LOG,Stephen,10,SNCB,SNCB,82 +PASSES,Mark +PASSES,John +PASSES,Mike +PASSES,Stephen + +END_SR,1 +Has,4,40 +Has,5,65 +Has,6,60 +Has,8,60 +Has,9,50 +Has,10,60 +Has,11,1 +Has,12,90 +Has,14,64 +Has,SNCB,475 +Has,FS,405 +Has,DR,385 +Has,John,25 +Has,Mike,9 +Has,Stephen,18 +Has,Mark,63 +START_OR,1.1 + +CompanyOperates,4,John +LaysTileAt,4,7,K8,N +CompanyRevenue,4,40 +CompanySplits,4,40 +RECEIVES,4,20 +Payout,John,20,1,100 + +CompanyOperates,5,Mark +LaysTileAt,5,3,U6,N +CompanyRevenue,5,80 +CompanySplits,5,80 +RECEIVES,5,40 +Payout,Mark,40,1,100 + +CompanyOperates,6,John +LaysTileAtFor,6,8,J9,SE,60 +CompanyRevenue,6,60 +CompanySplits,6,60 +RECEIVES,6,30 +Payout,John,30,1,100 + +CompanyOperates,8,Mark +LaysTileAtFor,8,4,J13,S,60 +CompanyRevenue,8,70 +CompanySplits,8,70 +RECEIVES,8,35 +Payout,Mark,35,1,100 + +CompanyOperates,9,Mark +LaysTileAt,9,9,H13,S +CompanyRevenue,9,90 +CompanySplits,9,90 +RECEIVES,9,45 +Payout,Mark,45,1,100 +BuysTrain,9,2,5,95 + +CompanyOperates,10,Mark +CompanyRevenue,10,80 +CompanySplits,10,80 +RECEIVES,10,40 +Payout,Mark,40,1,100 +BuysTrain,10,2,9,45 + +CompanyOperates,11,Stephen +CompanyRevenue,11,50 +CompanySplits,11,50 +RECEIVES,11,25 +Payout,Stephen,25,1,100 + +CompanyOperates,12,Mike +CompanyRevenue,12,90 +CompanySplits,12,90 +RECEIVES,12,45 +Payout,Mike,45,1,100 + +CompanyOperates,14,Stephen +CompanyRevenue,14,120 +CompanySplits,14,120 +RECEIVES,14,60 +Payout,Stephen,60,1,100 + +CompanyOperates,FS,Stephen +CompanyRevenue,FS,100 +CompanyPaysOutFull,FS,100 +Payout,Stephen,50,5,10 +Payout,FS,50,5,10 +PRICE_MOVES_LOG,FS,100,E3,110,F3 +BuysTrain,FS,3,IPO,200 +FirstTrainBought,3 +StartOfPhase,3 +BuysTrain,FS,2,14,177 + +CompanyOperates,DR,John +LaysTileAt,DR,581,E10,SW +CompanyRevenue,DR,140 +CompanyPaysOutFull,DR,140 +Payout,John,70,5,10 +Payout,Mark,14,1,10 +Payout,DR,56,4,10 +PRICE_MOVES_LOG,DR,90,E4,100,F4 +BuysTrain,DR,3,IPO,200 +BuysTrain,DR,3,IPO,200 + +CompanyOperates,SNCB,Mike +LaysTileAt,SNCB,580,J1,S +LAYS_FREE_TOKEN_ON,SNCB,J1 +CompanyRevenue,SNCB,180 +CompanyPaysOutFull,SNCB,180 +Payout,Stephen,18,1,10 +Payout,Mike,90,5,10 +Payout,Mark,18,1,10 +Payout,SNCB,54,3,10 +PRICE_MOVES_LOG,SNCB,82,D4,90,E4 +BuysTrain,SNCB,3,IPO,200 +BuysTrain,SNCB,3,IPO,200 +NewTrainAvailable,3,4 + +EndOfOperatingRound,1.1 +ORWorthIncrease,John,1.1,170 +ORWorthIncrease,Mike,1.1,175 +ORWorthIncrease,Stephen,1.1,211 +ORWorthIncrease,Mark,1.1,210 +Has,4,60 +Has,5,200 +Has,6,30 +Has,8,35 +Has,9,45 +Has,10,55 +Has,11,26 +Has,12,135 +Has,14,301 +Has,SNCB,129 +Has,FS,78 +Has,DR,41 +Has,John,145 +Has,Mike,144 +Has,Stephen,171 +Has,Mark,255 +START_OR,1.2 + +CompanyOperates,4,John +LaysTileAt,4,8,F11,NW +CompanyRevenue,4,90 +CompanySplits,4,90 +RECEIVES,4,45 +Payout,John,45,1,100 +BuysTrain,4,2,6,105 + +CompanyOperates,5,Mark +CompanyDoesNotPayDividend,5 +BuysTrain,5,2,10,200 + +CompanyOperates,6,John +CompanyDoesNotPayDividend,6 +BuysTrain,6,3,DR,135 + +CompanyOperates,8,Mark +CompanyRevenue,8,110 +CompanySplits,8,110 +RECEIVES,8,55 +Payout,Mark,55,1,100 + +CompanyOperates,9,Mark +LaysTileAt,9,7,C10,S +CompanyRevenue,9,110 +CompanySplits,9,110 +RECEIVES,9,55 +Payout,Mark,55,1,100 + +CompanyOperates,10,Mark +CompanyRevenue,10,80 +CompanySplits,10,80 +RECEIVES,10,40 +Payout,Mark,40,1,100 + +CompanyOperates,11,Stephen +CompanyRevenue,11,50 +CompanySplits,11,50 +RECEIVES,11,25 +Payout,Stephen,25,1,100 + +CompanyOperates,12,Mike +CompanyRevenue,12,90 +CompanySplits,12,90 +RECEIVES,12,45 +Payout,Mike,45,1,100 + +CompanyOperates,14,Stephen +CompanyRevenue,14,90 +CompanySplits,14,90 +RECEIVES,14,45 +Payout,Stephen,45,1,100 +BuysTrain,14,4,IPO,300 +FirstTrainBought,4 +StartOfPhase,4 +TrainsRusted,2 + +CompanyOperates,FS,Stephen +LaysTileAt,FS,576,Q2,S +CompanyRevenue,FS,160 +CompanyPaysOutFull,FS,160 +Payout,Stephen,80,5,10 +Payout,FS,80,5,10 +PRICE_MOVES_LOG,FS,110,F3,122,G3 + +CompanyOperates,DR,John +LaysTileAt,DR,57,I6,S +CompanyRevenue,DR,130 +CompanyPaysOutFull,DR,130 +Payout,John,65,5,10 +Payout,Mark,13,1,10 +Payout,DR,52,4,10 +PRICE_MOVES_LOG,DR,100,F4,110,G4 +BuysTrain,DR,P,Pool,100 + +CompanyOperates,SNCB,Mike +LaysTileAt,SNCB,9,H1,S +CompanyRevenue,SNCB,250 +CompanyPaysOutFull,SNCB,250 +Payout,Stephen,25,1,10 +Payout,Mike,125,5,10 +Payout,Mark,25,1,10 +Payout,SNCB,75,3,10 +PRICE_MOVES_LOG,SNCB,90,E4,100,F4 + +EndOfOperatingRound,1.2 +ORWorthIncrease,John,1.2,160 +ORWorthIncrease,Mike,1.2,220 +ORWorthIncrease,Stephen,1.2,245 +ORWorthIncrease,Mark,1.2,208 +Has,4,0 +Has,5,0 +Has,6,0 +Has,8,90 +Has,9,100 +Has,10,295 +Has,11,51 +Has,12,180 +Has,14,46 +Has,SNCB,204 +Has,FS,158 +Has,DR,128 +Has,John,255 +Has,Mike,314 +Has,Stephen,346 +Has,Mark,443 +StartStockRound,2 +HasPriority,Mark +SELL_SHARE_LOG,Mark,10,DR,110 +START_COMPANY_LOG,Mark,KBS,100,200,2,20,KBS +MERGE_MINOR_LOG,Mark,8,KBS,90,0 +GetShareForMinor,Mark,10,KBS,8 +SharesPutInTreasury,70,KBS +PaysForTokens,KBS,100,5 +START_COMPANY_LOG,John,KPEV,100,200,2,20,KPEV +MERGE_MINOR_LOG,John,6,KPEV,0,1 +GetShareForMinor,John,10,KPEV,6 +SharesPutInTreasury,70,KPEV +PaysForTokens,KPEV,100,5 +START_COMPANY_LOG,Mike,NS,75,150,2,20,NS +MERGE_MINOR_LOG,Mike,12,NS,180,0 +GetShareForMinor,Mike,10,NS,12 +SharesPutInTreasury,70,NS +PaysForTokens,NS,100,5 +SELL_SHARE_LOG,Stephen,10,SNCB,100 +PRICE_MOVES_LOG,SNCB,100,F4,90,F5 +START_COMPANY_LOG,Stephen,SNCF,100,200,2,20,SNCF +MERGE_MINOR_LOG,Stephen,14,SNCF,46,1 +GetShareForMinor,Stephen,10,SNCF,14 +SharesPutInTreasury,70,SNCF +PaysForTokens,SNCF,100,5 +MERGE_MINOR_LOG,Mark,9,KBS,100,0 +GetShareForMinor,Mark,10,KBS,9 +ExchangesBaseToken,KBS,9,E10 +MinorCloses,9 +MERGE_MINOR_LOG,John,4,KPEV,0,0 +GetShareForMinor,John,10,KPEV,4 +ExchangesBaseToken,KPEV,4,G10 +MinorCloses,4 +BUY_SHARE_LOG,Mike,10,NS,NS,75 +MERGE_MINOR_LOG,Stephen,11,KPEV,51,0 +GetShareForMinor,Stephen,10,KPEV,11 +ExchangesBaseToken,KPEV,11,N11 +MinorCloses,11 +Floats,KPEV +BUY_SHARE_LOG,Mark,10,KBS,KBS,100 +Floats,KBS +Autopasses,John +BUY_SHARE_LOG,Mike,10,NS,NS,75 +Floats,NS +BUY_SHARE_LOG,Stephen,10,SNCF,SNCF,100 +START_COMPANY_LOG,Mark,KKÖB,82,164,2,20,KKÖB +MERGE_MINOR_LOG,Mark,10,KKÖB,295,0 +GetShareForMinor,Mark,10,KKÖB,10 +SharesPutInTreasury,70,KKÖB +PaysForTokens,KKÖB,100,5 +Autopasses,John +Autopasses,Mike +BUY_SHARE_LOG,Stephen,10,SNCF,SNCF,100 +Floats,SNCF +MERGE_MINOR_LOG,Mark,5,KKÖB,0,0 +GetShareForMinor,Mark,10,KKÖB,5 +ExchangesBaseToken,KKÖB,5,S8 +MinorCloses,5 +Autopasses,John +Autopasses,Mike +Autopasses,Stephen +BUY_SHARE_LOG,Mark,10,KKÖB,KKÖB,82 +Floats,KKÖB +Autopasses,John +Autopasses,Mike +Autopasses,Stephen +PASSES,Mark + +END_SR,2 +Has,SNCB,204 +Has,NS,380 +Has,KBS,390 +Has,KPEV,151 +Has,KKÖB,441 +Has,FS,158 +Has,SNCF,346 +Has,DR,128 +Has,John,55 +Has,Mike,14 +Has,Stephen,46 +Has,Mark,7 +START_OR,2.1 + +CompanyOperates,FS,Stephen +LaysTileAt,FS,579,M4,S +LAYS_FREE_TOKEN_ON,FS,J1 +CompanyRevenue,FS,170 +CompanyPaysOutFull,FS,170 +Payout,Stephen,85,5,10 +Payout,FS,85,5,10 +PRICE_MOVES_LOG,FS,122,G3,135,H3 +SELL_SHARES_LOG,FS,2,10,20,FS,270 +PRICE_MOVES_LOG,FS,135,H3,122,H4 + +CompanyOperates,DR,John +LaysTileAt,DR,15,I6,S +LAYS_FREE_TOKEN_ON,DR,I6 +CompanyRevenue,DR,190 +CompanyPaysOutFull,DR,190 +Payout,John,95,5,10 +Payout,DR,76,4,10 +PRICE_MOVES_LOG,DR,110,G4,122,H4 +SELL_SHARES_LOG,DR,3,10,30,DR,366 + +CompanyOperates,KBS,Mark +LaysTileAt,KBS,8,D9,NW +CompanyDoesNotPayDividend,KBS +PRICE_MOVES_LOG,KBS,100,E3,90,D3 +BuysTrain,KBS,4,IPO,300 + +CompanyOperates,KPEV,John +LaysTileAt,KPEV,578,G10,SW +LAYS_FREE_TOKEN_ON,KPEV,E10 +CompanyRevenue,KPEV,130 +CompanyPaysOutFull,KPEV,130 +Payout,Stephen,13,1,10 +Payout,John,52,4,10 +Payout,KPEV,65,5,10 +PRICE_MOVES_LOG,KPEV,100,E3,110,F3 +BuysTrain,KPEV,P,Pool,100 + +CompanyOperates,SNCF,Stephen +LaysTileAt,SNCF,144,K6,S +LAYS_FREE_TOKEN_ON,SNCF,I6 +CompanyRevenue,SNCF,150 +CompanyPaysOutFull,SNCF,150 +Payout,Stephen,75,5,10 +Payout,SNCF,75,5,10 +PRICE_MOVES_LOG,SNCF,100,E3,110,F3 +BuysTrain,SNCF,P,Pool,100 + +CompanyOperates,SNCB,Mike +LaysTileAt,SNCB,576,H3,NE +CompanyRevenue,SNCB,260 +CompanyPaysOutFull,SNCB,260 +Payout,Mark,26,1,10 +Payout,Mike,130,5,10 +Payout,SNCB,78,3,10 +PRICE_MOVES_LOG,SNCB,90,F5,100,F4 +BUY_SHARE_LOG,SNCB,10,SNCB,Pool,100 + +CompanyOperates,KKÖB,Mark +LaysTileAt,KKÖB,577,S8,NE +CompanyDoesNotPayDividend,KKÖB +PRICE_MOVES_LOG,KKÖB,82,D4,75,C4 +BuysTrain,KKÖB,4,IPO,300 + +CompanyOperates,NS,Mike +LaysTileAt,NS,58,C6,SE +CompanyDoesNotPayDividend,NS +PRICE_MOVES_LOG,NS,75,D5,70,C5 +BuysTrain,NS,4,IPO,300 +NewTrainAvailable,4,5 + +EndOfOperatingRound,2.1 +ORWorthIncrease,John,2.1,247 +ORWorthIncrease,Mike,2.1,155 +ORWorthIncrease,Stephen,2.1,233 +ORWorthIncrease,Mark,2.1,-49 +Has,SNCB,182 +Has,NS,80 +Has,KBS,90 +Has,KPEV,116 +Has,KKÖB,141 +Has,FS,513 +Has,SNCF,321 +Has,DR,570 +Has,John,202 +Has,Mike,144 +Has,Stephen,219 +Has,Mark,33 +START_OR,2.2 + +CompanyOperates,FS,Stephen +LaysTileAt,FS,83,K2,SW +CompanyRevenue,FS,170 +CompanyPaysOutFull,FS,170 +Payout,Stephen,85,5,10 +Payout,FS,51,3,10 +PRICE_MOVES_LOG,FS,122,H4,135,H3 +BuysTrain,FS,5,IPO,500 +FirstTrainBought,5 +StartOfPhase,5 + +CompanyOperates,DR,John +LaysTileAt,DR,584,E10,S +CompanyRevenue,DR,260 +CompanyPaysOutFull,DR,260 +Payout,John,130,5,10 +Payout,DR,26,1,10 +PRICE_MOVES_LOG,DR,122,H4,135,H3 + +CompanyOperates,KPEV,John +LaysTileAt,KPEV,578,L7,NW +LAYS_FREE_TOKEN_ON,KPEV,K10 +CompanyRevenue,KPEV,240 +CompanyPaysOutFull,KPEV,240 +Payout,Stephen,24,1,10 +Payout,John,96,4,10 +Payout,KPEV,120,5,10 +PRICE_MOVES_LOG,KPEV,110,F3,122,G3 + +CompanyOperates,SNCF,Stephen +LaysTileAt,SNCF,582,Q2,S +LAYS_FREE_TOKEN_ON,SNCF,Q2 +CompanyRevenue,SNCF,300 +CompanySplits,SNCF,300 +RECEIVES,SNCF,150 +Payout,Stephen,75,5,10 +Payout,SNCF,75,5,10 +PRICE_MOVES_LOG,SNCF,110,F3,122,G3 +BuysTrain,SNCF,5,IPO,500 +CompanyDiscardsTrain,SNCF,P,Pool + +CompanyOperates,SNCB,Mike +LaysTileAt,SNCB,582,H3,NE +CompanyRevenue,SNCB,300 +CompanyPaysOutFull,SNCB,300 +Payout,Mike,150,5,10 +Payout,Mark,30,1,10 +Payout,SNCB,120,4,10 +PRICE_MOVES_LOG,SNCB,100,F4,110,G4 +SELL_SHARES_LOG,SNCB,4,10,40,SNCB,440 + +CompanyOperates,KBS,Mark +LaysTileAt,KBS,9,C8,NW +CompanyRevenue,KBS,260 +CompanyPaysOutFull,KBS,260 +Payout,Mark,130,5,10 +Payout,KBS,130,5,10 +PRICE_MOVES_LOG,KBS,90,D3,100,E3 + +CompanyOperates,KKÖB,Mark +LaysTileAt,KKÖB,15,R9,NE +CompanyRevenue,KKÖB,170 +CompanyPaysOutFull,KKÖB,170 +Payout,Mark,85,5,10 +Payout,KKÖB,85,5,10 +PRICE_MOVES_LOG,KKÖB,75,C4,82,D4 + +CompanyOperates,NS,Mike +LaysTileAt,NS,583,J1,S +LAYS_FREE_TOKEN_ON,NS,H3 +CompanyRevenue,NS,270 +CompanyPaysOutFull,NS,270 +Payout,Mike,135,5,10 +Payout,NS,135,5,10 +PRICE_MOVES_LOG,NS,70,C5,75,D5 +BuysTrain,NS,3,SNCB,1 + +EndOfOperatingRound,2.2 +ORWorthIncrease,John,2.2,339 +ORWorthIncrease,Mike,2.2,360 +ORWorthIncrease,Stephen,2.2,321 +ORWorthIncrease,Mark,2.2,340 +Has,SNCB,743 +Has,NS,214 +Has,KBS,220 +Has,KPEV,236 +Has,KKÖB,226 +Has,FS,64 +Has,SNCF,46 +Has,DR,596 +Has,John,428 +Has,Mike,429 +Has,Stephen,403 +Has,Mark,278 +StartStockRound,3 +HasPriority,John +BUY_SHARE_LOG,John,10,KPEV,KPEV,122 +BUY_SHARE_LOG,Mike,10,FS,Pool,135 +BUY_SHARE_LOG,Stephen,10,SNCF,SNCF,122 +BUY_SHARE_LOG,Mark,10,SNCF,SNCF,122 +BUY_SHARE_LOG,John,10,KPEV,KPEV,122 +BUY_SHARE_LOG,Mike,10,FS,Pool,135 +BUY_SHARE_LOG,Stephen,10,FS,FS,135 +BUY_SHARE_LOG,Mark,10,SNCF,SNCF,122 +BUY_SHARE_LOG,John,10,DR,DR,135 +BUY_SHARE_LOG,Mike,10,FS,FS,135 +BUY_SHARE_LOG,Stephen,10,KPEV,KPEV,122 +PASSES,Mark +PASSES,John +PASSES,Mike +PASSES,Stephen + +END_SR,3 +Has,SNCB,743 +Has,NS,214 +Has,KBS,220 +Has,KPEV,602 +Has,KKÖB,226 +Has,FS,334 +Has,SNCF,412 +Has,DR,731 +Has,John,49 +Has,Mike,24 +Has,Stephen,24 +Has,Mark,34 +START_OR,3.1 + +CompanyOperates,FS,Stephen +LaysTileAt,FS,582,M4,NE +LAYS_FREE_TOKEN_ON,FS,M4 +CompanyRevenue,FS,320 +CompanyPaysOutFull,FS,320 +Payout,Stephen,192,6,10 +Payout,Mike,96,3,10 +Payout,FS,32,1,10 +PRICE_MOVES_LOG,FS,135,H3,150,I3 + +CompanyOperates,DR,John +LaysTileAt,DR,8,G6,NE +CompanyRevenue,DR,280 +CompanyPaysOutFull,DR,280 +Payout,John,168,6,10 +PRICE_MOVES_LOG,DR,135,H3,150,I3 +BuysTrain,DR,5,IPO,500 +NewTrainAvailable,5,6 +CompanyDiscardsTrain,DR,P,Pool + +CompanyOperates,KPEV,John +LaysTileAt,KPEV,581,N11,SW +CompanyRevenue,KPEV,240 +CompanyPaysOutFull,KPEV,240 +Payout,Stephen,48,2,10 +Payout,John,144,6,10 +Payout,KPEV,48,2,10 +PRICE_MOVES_LOG,KPEV,122,G3,135,H3 +BuysTrain,KPEV,6,IPO,600 +FirstTrainBought,6 +StartOfPhase,6 +TrainsRusted,3 +CompanyDiscardsTrain,KPEV,P,Pool + +CompanyOperates,SNCF,Stephen +LaysTileAt,SNCF,83,I2,SE +LAYS_FREE_TOKEN_ON,SNCF,J1 +CompanyRevenue,SNCF,470 +CompanyPaysOutFull,SNCF,470 +Payout,Stephen,282,6,10 +Payout,Mark,94,2,10 +Payout,SNCF,94,2,10 +PRICE_MOVES_LOG,SNCF,122,G3,135,H3 + +CompanyOperates,SNCB,Mike +LaysTileAt,SNCB,578,C4,SE +CompanyDoesNotPayDividend,SNCB +PRICE_MOVES_LOG,SNCB,110,G4,100,F4 +BuysTrain,SNCB,6,IPO,600 +NewTrainAvailable,6,8 +BuysTrain,SNCB,P,Pool,100 + +CompanyOperates,KBS,Mark +LaysTileAt,KBS,576,P13,SE +CompanyRevenue,KBS,270 +CompanyPaysOutFull,KBS,270 +Payout,Mark,135,5,10 +Payout,KBS,135,5,10 +PRICE_MOVES_LOG,KBS,100,E3,110,F3 +SELL_SHARES_LOG,KBS,5,10,50,KBS,550 +PRICE_MOVES_LOG,KBS,110,F3,90,F5 + +CompanyOperates,KKÖB,Mark +LaysTileAt,KKÖB,584,N11,S +DuplicateTokenRemoved,KPEV,N11 +LAYS_FREE_TOKEN_ON,KKÖB,N11 +CompanyRevenue,KKÖB,190 +CompanyPaysOutFull,KKÖB,190 +Payout,Mark,95,5,10 +Payout,KKÖB,95,5,10 +PRICE_MOVES_LOG,KKÖB,82,D4,90,E4 +SELL_SHARES_LOG,KKÖB,5,10,50,KKÖB,450 +PRICE_MOVES_LOG,KKÖB,90,E4,75,E6 + +CompanyOperates,NS,Mike +LaysTileAt,NS,141,C6,NW +LAYS_FREE_TOKEN_ON,NS,J1 +CompanyRevenue,NS,260 +CompanyPaysOutFull,NS,260 +Payout,Mike,130,5,10 +Payout,NS,130,5,10 +PRICE_MOVES_LOG,NS,75,D5,82,E5 + +EndOfOperatingRound,3.1 +ORWorthIncrease,John,3.1,480 +ORWorthIncrease,Mike,3.1,256 +ORWorthIncrease,Stephen,3.1,716 +ORWorthIncrease,Mark,3.1,255 +Has,SNCB,43 +Has,NS,344 +Has,KBS,905 +Has,KPEV,50 +Has,KKÖB,771 +Has,FS,366 +Has,SNCF,506 +Has,DR,231 +Has,John,361 +Has,Mike,250 +Has,Stephen,546 +Has,Mark,358 +START_OR,3.2 + +CompanyOperates,FS,Stephen +LaysTileAt,FS,582,L7,S +LAYS_FREE_TOKEN_ON,FS,L7 +CompanyRevenue,FS,360 +CompanyPaysOutFull,FS,360 +Payout,Stephen,216,6,10 +Payout,Mike,108,3,10 +Payout,FS,36,1,10 +PRICE_MOVES_LOG,FS,150,I3,165,J3 +BuysTrain,FS,4,SNCF,225 + +CompanyOperates,DR,John +LaysTileAt,DR,58,F7,SW +CompanyRevenue,DR,300 +CompanyPaysOutFull,DR,300 +Payout,John,180,6,10 +PRICE_MOVES_LOG,DR,150,I3,165,J3 +BuysTrain,DR,P,Pool,100 + +CompanyOperates,KPEV,John +LaysTileAt,KPEV,582,P13,SE +LAYS_FREE_TOKEN_ON,KPEV,P13 +CompanyRevenue,KPEV,330 +CompanyPaysOutFull,KPEV,330 +Payout,Stephen,66,2,10 +Payout,John,198,6,10 +Payout,KPEV,66,2,10 +PRICE_MOVES_LOG,KPEV,135,H3,150,I3 +BuysTrain,KPEV,P,Pool,100 +SELL_SHARES_LOG,KPEV,1,10,10,KPEV,150 + +CompanyOperates,SNCF,Stephen +LaysTileAt,SNCF,546,I2,NE +CompanyRevenue,SNCF,350 +CompanyPaysOutFull,SNCF,350 +Payout,Stephen,210,6,10 +Payout,Mark,70,2,10 +Payout,SNCF,70,2,10 +PRICE_MOVES_LOG,SNCF,135,H3,150,I3 +BuysTrain,SNCF,8,IPO,800 +FirstTrainBought,8 +StartOfPhase,8 +TrainsRusted,4 + +CompanyOperates,SNCB,Mike +LaysTileAt,SNCB,582,C4,N +LAYS_FREE_TOKEN_ON,SNCB,C4 +CompanyRevenue,SNCB,510 +CompanyPaysOutFull,SNCB,510 +Payout,Mike,255,5,10 +Payout,Mark,51,1,10 +PRICE_MOVES_LOG,SNCB,100,F4,110,G4 + +CompanyOperates,KBS,Mark +CompanyDoesNotPayDividend,KBS +PRICE_MOVES_LOG,KBS,90,F5,82,E5 +BuysTrain,KBS,8,IPO,800 +BuysTrain,KBS,P,Pool,100 + +CompanyOperates,NS,Mike +LaysTileAt,NS,83,H1,NE +CompanyDoesNotPayDividend,NS +PRICE_MOVES_LOG,NS,82,E5,75,D5 +PresidentAddsCash,NS,Mike,456 +BuysTrain,NS,8,IPO,800 + +CompanyOperates,KKÖB,Mark +LaysTileAt,KKÖB,576,R5,NW +CompanyDoesNotPayDividend,KKÖB +PRICE_MOVES_LOG,KKÖB,75,E6,70,D6 +PresidentAddsCash,KKÖB,Mark,29 +BuysTrain,KKÖB,8,IPO,800 + +EndOfOperatingRound,3.2 +ORWorthIncrease,John,3.2,558 +ORWorthIncrease,Mike,3.2,-33 +ORWorthIncrease,Stephen,3.2,702 +ORWorthIncrease,Mark,3.2,67 +Has,SNCB,43 +Has,NS,0 +Has,KBS,5 +Has,KPEV,166 +Has,KKÖB,0 +Has,FS,177 +Has,SNCF,1 +Has,DR,131 +Has,John,739 +Has,Mike,157 +Has,Stephen,1038 +Has,Mark,450 +StartStockRound,4 +HasPriority,Mark +BUY_SHARE_LOG,Mark,10,SNCF,SNCF,150 +BUY_SHARE_LOG,John,10,FS,FS,165 +SELL_SHARES_LOG,Mike,3,10,30,FS,495 +BUY_SHARE_LOG,Mike,10,SNCF,SNCF,150 +BUY_SHARE_LOG,Stephen,10,KPEV,KPEV,150 +BUY_SHARE_LOG,Mark,10,SNCB,Pool,110 +BUY_SHARE_LOG,John,10,FS,Pool,165 +BUY_SHARE_LOG,Mike,10,SNCB,Pool,110 +BUY_SHARE_LOG,Stephen,10,SNCB,Pool,110 +BUY_SHARE_LOG,Mark,10,KBS,Pool,82 +BUY_SHARE_LOG,John,10,FS,Pool,165 +BUY_SHARE_LOG,Mike,10,KPEV,Pool,150 +BUY_SHARE_LOG,Stephen,10,KBS,Pool,82 +BUY_SHARE_LOG,Mark,10,KKÖB,Pool,70 +BUY_SHARE_LOG,John,10,KBS,Pool,82 +BUY_SHARE_LOG,Mike,10,DR,Pool,165 +BUY_SHARE_LOG,Stephen,10,DR,Pool,165 +Autopasses,Mark +BUY_SHARE_LOG,John,10,KBS,Pool,82 +BUY_SHARE_LOG,Mike,10,NS,NS,75 +Autopasses,Stephen +Autopasses,Mark +BUY_SHARE_LOG,John,10,KKÖB,Pool,70 +PASSES,Mike +Autopasses,Stephen +Autopasses,Mark +PASSES,John + +END_SR,4 +SoldOut,KPEV +PRICE_MOVES_LOG,KPEV,150,I3,165,I2 +SoldOut,SNCF +PRICE_MOVES_LOG,SNCF,150,I3,165,I2 +Has,SNCB,43 +Has,NS,75 +Has,KBS,5 +Has,KPEV,316 +Has,KKÖB,0 +Has,FS,342 +Has,SNCF,301 +Has,DR,131 +Has,John,10 +Has,Mike,2 +Has,Stephen,531 +Has,Mark,38 +START_OR,4.1 + +CompanyOperates,FS,Stephen +LaysTileAt,FS,142,M2,SW +CompanyRevenue,FS,360 +CompanyPaysOutFull,FS,360 +Payout,Stephen,216,6,10 +Payout,John,108,3,10 +PRICE_MOVES_LOG,FS,165,J3,180,K3 +BuysTrain,FS,P,Pool,100 +BUY_SHARE_LOG,FS,10,FS,Pool,180 + +CompanyOperates,DR,John +LaysTileAt,DR,8,D7,S +CompanyRevenue,DR,380 +CompanyPaysOutFull,DR,380 +Payout,Stephen,38,1,10 +Payout,John,228,6,10 +Payout,Mike,38,1,10 +PRICE_MOVES_LOG,DR,165,J3,180,K3 + +CompanyOperates,KPEV,John +LaysTileAtFor,KPEV,4,O12,NW,60 +CompanyRevenue,KPEV,400 +CompanyPaysOutFull,KPEV,400 +Payout,Stephen,120,3,10 +Payout,John,240,6,10 +Payout,Mike,40,1,10 +PRICE_MOVES_LOG,KPEV,165,I2,180,J2 + +CompanyOperates,SNCF,Stephen +LaysTileAt,SNCF,145,M2,N +CompanyRevenue,SNCF,550 +CompanyPaysOutFull,SNCF,550 +Payout,Stephen,330,6,10 +Payout,Mike,55,1,10 +Payout,Mark,165,3,10 +PRICE_MOVES_LOG,SNCF,165,I2,180,J2 + +CompanyOperates,SNCB,Mike +LaysTileAt,SNCB,80,C10,SW +CompanyRevenue,SNCB,510 +CompanyPaysOutFull,SNCB,510 +Payout,Stephen,51,1,10 +Payout,Mark,102,2,10 +Payout,Mike,306,6,10 +PRICE_MOVES_LOG,SNCB,110,G4,122,H4 + +CompanyOperates,KBS,Mark +LaysTileAt,KBS,582,S8,NE +LAYS_FREE_TOKEN_ON,KBS,N11 +CompanyRevenue,KBS,540 +CompanyPaysOutFull,KBS,540 +Payout,Stephen,54,1,10 +Payout,John,108,2,10 +Payout,Mark,324,6,10 +PRICE_MOVES_LOG,KBS,82,E5,90,F5 + +CompanyOperates,NS,Mike +LaysTileAt,NS,142,D11,S +CompanyRevenue,NS,350 +CompanyPaysOutFull,NS,350 +Payout,Mike,210,6,10 +Payout,NS,140,4,10 +PRICE_MOVES_LOG,NS,75,D5,82,E5 + +CompanyOperates,KKÖB,Mark +LaysTileAt,KKÖB,14,K10,NW +LAYS_FREE_TOKEN_ON,KKÖB,K10 +CompanyRevenue,KKÖB,320 +CompanyPaysOutFull,KKÖB,320 +Payout,John,32,1,10 +Payout,Mark,192,6,10 +PRICE_MOVES_LOG,KKÖB,70,D6,75,E6 + +EndOfOperatingRound,4.1 +ORWorthIncrease,John,4.1,962 +ORWorthIncrease,Mike,4.1,808 +ORWorthIncrease,Stephen,4.1,1069 +ORWorthIncrease,Mark,4.1,930 +Has,SNCB,43 +Has,NS,215 +Has,KBS,5 +Has,KPEV,256 +Has,KKÖB,0 +Has,FS,62 +Has,SNCF,301 +Has,DR,131 +Has,John,726 +Has,Mike,651 +Has,Stephen,1340 +Has,Mark,821 +START_OR,4.2 + +CompanyOperates,FS,Stephen +LaysTileAt,FS,141,G8,SE +CompanyRevenue,FS,450 +CompanyPaysOutFull,FS,450 +Payout,Stephen,270,6,10 +Payout,John,135,3,10 +Payout,FS,45,1,10 +PRICE_MOVES_LOG,FS,180,K3,200,K2 + +CompanyOperates,DR,John +LaysTileAt,DR,81,F13,SW +CompanyRevenue,DR,440 +CompanyPaysOutFull,DR,440 +Payout,Stephen,44,1,10 +Payout,John,264,6,10 +Payout,Mike,44,1,10 +PRICE_MOVES_LOG,DR,180,K3,200,K2 + +CompanyOperates,KPEV,John +LaysTileAt,KPEV,141,H9,SE +CompanyRevenue,KPEV,400 +CompanyPaysOutFull,KPEV,400 +Payout,Stephen,120,3,10 +Payout,John,240,6,10 +Payout,Mike,40,1,10 +PRICE_MOVES_LOG,KPEV,180,J2,200,K2 + +CompanyOperates,SNCF,Stephen +LaysTileAt,SNCF,144,F7,S +CompanyRevenue,SNCF,600 +CompanyPaysOutFull,SNCF,600 +Payout,Stephen,360,6,10 +Payout,Mark,180,3,10 +Payout,Mike,60,1,10 +PRICE_MOVES_LOG,SNCF,180,J2,200,K2 + +CompanyOperates,SNCB,Mike +CompanyRevenue,SNCB,560 +CompanyPaysOutFull,SNCB,560 +Payout,Stephen,56,1,10 +Payout,Mark,112,2,10 +Payout,Mike,336,6,10 +PRICE_MOVES_LOG,SNCB,122,H4,135,H3 + +CompanyOperates,KBS,Mark +LaysTileAt,KBS,82,F9,NW +LAYS_FREE_TOKEN_ON,KBS,S8 +CompanyRevenue,KBS,600 +CompanyPaysOutFull,KBS,600 +Payout,Stephen,60,1,10 +Payout,John,120,2,10 +Payout,Mark,360,6,10 +PRICE_MOVES_LOG,KBS,90,F5,100,F4 + +CompanyOperates,NS,Mike +LaysTileAt,NS,8,L1,N +CompanyRevenue,NS,410 +CompanyPaysOutFull,NS,410 +Payout,Mike,246,6,10 +Payout,NS,164,4,10 +PRICE_MOVES_LOG,NS,82,E5,90,F5 + +CompanyOperates,KKÖB,Mark +LaysTileAt,KKÖB,582,G10,SE +LAYS_FREE_TOKEN_ON,KKÖB,G10 +CompanyRevenue,KKÖB,540 +CompanyPaysOutFull,KKÖB,540 +Payout,John,54,1,10 +Payout,Mark,324,6,10 +PRICE_MOVES_LOG,KKÖB,75,E6,82,E5 + +EndOfOperatingRound,4.2 +ORWorthIncrease,John,4.2,1140 +ORWorthIncrease,Mike,4.2,912 +ORWorthIncrease,Stephen,4.2,1253 +ORWorthIncrease,Mark,4.2,1164 +Has,SNCB,43 +Has,NS,379 +Has,KBS,5 +Has,KPEV,256 +Has,KKÖB,0 +Has,FS,107 +Has,SNCF,301 +Has,DR,131 +Has,John,1539 +Has,Mike,1377 +Has,Stephen,2250 +Has,Mark,1797 +StartStockRound,5 +HasPriority,Mike +BUY_SHARE_LOG,Mike,10,KBS,Pool,100 +Autopasses,Stephen +BUY_SHARE_LOG,Mark,10,SNCB,Pool,135 +SELL_SHARE_LOG,John,10,KKÖB,82 +PRICE_MOVES_LOG,KKÖB,82,E5,75,E6 +BUY_SHARE_LOG,John,10,FS,FS,200 +BUY_SHARE_LOG,Mike,10,DR,Pool,200 +Autopasses,Stephen +Autopasses,Mark +Autopasses,John +BUY_SHARE_LOG,Mike,10,DR,Pool,200 +Autopasses,Stephen +Autopasses,Mark +Autopasses,John +SELL_SHARE_LOG,Mike,10,NS,90 +BUY_SHARE_LOG,Mike,10,KKÖB,Pool,75 +Autopasses,Stephen +Autopasses,Mark +Autopasses,John +SELL_SHARE_LOG,Mike,10,NS,90 +BUY_SHARE_LOG,Mike,10,KKÖB,Pool,75 +Autopasses,Stephen +Autopasses,Mark +Autopasses,John +SELL_SHARE_LOG,Mike,10,NS,90 +BUY_SHARE_LOG,Mike,10,KKÖB,Pool,75 +Autopasses,Stephen +Autopasses,Mark +Autopasses,John +SELL_SHARE_LOG,Mike,10,NS,90 +BUY_SHARE_LOG,Mike,10,KKÖB,Pool,75 +Autopasses,Stephen +Autopasses,Mark +Autopasses,John +PASSES,Mike + +END_SR,5 +SoldOut,FS +PRICE_MOVES_LOG,FS,200,K2,220,K1 +SoldOut,DR +PRICE_MOVES_LOG,DR,200,K2,220,K1 +SoldOut,KPEV +PRICE_MOVES_LOG,KPEV,200,K2,220,K1 +SoldOut,SNCF +PRICE_MOVES_LOG,SNCF,200,K2,220,K1 +SoldOut,SNCB +PRICE_MOVES_LOG,SNCB,135,H3,150,H2 +SoldOut,KBS +PRICE_MOVES_LOG,KBS,100,F4,110,F3 +SoldOut,KKÖB +PRICE_MOVES_LOG,KKÖB,75,E6,82,E5 +Has,SNCB,43 +Has,NS,379 +Has,KBS,5 +Has,KPEV,256 +Has,KKÖB,0 +Has,FS,307 +Has,SNCF,301 +Has,DR,131 +Has,John,1421 +Has,Mike,937 +Has,Stephen,2250 +Has,Mark,1662 +START_OR,5.1 + +CompanyOperates,FS,Stephen +LaysTileAt,FS,8,N3,NW +CompanyRevenue,FS,570 +CompanyPaysOutFull,FS,570 +Payout,Stephen,342,6,10 +Payout,John,228,4,10 +PRICE_MOVES_LOG,FS,220,K1,245,L1 + +CompanyOperates,DR,John +LaysTileAt,DR,145,G8,NW +CompanyRevenue,DR,450 +CompanyPaysOutFull,DR,450 +Payout,Stephen,45,1,10 +Payout,John,270,6,10 +Payout,Mike,135,3,10 +PRICE_MOVES_LOG,DR,220,K1,245,L1 + +CompanyOperates,KPEV,John +LaysTileAt,KPEV,611,K10,S +CompanyRevenue,KPEV,550 +CompanyPaysOutFull,KPEV,550 +Payout,Stephen,165,3,10 +Payout,John,330,6,10 +Payout,Mike,55,1,10 +PRICE_MOVES_LOG,KPEV,220,K1,245,L1 + +CompanyOperates,SNCF,Stephen +LaysTileAt,SNCF,544,K2,NW +CompanyRevenue,SNCF,620 +CompanyPaysOutFull,SNCF,620 +Payout,Stephen,372,6,10 +Payout,Mark,186,3,10 +Payout,Mike,62,1,10 +PRICE_MOVES_LOG,SNCF,220,K1,245,L1 + +CompanyOperates,SNCB,Mike +LaysTileAt,SNCB,80,N3,NE +CompanyRevenue,SNCB,560 +CompanyPaysOutFull,SNCB,560 +Payout,Stephen,56,1,10 +Payout,Mark,168,3,10 +Payout,Mike,336,6,10 +PRICE_MOVES_LOG,SNCB,150,H2,165,I2 + +CompanyOperates,KBS,Mark +LaysTileAt,KBS,513,K10,S +LAYS_FREE_TOKEN_ON,KBS,K10 +CompanyRevenue,KBS,670 +CompanyPaysOutFull,KBS,670 +Payout,Stephen,67,1,10 +Payout,John,134,2,10 +Payout,Mark,402,6,10 +Payout,Mike,67,1,10 +PRICE_MOVES_LOG,KBS,110,F3,122,G3 + +CompanyOperates,NS,Mike +LaysTileAtFor,NS,9,J3,S,60 +CompanyRevenue,NS,460 +CompanyPaysOutFull,NS,460 +Payout,Mike,92,2,10 +Payout,NS,184,4,10 +PRICE_MOVES_LOG,NS,90,F5,100,F4 + +CompanyOperates,KKÖB,Mark +LaysTileAt,KKÖB,143,U6,S +CompanyRevenue,KKÖB,620 +CompanyPaysOutFull,KKÖB,620 +Payout,Mark,372,6,10 +Payout,Mike,248,4,10 +PRICE_MOVES_LOG,KKÖB,82,E5,90,F5 + +EndOfOperatingRound,5.1 +ORWorthIncrease,John,5.1,1386 +ORWorthIncrease,Mike,5.1,1274 +ORWorthIncrease,Stephen,5.1,1474 +ORWorthIncrease,Mark,5.1,1368 +Has,SNCB,43 +Has,NS,503 +Has,KBS,5 +Has,KPEV,256 +Has,KKÖB,0 +Has,FS,307 +Has,SNCF,301 +Has,DR,131 +Has,John,2383 +Has,Mike,1932 +Has,Stephen,3297 +Has,Mark,2790 +START_OR,5.2 + +CompanyOperates,FS,Stephen +LaysTileAt,FS,147,K6,NW +CompanyRevenue,FS,570 +CompanyPaysOutFull,FS,570 +BankIsBrokenReportText +Payout,Stephen,342,6,10 +Payout,John,228,4,10 +PRICE_MOVES_LOG,FS,245,L1,270,M1 + +CompanyOperates,DR,John +LaysTileAt,DR,146,D11,N +CompanyRevenue,DR,470 +CompanyPaysOutFull,DR,470 +Payout,Stephen,47,1,10 +Payout,John,282,6,10 +Payout,Mike,141,3,10 +PRICE_MOVES_LOG,DR,245,L1,270,M1 + +CompanyOperates,KPEV,John +LaysTileAt,KPEV,142,E12,S +CompanyRevenue,KPEV,580 +CompanyPaysOutFull,KPEV,580 +Payout,Stephen,174,3,10 +Payout,John,348,6,10 +Payout,Mike,58,1,10 +PRICE_MOVES_LOG,KPEV,245,L1,270,M1 + +CompanyOperates,SNCF,Stephen +LaysTileAt,SNCF,8,L3,N +CompanyRevenue,SNCF,800 +CompanyPaysOutFull,SNCF,800 +Payout,Stephen,480,6,10 +Payout,Mark,240,3,10 +Payout,Mike,80,1,10 +PRICE_MOVES_LOG,SNCF,245,L1,270,M1 + +CompanyOperates,SNCB,Mike +LaysTileAt,SNCB,83,L3,NE +CompanyRevenue,SNCB,590 +CompanyPaysOutFull,SNCB,590 +Payout,Stephen,59,1,10 +Payout,Mark,177,3,10 +Payout,Mike,354,6,10 +PRICE_MOVES_LOG,SNCB,165,I2,180,J2 + +CompanyOperates,KBS,Mark +LaysTileAt,KBS,611,R9,NE +CompanyRevenue,KBS,730 +CompanyPaysOutFull,KBS,730 +Payout,Stephen,73,1,10 +Payout,John,146,2,10 +Payout,Mark,438,6,10 +Payout,Mike,73,1,10 +PRICE_MOVES_LOG,KBS,122,G3,135,H3 + +CompanyOperates,NS,Mike +CompanyRevenue,NS,500 +CompanyPaysOutFull,NS,500 +Payout,Mike,100,2,10 +Payout,NS,200,4,10 +PRICE_MOVES_LOG,NS,100,F4,110,G4 + +CompanyOperates,KKÖB,Mark +LaysTileAt,KKÖB,513,R9,S +CompanyRevenue,KKÖB,640 +CompanyPaysOutFull,KKÖB,640 +Payout,Mark,384,6,10 +Payout,Mike,256,4,10 +PRICE_MOVES_LOG,KKÖB,90,F5,100,F4 + +EndOfOperatingRound,5.2 +ORWorthIncrease,John,5.2,1430 +ORWorthIncrease,Mike,5.2,1350 +ORWorthIncrease,Stephen,5.2,1603 +ORWorthIncrease,Mark,5.2,1497 +Has,SNCB,43 +Has,NS,703 +Has,KBS,5 +Has,KPEV,256 +Has,KKÖB,0 +Has,FS,307 +Has,SNCF,301 +Has,DR,131 +Has,John,3387 +Has,Mike,2994 +Has,Stephen,4472 +Has,Mark,4029 +GameOver +EoGWinnerStephen! +EoGFinalRanking : +1. 9107 Stephen +2. 7977 John +3. 6789 Mark +4. 6179 Mike diff --git a/src/test/resources/data/real/18EUR42.rails b/src/test/resources/data/real/18EUR42.rails new file mode 100644 index 000000000..0bfd81946 Binary files /dev/null and b/src/test/resources/data/real/18EUR42.rails differ diff --git a/src/test/resources/data/real/18EUR42.report b/src/test/resources/data/real/18EUR42.report new file mode 100644 index 000000000..ead150a26 --- /dev/null +++ b/src/test/resources/data/real/18EUR42.report @@ -0,0 +1,1781 @@ +GameIs,18EU +PlayerIs,1,John +PlayerIs,2,Mike +PlayerIs,3,Mark +PlayerIs,4,Jean +PlayerCash,350 +BankHas,10600 +StartOfPhase,2 +BankSizeIs,10600 +StartOfInitialRound,1 +HasPriority,John + +SelectForAuctioning,John,14 +DeclinedToBid,Mike +DeclinedToBid,Mark +DeclinedToBid,Jean +ITEM_PRICE_REDUCED,14,90 +BuysItemFor,John,14,90 +Floats,14 + +SelectForAuctioning,Mike,7 +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +ITEM_PRICE_REDUCED,7,90 +BuysItemFor,Mike,7,90 +Floats,7 + +SelectForAuctioning,Mark,5 +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,5,90 +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,5,80 +BuysItemFor,Mark,5,80 +Floats,5 + +SelectForAuctioning,Jean,1 +DeclinedToBid,John +DeclinedToBid,Mike +BID_ITEM,Mark,100,1 +BID_ITEM,Jean,105,1 +PASSES,John +PASSES,Mike +BID_ITEM,Mark,110,1 +PASSES,Jean +BuysItemFor,Mark,1,110 +Floats,1 + +SelectForAuctioning,John,13 +BID_ITEM,Mike,100,13 +PASSES,Mark +BID_ITEM,Jean,105,13 +BID_ITEM,John,110,13 +PASSES,Mike +BID_ITEM,Jean,115,13 +BID_ITEM,John,120,13 +PASSES,Jean +BuysItemFor,John,13,120 +Floats,13 + +SelectForAuctioning,Mike,6 +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +ITEM_PRICE_REDUCED,6,90 +DeclinedToBid,Mike +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +ITEM_PRICE_REDUCED,6,80 +DeclinedToBid,Mike +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +ITEM_PRICE_REDUCED,6,70 +BuysItemFor,Mike,6,70 +Floats,6 + +SelectForAuctioning,Mark,10 +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,10,90 +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,10,80 +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,10,70 +BuysItemFor,Mark,10,70 +Floats,10 + +SelectForAuctioning,Jean,12 +DeclinedToBid,John +BID_ITEM,Mike,100,12 +PASSES,Mark +BID_ITEM,Jean,105,12 +PASSES,John +PASSES,Mike +BuysItemFor,Jean,12,105 +Floats,12 + +SelectForAuctioning,John,2 +DeclinedToBid,Mike +DeclinedToBid,Mark +BID_ITEM,Jean,100,2 +PASSES,John +PASSES,Mike +PASSES,Mark +BuysItemFor,Jean,2,100 +Floats,2 + +SelectForAuctioning,Mike,8 +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +ITEM_PRICE_REDUCED,8,90 +DeclinedToBid,Mike +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +ITEM_PRICE_REDUCED,8,80 +BuysItemFor,Mike,8,80 +Floats,8 + +SelectForAuctioning,Mark,11 +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,11,90 +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,11,80 +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,11,70 +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,11,60 +DeclinedToBid,Mark +BuysItemFor,Jean,11,60 +Floats,11 + +SelectForAuctioning,Jean,15 +DeclinedToBid,John +DeclinedToBid,Mike +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,15,90 +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,15,80 +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,15,70 +BuysItemFor,Jean,15,70 +Floats,15 + +SelectForAuctioning,John,3 +DeclinedToBid,Mike +DeclinedToBid,Mark +DeclinedToBid,Jean +ITEM_PRICE_REDUCED,3,90 +BuysItemFor,John,3,90 +Floats,3 + +SelectForAuctioning,Mike,4 +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +ITEM_PRICE_REDUCED,4,90 +DeclinedToBid,Mike +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +ITEM_PRICE_REDUCED,4,80 +DeclinedToBid,Mike +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +ITEM_PRICE_REDUCED,4,70 +DeclinedToBid,Mike +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +ITEM_PRICE_REDUCED,4,60 +DeclinedToBid,Mike +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +ITEM_PRICE_REDUCED,4,50 +BuysItemFor,Mike,4,50 +Floats,4 + +SelectForAuctioning,Mark,9 +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,9,90 +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,9,80 +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,9,70 +DeclinedToBid,Mark +DeclinedToBid,Jean +DeclinedToBid,John +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,9,60 +BuysItemFor,Mark,9,60 +NewTrainAvailable,2,3 +Floats,9 +Has,1,0 +Has,2,0 +Has,3,0 +Has,4,0 +Has,5,0 +Has,6,0 +Has,7,0 +Has,8,0 +Has,9,0 +Has,10,0 +Has,11,0 +Has,12,0 +Has,13,0 +Has,14,0 +Has,15,0 +Has,John,50 +Has,Mike,60 +Has,Mark,30 +Has,Jean,15 +START_OR,0.1 + +CompanyOperates,1,Mark +LaysTileAt,1,8,I2,SW +LaysTileAt,1,58,G2,S +CompanyRevenue,1,90 +CompanySplits,1,90 +RECEIVES,1,45 +Payout,Mark,45,1,100 + +CompanyOperates,2,Jean +LaysTileAt,2,201,H3,N +LaysTileAt,2,58,F3,NE +CompanyRevenue,2,40 +CompanySplits,2,40 +RECEIVES,2,20 +Payout,Jean,20,1,100 + +CompanyOperates,3,John +LaysTileAt,3,8,K2,S +LaysTileAt,3,3,M2,N +CompanyRevenue,3,50 +CompanySplits,3,50 +RECEIVES,3,25 +Payout,John,25,1,100 + +CompanyOperates,4,Mike +LaysTileAt,4,202,G10,NE +LaysTileAt,4,58,H9,NW +CompanyRevenue,4,40 +CompanySplits,4,40 +RECEIVES,4,20 +Payout,Mike,20,1,100 + +CompanyOperates,5,Mark +LaysTileAt,5,201,S8,SW +LaysTileAt,5,8,U8,SW +CompanyRevenue,5,60 +CompanySplits,5,60 +RECEIVES,5,30 +Payout,Mark,30,1,100 + +CompanyOperates,6,Mike +LaysTileAt,6,3,L11,SE +LaysTileAt,6,9,M12,NW +CompanyRevenue,6,40 +CompanySplits,6,40 +RECEIVES,6,20 +Payout,Mike,20,1,100 + +CompanyOperates,7,Mike +LaysTileAt,7,9,F9,SW +LaysTileAt,7,3,G8,NE +CompanyRevenue,7,80 +CompanySplits,7,80 +RECEIVES,7,40 +Payout,Mike,40,1,100 + +CompanyOperates,8,Mike +LaysTileAt,8,202,P13,S +LaysTileAt,8,8,N13,S +CompanyRevenue,8,70 +CompanySplits,8,70 +RECEIVES,8,35 +Payout,Mike,35,1,100 + +CompanyOperates,9,Mark +LaysTileAt,9,58,D11,SE +LaysTileAt,9,4,E12,NW +CompanyRevenue,9,50 +CompanySplits,9,50 +RECEIVES,9,25 +Payout,Mark,25,1,100 + +CompanyOperates,10,Mark +LaysTileAt,10,201,R5,S +LaysTileAt,10,57,T5,S +CompanyRevenue,10,60 +CompanySplits,10,60 +RECEIVES,10,30 +Payout,Mark,30,1,100 + +CompanyOperates,11,Jean +LaysTileAt,11,9,Q10,SW +LaysTileAt,11,57,R9,SW +CompanyRevenue,11,50 +CompanySplits,11,50 +RECEIVES,11,25 +Payout,Jean,25,1,100 + +CompanyOperates,12,Jean +LaysTileAt,12,202,C4,NW +LaysTileAt,12,3,D3,NE +CompanyRevenue,12,40 +CompanySplits,12,40 +RECEIVES,12,20 +Payout,Jean,20,1,100 + +CompanyOperates,13,John +LaysTileAt,13,201,L7,N +LaysTileAt,13,58,K6,SE +CompanyRevenue,13,40 +CompanySplits,13,40 +RECEIVES,13,20 +Payout,John,20,1,100 + +CompanyOperates,14,John +LaysTileAt,14,202,M4,SE +LaysTileAt,14,4,L5,SW +CompanyRevenue,14,80 +CompanySplits,14,80 +RECEIVES,14,40 +Payout,John,40,1,100 + +CompanyOperates,15,Jean +LaysTileAt,15,202,Q2,SW +LaysTileAt,15,57,S2,S +CompanyRevenue,15,60 +CompanySplits,15,60 +RECEIVES,15,30 +Payout,Jean,30,1,100 + +EndOfOperatingRound,0.1 +ORWorthIncrease,John,0.1,85 +ORWorthIncrease,Mike,0.1,115 +ORWorthIncrease,Mark,0.1,130 +ORWorthIncrease,Jean,0.1,95 +Has,1,45 +Has,2,20 +Has,3,25 +Has,4,20 +Has,5,30 +Has,6,20 +Has,7,40 +Has,8,35 +Has,9,25 +Has,10,30 +Has,11,25 +Has,12,20 +Has,13,20 +Has,14,40 +Has,15,30 +Has,John,135 +Has,Mike,175 +Has,Mark,160 +Has,Jean,110 +START_OR,0.2 + +CompanyOperates,1,Mark +CompanyRevenue,1,90 +CompanySplits,1,90 +RECEIVES,1,45 +Payout,Mark,45,1,100 + +CompanyOperates,2,Jean +LaysTileAt,2,3,E4,SW +CompanyRevenue,2,90 +CompanySplits,2,90 +RECEIVES,2,45 +Payout,Jean,45,1,100 + +CompanyOperates,3,John +LaysTileAt,3,8,L3,SE +CompanyRevenue,3,80 +CompanySplits,3,80 +RECEIVES,3,40 +Payout,John,40,1,100 + +CompanyOperates,4,Mike +CompanyRevenue,4,80 +CompanySplits,4,80 +RECEIVES,4,40 +Payout,Mike,40,1,100 + +CompanyOperates,5,Mark +LaysTileAt,5,58,T7,NW +CompanyRevenue,5,70 +CompanySplits,5,70 +RECEIVES,5,35 +Payout,Mark,35,1,100 + +CompanyOperates,6,Mike +CompanyRevenue,6,70 +CompanySplits,6,70 +RECEIVES,6,35 +Payout,Mike,35,1,100 + +CompanyOperates,7,Mike +CompanyRevenue,7,80 +CompanySplits,7,80 +RECEIVES,7,40 +Payout,Mike,40,1,100 + +CompanyOperates,8,Mike +CompanyRevenue,8,70 +CompanySplits,8,70 +RECEIVES,8,35 +Payout,Mike,35,1,100 +BuysTrain,8,2,7,70 + +CompanyOperates,9,Mark +LaysTileAt,9,8,F13,NW +CompanyRevenue,9,70 +CompanySplits,9,70 +RECEIVES,9,35 +Payout,Mark,35,1,100 + +CompanyOperates,10,Mark +LaysTileAt,10,9,S6,NW +CompanyRevenue,10,70 +CompanySplits,10,70 +RECEIVES,10,35 +Payout,Mark,35,1,100 + +CompanyOperates,11,Jean +CompanyRevenue,11,50 +CompanySplits,11,50 +RECEIVES,11,25 +Payout,Jean,25,1,100 + +CompanyOperates,12,Jean +LaysTileAt,12,8,D5,NW +CompanyRevenue,12,90 +CompanySplits,12,90 +RECEIVES,12,45 +Payout,Jean,45,1,100 + +CompanyOperates,13,John +LaysTileAt,13,58,J7,S +CompanyRevenue,13,90 +CompanySplits,13,90 +RECEIVES,13,45 +Payout,John,45,1,100 + +CompanyOperates,14,John +CompanyRevenue,14,100 +CompanySplits,14,100 +RECEIVES,14,50 +Payout,John,50,1,100 + +CompanyOperates,15,Jean +LaysTileAt,15,3,P3,SW +CompanyRevenue,15,70 +CompanySplits,15,70 +RECEIVES,15,35 +Payout,Jean,35,1,100 + +EndOfOperatingRound,0.2 +ORWorthIncrease,John,0.2,135 +ORWorthIncrease,Mike,0.2,150 +ORWorthIncrease,Mark,0.2,150 +ORWorthIncrease,Jean,0.2,150 +Has,1,90 +Has,2,65 +Has,3,65 +Has,4,60 +Has,5,65 +Has,6,55 +Has,7,150 +Has,8,0 +Has,9,60 +Has,10,65 +Has,11,50 +Has,12,65 +Has,13,65 +Has,14,90 +Has,15,65 +Has,John,270 +Has,Mike,325 +Has,Mark,310 +Has,Jean,260 +StartStockRound,1 +HasPriority,John +START_COMPANY_LOG,John,KBS,90,180,2,20,KBS +MERGE_MINOR_LOG,John,14,KBS,90,1 +GetShareForMinor,John,10,KBS,14 +SharesPutInTreasury,70,KBS +PaysForTokens,KBS,100,5 +START_COMPANY_LOG,Mike,DR,90,180,2,20,DR +MERGE_MINOR_LOG,Mike,4,DR,60,1 +GetShareForMinor,Mike,10,DR,4 +SharesPutInTreasury,70,DR +PaysForTokens,DR,100,5 +START_COMPANY_LOG,Mark,FS,100,200,2,20,FS +MERGE_MINOR_LOG,Mark,10,FS,65,1 +GetShareForMinor,Mark,10,FS,10 +SharesPutInTreasury,70,FS +PaysForTokens,FS,100,5 +START_COMPANY_LOG,Jean,SNCB,75,150,2,20,SNCB +MERGE_MINOR_LOG,Jean,2,SNCB,65,1 +GetShareForMinor,Jean,10,SNCB,2 +SharesPutInTreasury,70,SNCB +PaysForTokens,SNCB,100,5 +MERGE_MINOR_LOG,John,13,KBS,65,1 +GetShareForMinor,John,10,KBS,13 +ExchangesBaseToken,KBS,13,L7 +MinorCloses,13 +MERGE_MINOR_LOG,Mike,7,DR,150,0 +GetShareForMinor,Mike,10,DR,7 +ExchangesBaseToken,DR,7,E10 +MinorCloses,7 +MERGE_MINOR_LOG,Mark,5,FS,65,1 +GetShareForMinor,Mark,10,FS,5 +ExchangesBaseToken,FS,5,S8 +MinorCloses,5 +MERGE_MINOR_LOG,Jean,12,SNCB,65,1 +GetShareForMinor,Jean,10,SNCB,12 +ExchangesBaseToken,SNCB,12,C4 +MinorCloses,12 +BUY_SHARE_LOG,John,10,KBS,KBS,90 +Floats,KBS +BUY_SHARE_LOG,Mike,10,DR,DR,90 +Floats,DR +BUY_SHARE_LOG,Mark,10,FS,FS,100 +Floats,FS +BUY_SHARE_LOG,Jean,10,SNCB,SNCB,75 +Floats,SNCB +PASSES,John +PASSES,Mike +PASSES,Mark +PASSES,Jean + +END_SR,1 +Has,1,90 +Has,3,65 +Has,6,55 +Has,8,0 +Has,9,60 +Has,11,50 +Has,15,65 +Has,SNCB,255 +Has,KBS,325 +Has,FS,330 +Has,DR,380 +Has,John,0 +Has,Mike,55 +Has,Mark,10 +Has,Jean,35 +START_OR,1.1 + +CompanyOperates,1,Mark +CompanyRevenue,1,90 +CompanySplits,1,90 +RECEIVES,1,45 +Payout,Mark,45,1,100 + +CompanyOperates,3,John +CompanyRevenue,3,80 +CompanySplits,3,80 +RECEIVES,3,40 +Payout,John,40,1,100 + +CompanyOperates,6,Mike +CompanyRevenue,6,70 +CompanySplits,6,70 +RECEIVES,6,35 +Payout,Mike,35,1,100 + +CompanyOperates,8,Mike +CompanyRevenue,8,130 +CompanySplits,8,130 +RECEIVES,8,65 +Payout,Mike,65,1,100 + +CompanyOperates,9,Mark +CompanyRevenue,9,70 +CompanySplits,9,70 +RECEIVES,9,35 +Payout,Mark,35,1,100 + +CompanyOperates,11,Jean +CompanyRevenue,11,50 +CompanySplits,11,50 +RECEIVES,11,25 +Payout,Jean,25,1,100 + +CompanyOperates,15,Jean +LaysTileAt,15,9,O2,NW +CompanyRevenue,15,70 +CompanySplits,15,70 +RECEIVES,15,35 +Payout,Jean,35,1,100 + +CompanyOperates,FS,Mark +CompanyRevenue,FS,140 +CompanyPaysOutFull,FS,140 +Payout,Mark,70,5,10 +Payout,FS,70,5,10 +PRICE_MOVES_LOG,FS,100,E3,110,F3 +BuysTrain,FS,3,IPO,200 +FirstTrainBought,3 +StartOfPhase,3 +BuysTrain,FS,3,IPO,200 + +CompanyOperates,KBS,John +LaysTileAt,KBS,579,M4,S +CompanyRevenue,KBS,190 +CompanyPaysOutFull,KBS,190 +Payout,John,95,5,10 +Payout,KBS,95,5,10 +PRICE_MOVES_LOG,KBS,90,E4,100,F4 +BuysTrain,KBS,3,IPO,200 +BuysTrain,KBS,P,Pool,100 + +CompanyOperates,DR,Mike +LaysTileAt,DR,581,E10,SW +CompanyRevenue,DR,100 +CompanyPaysOutFull,DR,100 +Payout,Mike,50,5,10 +Payout,DR,50,5,10 +PRICE_MOVES_LOG,DR,90,E4,100,F4 +BuysTrain,DR,3,IPO,200 +BuysTrain,DR,3,IPO,200 +NewTrainAvailable,3,4 + +CompanyOperates,SNCB,Jean +LaysTileAt,SNCB,141,G2,N +CompanyRevenue,SNCB,170 +CompanyPaysOutFull,SNCB,170 +Payout,Jean,85,5,10 +Payout,SNCB,85,5,10 +PRICE_MOVES_LOG,SNCB,75,D5,82,E5 +BuysTrain,SNCB,4,IPO,300 +FirstTrainBought,4 +StartOfPhase,4 +TrainsRusted,2 + +EndOfOperatingRound,1.1 +ORWorthIncrease,John,1.1,185 +ORWorthIncrease,Mike,1.1,200 +ORWorthIncrease,Mark,1.1,200 +ORWorthIncrease,Jean,1.1,180 +Has,1,135 +Has,3,105 +Has,6,90 +Has,8,65 +Has,9,95 +Has,11,75 +Has,15,100 +Has,SNCB,40 +Has,KBS,120 +Has,FS,0 +Has,DR,30 +Has,John,135 +Has,Mike,205 +Has,Mark,160 +Has,Jean,180 +START_OR,1.2 + +CompanyOperates,1,Mark +CompanyDoesNotPayDividend,1 + +CompanyOperates,3,John +CompanyDoesNotPayDividend,3 + +CompanyOperates,6,Mike +CompanyDoesNotPayDividend,6 + +CompanyOperates,8,Mike +CompanyDoesNotPayDividend,8 + +CompanyOperates,9,Mark +LaysTileAt,9,7,C10,S +CompanyDoesNotPayDividend,9 + +CompanyOperates,11,Jean +CompanyDoesNotPayDividend,11 + +CompanyOperates,15,Jean +LaysTileAtFor,15,8,N1,N,60 +CompanyDoesNotPayDividend,15 + +CompanyOperates,FS,Mark +LaysTileAt,FS,577,S8,NE +CompanyRevenue,FS,200 +CompanyPaysOutFull,FS,200 +Payout,Mark,100,5,10 +Payout,FS,100,5,10 +PRICE_MOVES_LOG,FS,110,F3,122,G3 + +CompanyOperates,KBS,John +LaysTileAt,KBS,578,L7,SW +CompanyRevenue,KBS,200 +CompanySplits,KBS,200 +RECEIVES,KBS,100 +Payout,John,50,5,10 +Payout,KBS,50,5,10 +PRICE_MOVES_LOG,KBS,100,F4,110,G4 +SELL_SHARES_LOG,KBS,2,10,20,KBS,220 + +CompanyOperates,DR,Mike +LaysTileAt,DR,576,G10,N +CompanyRevenue,DR,200 +CompanyPaysOutFull,DR,200 +Payout,Mike,100,5,10 +Payout,DR,100,5,10 +PRICE_MOVES_LOG,DR,100,F4,110,G4 + +CompanyOperates,SNCB,Jean +LaysTileAt,SNCB,4,C6,SW +CompanyRevenue,SNCB,200 +CompanyPaysOutFull,SNCB,200 +Payout,Jean,100,5,10 +Payout,SNCB,100,5,10 +PRICE_MOVES_LOG,SNCB,82,E5,90,F5 +BuysTrain,SNCB,P,Pool,100 + +EndOfOperatingRound,1.2 +ORWorthIncrease,John,1.2,100 +ORWorthIncrease,Mike,1.2,150 +ORWorthIncrease,Mark,1.2,160 +ORWorthIncrease,Jean,1.2,140 +Has,1,135 +Has,3,105 +Has,6,90 +Has,8,65 +Has,9,95 +Has,11,75 +Has,15,40 +Has,SNCB,40 +Has,KBS,490 +Has,FS,100 +Has,DR,130 +Has,John,185 +Has,Mike,305 +Has,Mark,260 +Has,Jean,280 +StartStockRound,2 +HasPriority,John +BUY_SHARE_LOG,John,10,SNCB,SNCB,90 +START_COMPANY_LOG,Mike,KKÖB,100,200,2,20,KKÖB +MERGE_MINOR_LOG,Mike,8,KKÖB,65,0 +GetShareForMinor,Mike,10,KKÖB,8 +SharesPutInTreasury,70,KKÖB +PaysForTokens,KKÖB,100,5 +BUY_SHARE_LOG,Mark,10,SNCB,SNCB,90 +BUY_SHARE_LOG,Jean,10,KBS,Pool,110 +BUY_SHARE_LOG,John,10,SNCB,SNCB,90 +MERGE_MINOR_LOG,Mike,6,KKÖB,90,0 +GetShareForMinor,Mike,10,KKÖB,6 +NoBaseTokenExchange,KKÖB,6,N11 +MinorCloses,6 +BUY_SHARE_LOG,Mark,10,FS,FS,122 +BUY_SHARE_LOG,Jean,10,KBS,Pool,110 +PASSES,John +BUY_SHARE_LOG,Mike,10,KKÖB,KKÖB,100 +Floats,KKÖB +PASSES,Mark +PASSES,Jean +PASSES,John +PASSES,Mike + +END_SR,2 +Has,1,135 +Has,3,105 +Has,9,95 +Has,11,75 +Has,15,40 +Has,SNCB,310 +Has,KBS,490 +Has,KKÖB,355 +Has,FS,222 +Has,DR,130 +Has,John,5 +Has,Mike,5 +Has,Mark,48 +Has,Jean,60 +START_OR,2.1 + +CompanyOperates,1,Mark +CompanyDoesNotPayDividend,1 + +CompanyOperates,3,John +CompanyDoesNotPayDividend,3 + +CompanyOperates,9,Mark +LaysTileAt,9,8,D9,NW +CompanyDoesNotPayDividend,9 + +CompanyOperates,11,Jean +CompanyDoesNotPayDividend,11 + +CompanyOperates,15,Jean +LaysTileAt,15,9,L1,S +CompanyDoesNotPayDividend,15 + +CompanyOperates,FS,Mark +LaysTileAt,FS,581,N11,SW +CompanyRevenue,FS,220 +CompanyPaysOutFull,FS,220 +Payout,Mark,132,6,10 +Payout,FS,88,4,10 +PRICE_MOVES_LOG,FS,122,G3,135,H3 +BuysTrain,FS,4,IPO,300 + +CompanyOperates,KBS,John +LaysTileAt,KBS,580,J1,S +CompanyRevenue,KBS,240 +CompanyPaysOutFull,KBS,240 +Payout,John,120,5,10 +Payout,Jean,48,2,10 +Payout,KBS,72,3,10 +PRICE_MOVES_LOG,KBS,110,G4,122,H4 + +CompanyOperates,DR,Mike +LaysTileAt,DR,83,D9,N +CompanyRevenue,DR,200 +CompanyPaysOutFull,DR,200 +Payout,Mike,100,5,10 +Payout,DR,100,5,10 +PRICE_MOVES_LOG,DR,110,G4,122,H4 +BuysTrain,DR,P,Pool,100 +SELL_SHARES_LOG,DR,5,10,50,DR,610 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,576,P13,SE +LAYS_FREE_TOKEN_ON,KKÖB,N11 +CompanyDoesNotPayDividend,KKÖB +PRICE_MOVES_LOG,KKÖB,100,E3,90,D3 +BuysTrain,KKÖB,3,DR,190 +BuysTrain,KKÖB,P,Pool,100 + +CompanyOperates,SNCB,Jean +LaysTileAt,SNCB,579,C4,SW +CompanyRevenue,SNCB,270 +CompanySplits,SNCB,270 +RECEIVES,SNCB,130 +Payout,Mark,14,1,10 +Payout,John,28,2,10 +Payout,Jean,70,5,10 +Payout,SNCB,28,2,10 +PRICE_MOVES_LOG,SNCB,90,F5,100,F4 +BuysTrain,SNCB,4,IPO,300 + +EndOfOperatingRound,2.1 +ORWorthIncrease,John,2.1,228 +ORWorthIncrease,Mike,2.1,110 +ORWorthIncrease,Mark,2.1,234 +ORWorthIncrease,Jean,2.1,192 +Has,1,135 +Has,3,105 +Has,9,95 +Has,11,75 +Has,15,40 +Has,SNCB,168 +Has,KBS,562 +Has,KKÖB,65 +Has,FS,10 +Has,DR,930 +Has,John,153 +Has,Mike,105 +Has,Mark,194 +Has,Jean,178 +START_OR,2.2 + +CompanyOperates,1,Mark +LaysTileAt,1,9,H1,S +CompanyDoesNotPayDividend,1 +BuysTrain,1,3,FS,34 + +CompanyOperates,3,John +CompanyDoesNotPayDividend,3 + +CompanyOperates,9,Mark +LaysTileAt,9,9,C8,NW +CompanyDoesNotPayDividend,9 + +CompanyOperates,11,Jean +CompanyDoesNotPayDividend,11 + +CompanyOperates,15,Jean +CompanyDoesNotPayDividend,15 + +CompanyOperates,FS,Mark +LaysTileAt,FS,15,R9,NE +CompanyRevenue,FS,260 +CompanyPaysOutFull,FS,260 +Payout,Mark,156,6,10 +Payout,FS,104,4,10 +PRICE_MOVES_LOG,FS,135,H3,150,I3 +SELL_SHARES_LOG,FS,2,10,20,FS,300 + +CompanyOperates,KBS,John +LaysTileAt,KBS,57,I6,NW +CompanyRevenue,KBS,240 +CompanyPaysOutFull,KBS,240 +Payout,John,120,5,10 +Payout,Jean,48,2,10 +Payout,KBS,72,3,10 +PRICE_MOVES_LOG,KBS,122,H4,135,H3 +BuysTrain,KBS,4,IPO,300 +NewTrainAvailable,4,5 + +CompanyOperates,DR,Mike +LaysTileAt,DR,142,G8,N +CompanyRevenue,DR,200 +CompanyPaysOutFull,DR,200 +Payout,Mike,100,5,10 +PRICE_MOVES_LOG,DR,122,H4,135,H3 +BuysTrain,DR,5,IPO,500 +FirstTrainBought,5 +StartOfPhase,5 +CompanyDiscardsTrain,KBS,P,Pool +CompanyDiscardsTrain,DR,P,Pool +CompanyDiscardsTrain,SNCB,P,Pool + +CompanyOperates,SNCB,Jean +LaysTileAt,SNCB,583,J1,S +LAYS_FREE_TOKEN_ON,SNCB,J1 +CompanyRevenue,SNCB,440 +CompanyPaysOutFull,SNCB,440 +Payout,Mark,44,1,10 +Payout,John,88,2,10 +Payout,Jean,220,5,10 +Payout,SNCB,88,2,10 +PRICE_MOVES_LOG,SNCB,100,F4,110,G4 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,141,L11,N +CompanyRevenue,KKÖB,200 +CompanyPaysOutFull,KKÖB,200 +Payout,Mike,100,5,10 +Payout,KKÖB,100,5,10 +PRICE_MOVES_LOG,KKÖB,90,D3,100,E3 + +EndOfOperatingRound,2.2 +ORWorthIncrease,John,2.2,293 +ORWorthIncrease,Mike,2.2,315 +ORWorthIncrease,Mark,2.2,300 +ORWorthIncrease,Jean,2.2,344 +Has,1,101 +Has,3,105 +Has,9,95 +Has,11,75 +Has,15,40 +Has,SNCB,256 +Has,KBS,334 +Has,KKÖB,165 +Has,FS,448 +Has,DR,430 +Has,John,361 +Has,Mike,305 +Has,Mark,394 +Has,Jean,446 +StartFinalMinorExchangeRound +HasFirstTurn,Mike +MERGE_MINOR_LOG,Mark,1,SNCB,101,1 +GetShareForMinor,Mark,10,SNCB,1 +NoBaseTokenExchange,SNCB,1,J1 +MinorCloses,1 +MERGE_MINOR_LOG,Jean,11,FS,75,0 +GetShareForMinor,Jean,10,FS,11 +ExchangesBaseToken,FS,11,N11 +MinorCloses,11 +MERGE_MINOR_LOG,John,3,KBS,105,0 +GetShareForMinor,John,10,KBS,3 +ExchangesBaseToken,KBS,3,J1 +MinorCloses,3 +MERGE_MINOR_LOG,Mark,9,DR,95,0 +GetShareForMinor,Mark,10,DR,9 +NoBaseTokenExchange,DR,9,E10 +MinorCloses,9 +MERGE_MINOR_LOG,Jean,15,KBS,40,0 +GetShareForMinor,Jean,10,KBS,15 +NoBaseTokenExchange,KBS,15,Q2 +MinorCloses,15 +CompanyDiscardsTrain,SNCB,3,Pool + +END_SR,2 +Has,SNCB,357 +Has,KBS,479 +Has,KKÖB,165 +Has,FS,523 +Has,DR,430 +Has,John,361 +Has,Mike,305 +Has,Mark,394 +Has,Jean,446 +StartStockRound,3 +HasPriority,Mark +SELL_SHARE_LOG,Mark,10,FS,150 +START_COMPANY_LOG,Mark,KPEV,100,200,2,20,KPEV +SelectedHomeBase,KPEV,Hex E10 (Berlin SE,S) +SharesPutInTreasury,80,KPEV +PaysForTokens,KPEV,100,5 +BUY_SHARE_LOG,Jean,10,DR,Pool,135 +SELL_SHARES_LOG,John,2,10,20,SNCB,220 +START_COMPANY_LOG,John,NS,100,200,2,20,NS +SelectedHomeBase,NS,Hex J1 (Paris S,SE) +SharesPutInTreasury,80,NS +PaysForTokens,NS,100,5 +BUY_SHARE_LOG,Mike,10,KKÖB,KKÖB,100 +BUY_SHARE_LOG,Mark,10,KPEV,KPEV,100 +BUY_SHARE_LOG,Jean,10,DR,Pool,135 +BUY_SHARE_LOG,John,10,NS,NS,100 +BUY_SHARE_LOG,Mike,10,SNCB,Pool,110 +BUY_SHARE_LOG,Mark,10,KPEV,KPEV,100 +BUY_SHARE_LOG,Jean,10,DR,Pool,135 +BUY_SHARE_LOG,John,10,NS,NS,100 +Autopasses,Mike +BUY_SHARE_LOG,Mark,10,KPEV,KPEV,100 +Floats,KPEV +MonetiseTreasuryShares,KPEV,500 +SELL_SHARES_LOG,Jean,3,10,30,DR,405 +PRICE_MOVES_LOG,DR,135,H3,122,H4 +BUY_SHARE_LOG,Jean,10,FS,FS,150 +BUY_SHARE_LOG,John,10,NS,NS,100 +Floats,NS +MonetiseTreasuryShares,NS,500 +Autopasses,Mike +Autopasses,Mark +SELL_SHARE_LOG,Jean,10,FS,150 +BUY_SHARE_LOG,Jean,10,KKÖB,KKÖB,100 +PASSES,John +Autopasses,Mike +Autopasses,Mark +BUY_SHARE_LOG,Jean,10,KKÖB,KKÖB,100 +PASSES,John +Autopasses,Mike +Autopasses,Mark +BUY_SHARE_LOG,Jean,10,KKÖB,KKÖB,100 +PASSES,John +Autopasses,Mike +Autopasses,Mark +BUY_SHARE_LOG,Jean,10,KKÖB,KKÖB,100 +PASSES,John +Autopasses,Mike +Autopasses,Mark +SELL_SHARES_LOG,Jean,4,10,40,KKÖB,400 +PRICE_MOVES_LOG,KKÖB,100,E3,75,E6 +START_COMPANY_LOG,Jean,SNCF,82,164,2,20,SNCF +SelectedHomeBase,SNCF,Hex J1 (Paris NE,N) +SharesPutInTreasury,80,SNCF +PaysForTokens,SNCF,100,5 +BUY_SHARE_LOG,John,10,KKÖB,Pool,75 +Autopasses,Mike +Autopasses,Mark +BUY_SHARE_LOG,Jean,10,SNCF,SNCF,82 +Autopasses,John +Autopasses,Mike +Autopasses,Mark +BUY_SHARE_LOG,Jean,10,SNCF,SNCF,82 +Autopasses,John +Autopasses,Mike +Autopasses,Mark +BUY_SHARE_LOG,Jean,10,SNCF,SNCF,82 +Floats,SNCF +MonetiseTreasuryShares,SNCF,410 +Autopasses,John +Autopasses,Mike +Autopasses,Mark +SELL_SHARE_LOG,Jean,10,FS,150 +BUY_SHARE_LOG,Jean,10,SNCB,Pool,110 +Autopasses,John +Autopasses,Mike +Autopasses,Mark +PASSES,Jean + +END_SR,3 +Has,SNCB,357 +Has,NS,900 +Has,KBS,479 +Has,KPEV,900 +Has,KKÖB,665 +Has,FS,673 +Has,SNCF,720 +Has,DR,430 +Has,John,6 +Has,Mike,95 +Has,Mark,44 +Has,Jean,76 +START_OR,3.1 + +CompanyOperates,FS,Mark +LaysTileAt,FS,584,N11,S +LAYS_FREE_TOKEN_ON,FS,R9 +CompanyRevenue,FS,310 +CompanySplits,FS,310 +RECEIVES,FS,150 +Payout,Mark,80,5,10 +PRICE_MOVES_LOG,FS,150,I3,165,J3 +BUY_SHARES_LOG,FS,2,10,20,FS,Pool,330 + +CompanyOperates,KBS,John +LaysTileAt,KBS,582,M4,NE +CompanyRevenue,KBS,380 +CompanyPaysOutFull,KBS,380 +Payout,Jean,114,3,10 +Payout,John,228,6,10 +Payout,KBS,38,1,10 +PRICE_MOVES_LOG,KBS,135,H3,150,I3 +SELL_SHARES_LOG,KBS,1,10,10,KBS,150 + +CompanyOperates,DR,Mike +LaysTileAt,DR,582,C4,N +LAYS_FREE_TOKEN_ON,DR,C4 +CompanyRevenue,DR,380 +CompanyPaysOutFull,DR,380 +Payout,Mark,38,1,10 +Payout,Mike,190,5,10 +PRICE_MOVES_LOG,DR,122,H4,135,H3 +BUY_SHARES_LOG,DR,2,10,20,DR,Pool,270 + +CompanyOperates,SNCB,Jean +LaysTileAt,SNCB,578,H3,NW +LAYS_FREE_TOKEN_ON,SNCB,E10 +CompanyRevenue,SNCB,500 +CompanySplits,SNCB,500 +RECEIVES,SNCB,250 +Payout,Mark,50,2,10 +Payout,Jean,150,6,10 +Payout,Mike,25,1,10 +Payout,SNCB,25,1,10 +PRICE_MOVES_LOG,SNCB,110,G4,122,H4 + +CompanyOperates,KPEV,Mark +LaysTileAt,KPEV,582,G10,N +LAYS_FREE_TOKEN_ON,KPEV,G10 +CompanyDoesNotPayDividend,KPEV +PRICE_MOVES_LOG,KPEV,100,E3,90,D3 +BuysTrain,KPEV,3,FS,399 +BuysTrain,KPEV,5,IPO,500 + +CompanyOperates,NS,John +LaysTileAt,NS,83,K2,SW +LAYS_FREE_TOKEN_ON,NS,M4 +CompanyDoesNotPayDividend,NS +PRICE_MOVES_LOG,NS,100,E3,90,D3 +BuysTrain,NS,3,KBS,238 +BuysTrain,NS,5,IPO,500 +NewTrainAvailable,5,6 + +CompanyOperates,SNCF,Jean +LaysTileAt,SNCF,582,H3,S +LAYS_FREE_TOKEN_ON,SNCF,H3 +CompanyDoesNotPayDividend,SNCF +PRICE_MOVES_LOG,SNCF,82,D4,75,C4 +BuysTrain,SNCF,6,IPO,600 +FirstTrainBought,6 +StartOfPhase,6 +TrainsRusted,3 +CompanyDiscardsTrain,KKÖB,P,Pool +BuysTrain,SNCF,P,Pool,100 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,582,S8,NE +LAYS_FREE_TOKEN_ON,KKÖB,S8 +CompanyDoesNotPayDividend,KKÖB +PRICE_MOVES_LOG,KKÖB,75,E6,70,D6 +BuysTrain,KKÖB,6,IPO,600 +NewTrainAvailable,6,8 + +EndOfOperatingRound,3.1 +ORWorthIncrease,John,3.1,263 +ORWorthIncrease,Mike,3.1,262 +ORWorthIncrease,Mark,3.1,230 +ORWorthIncrease,Jean,3.1,346 +Has,SNCB,632 +Has,NS,162 +Has,KBS,905 +Has,KPEV,1 +Has,KKÖB,65 +Has,FS,892 +Has,SNCF,20 +Has,DR,160 +Has,John,234 +Has,Mike,310 +Has,Mark,212 +Has,Jean,340 +START_OR,3.2 + +CompanyOperates,FS,Mark +LaysTileAt,FS,582,P13,SE +LAYS_FREE_TOKEN_ON,FS,P13 +CompanyRevenue,FS,210 +CompanyPaysOutFull,FS,210 +Payout,Mark,105,5,10 +Payout,FS,42,2,10 +PRICE_MOVES_LOG,FS,165,J3,180,K3 +BuysTrain,FS,8,IPO,800 +FirstTrainBought,8 +StartOfPhase,8 +TrainsRusted,4 +BuysTrain,FS,P,Pool,100 + +CompanyOperates,KBS,John +LaysTileAt,KBS,82,I2,NE +LAYS_FREE_TOKEN_ON,KBS,I6 +CompanyDoesNotPayDividend,KBS +PRICE_MOVES_LOG,KBS,150,I3,135,H3 +BuysTrain,KBS,8,IPO,800 +BuysTrain,KBS,P,Pool,100 + +CompanyOperates,DR,Mike +LaysTileAt,DR,142,F3,SE +CompanyRevenue,DR,310 +CompanyPaysOutFull,DR,310 +Payout,Mark,31,1,10 +Payout,Mike,155,5,10 +Payout,DR,62,2,10 +PRICE_MOVES_LOG,DR,135,H3,150,I3 +BuysTrain,DR,P,Pool,100 + +CompanyOperates,SNCB,Jean +LaysTileAt,SNCB,57,G4,SW +CompanyDoesNotPayDividend,SNCB +PRICE_MOVES_LOG,SNCB,122,H4,110,G4 +PresidentAddsCash,SNCB,Jean,168 +BuysTrain,SNCB,8,IPO,800 + +CompanyOperates,KPEV,Mark +LaysTileAt,KPEV,584,E10,S +CompanyRevenue,KPEV,240 +CompanySplits,KPEV,240 +RECEIVES,KPEV,120 +Payout,Mark,60,5,10 +PRICE_MOVES_LOG,KPEV,90,D3,100,E3 +BuysTrain,KPEV,P,Pool,100 + +CompanyOperates,NS,John +LaysTileAt,NS,582,L7,SE +LAYS_FREE_TOKEN_ON,NS,L7 +CompanyRevenue,NS,290 +CompanyPaysOutFull,NS,290 +Payout,John,145,5,10 +PRICE_MOVES_LOG,NS,90,D3,100,E3 + +CompanyOperates,SNCF,Jean +LaysTileAt,SNCF,57,F5,SW +LAYS_FREE_TOKEN_ON,SNCF,G4 +CompanyRevenue,SNCF,370 +CompanyPaysOutFull,SNCF,370 +Payout,Jean,185,5,10 +PRICE_MOVES_LOG,SNCF,75,C4,82,D4 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,611,R9,SE +LAYS_FREE_TOKEN_ON,KKÖB,R9 +CompanyRevenue,KKÖB,430 +CompanyPaysOutFull,KKÖB,430 +Payout,John,43,1,10 +Payout,Mike,258,6,10 +PRICE_MOVES_LOG,KKÖB,70,D6,75,E6 + +EndOfOperatingRound,3.2 +ORWorthIncrease,John,3.2,153 +ORWorthIncrease,Mike,3.2,506 +ORWorthIncrease,Mark,3.2,312 +ORWorthIncrease,Jean,3.2,-65 +Has,SNCB,0 +Has,NS,162 +Has,KBS,5 +Has,KPEV,21 +Has,KKÖB,65 +Has,FS,34 +Has,SNCF,20 +Has,DR,122 +Has,John,422 +Has,Mike,723 +Has,Mark,408 +Has,Jean,357 +StartStockRound,4 +HasPriority,John +BUY_SHARE_LOG,John,10,FS,Pool,180 +BUY_SHARE_LOG,Mike,10,SNCB,SNCB,110 +BUY_SHARE_LOG,Mark,10,FS,Pool,180 +BUY_SHARE_LOG,Jean,10,KKÖB,Pool,75 +BUY_SHARE_LOG,John,10,FS,Pool,180 +BUY_SHARE_LOG,Mike,10,FS,FS,180 +BUY_SHARE_LOG,Mark,10,KBS,Pool,135 +BUY_SHARE_LOG,Jean,10,KKÖB,Pool,75 +Autopasses,John +BUY_SHARE_LOG,Mike,10,FS,FS,180 +BUY_SHARE_LOG,Mark,10,SNCF,Pool,82 +BUY_SHARE_LOG,Jean,10,KKÖB,Pool,75 +Autopasses,John +BUY_SHARE_LOG,Mike,10,DR,Pool,150 +PASSES,Mark +BUY_SHARE_LOG,Jean,10,SNCF,Pool,82 +Autopasses,John +BUY_SHARE_LOG,Mike,10,SNCF,Pool,82 +PASSES,Mark +PASSES,Jean +Autopasses,John +PASSES,Mike + +END_SR,4 +SoldOut,FS +PRICE_MOVES_LOG,FS,180,K3,200,K2 +SoldOut,KBS +PRICE_MOVES_LOG,KBS,135,H3,150,H2 +SoldOut,SNCB +PRICE_MOVES_LOG,SNCB,110,G4,122,G3 +SoldOut,KKÖB +PRICE_MOVES_LOG,KKÖB,75,E6,82,E5 +Has,SNCB,110 +Has,NS,162 +Has,KBS,5 +Has,KPEV,21 +Has,KKÖB,65 +Has,FS,394 +Has,SNCF,20 +Has,DR,122 +Has,John,62 +Has,Mike,21 +Has,Mark,11 +Has,Jean,50 +START_OR,4.1 + +CompanyOperates,FS,Mark +LaysTileAt,FS,15,T5,N +CompanyRevenue,FS,490 +CompanyPaysOutFull,FS,490 +Payout,Mark,294,6,10 +Payout,Mike,98,2,10 +Payout,John,98,2,10 +PRICE_MOVES_LOG,FS,200,K2,220,L2 + +CompanyOperates,DR,Mike +LaysTileAt,DR,147,G2,N +CompanyRevenue,DR,470 +CompanySplits,DR,470 +RECEIVES,DR,230 +Payout,Mark,24,1,10 +Payout,Mike,144,6,10 +Payout,DR,48,2,10 +PRICE_MOVES_LOG,DR,150,I3,165,J3 +SELL_SHARES_LOG,DR,2,10,20,DR,330 + +CompanyOperates,KBS,John +LaysTileAt,KBS,8,H5,N +CompanyRevenue,KBS,390 +CompanyPaysOutFull,KBS,390 +Payout,Mark,39,1,10 +Payout,John,234,6,10 +Payout,Jean,117,3,10 +PRICE_MOVES_LOG,KBS,150,H2,165,I2 + +CompanyOperates,SNCB,Jean +LaysTileAt,SNCB,8,D7,SW +CompanyRevenue,SNCB,670 +CompanyPaysOutFull,SNCB,670 +Payout,Mark,134,2,10 +Payout,Mike,134,2,10 +Payout,Jean,402,6,10 +PRICE_MOVES_LOG,SNCB,122,G3,135,H3 + +CompanyOperates,KPEV,Mark +LaysTileAt,KPEV,82,D5,SE +CompanyRevenue,KPEV,300 +CompanyPaysOutFull,KPEV,300 +Payout,Mark,150,5,10 +PRICE_MOVES_LOG,KPEV,100,E3,110,F3 + +CompanyOperates,NS,John +LaysTileAt,NS,141,P3,SE +CompanyRevenue,NS,290 +CompanyPaysOutFull,NS,290 +Payout,John,145,5,10 +PRICE_MOVES_LOG,NS,100,E3,110,F3 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,57,K10,NW +CompanyRevenue,KKÖB,430 +CompanyPaysOutFull,KKÖB,430 +Payout,Mike,258,6,10 +Payout,Jean,129,3,10 +Payout,John,43,1,10 +PRICE_MOVES_LOG,KKÖB,82,E5,90,F5 + +CompanyOperates,SNCF,Jean +LaysTileAt,SNCF,9,E6,SW +LAYS_FREE_TOKEN_ON,SNCF,F5 +CompanyRevenue,SNCF,520 +CompanyPaysOutFull,SNCF,520 +Payout,Mark,52,1,10 +Payout,Mike,52,1,10 +Payout,Jean,312,6,10 +PRICE_MOVES_LOG,SNCF,82,D4,90,E4 + +EndOfOperatingRound,4.1 +ORWorthIncrease,John,4.1,708 +ORWorthIncrease,Mike,4.1,898 +ORWorthIncrease,Mark,4.1,927 +ORWorthIncrease,Jean,4.1,1155 +Has,SNCB,110 +Has,NS,162 +Has,KBS,5 +Has,KPEV,21 +Has,KKÖB,65 +Has,FS,394 +Has,SNCF,20 +Has,DR,730 +Has,John,582 +Has,Mike,707 +Has,Mark,704 +Has,Jean,1010 +START_OR,4.2 + +CompanyOperates,FS,Mark +LaysTileAt,FS,4,U6,NW +CompanyRevenue,FS,600 +CompanyPaysOutFull,FS,600 +Payout,Mark,360,6,10 +Payout,Mike,120,2,10 +Payout,John,120,2,10 +PRICE_MOVES_LOG,FS,220,L2,245,M2 + +CompanyOperates,DR,Mike +LaysTileAtFor,DR,9,I10,S,60 +CompanyRevenue,DR,470 +CompanySplits,DR,470 +RECEIVES,DR,230 +Payout,Mark,24,1,10 +Payout,Mike,144,6,10 +PRICE_MOVES_LOG,DR,165,J3,180,K3 +BuysTrain,DR,8,IPO,800 +CompanyDiscardsTrain,DR,P,Pool + +CompanyOperates,KBS,John +LaysTileAt,KBS,14,F5,S +LAYS_FREE_TOKEN_ON,KBS,F5 +CompanyRevenue,KBS,520 +CompanyPaysOutFull,KBS,520 +Payout,Mark,52,1,10 +Payout,Jean,156,3,10 +Payout,John,312,6,10 +PRICE_MOVES_LOG,KBS,165,I2,180,J2 + +CompanyOperates,SNCB,Jean +LaysTileAt,SNCB,15,G4,NE +LAYS_FREE_TOKEN_ON,SNCB,G4 +CompanyRevenue,SNCB,670 +CompanyPaysOutFull,SNCB,670 +Payout,Mark,134,2,10 +Payout,Mike,134,2,10 +Payout,Jean,402,6,10 +PRICE_MOVES_LOG,SNCB,135,H3,150,I3 +BuysTrain,SNCB,P,Pool,100 + +CompanyOperates,KPEV,Mark +LaysTileAt,KPEV,141,E4,SE +CompanyRevenue,KPEV,380 +CompanyPaysOutFull,KPEV,380 +Payout,Mark,190,5,10 +PRICE_MOVES_LOG,KPEV,110,F3,122,G3 + +CompanyOperates,NS,John +LaysTileAt,NS,58,O4,SW +CompanyRevenue,NS,340 +CompanyPaysOutFull,NS,340 +Payout,John,170,5,10 +PRICE_MOVES_LOG,NS,110,F3,122,G3 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,513,R9,S +CompanyRevenue,KKÖB,450 +CompanyPaysOutFull,KKÖB,450 +Payout,Jean,135,3,10 +Payout,Mike,270,6,10 +Payout,John,45,1,10 +PRICE_MOVES_LOG,KKÖB,90,F5,100,F4 + +CompanyOperates,SNCF,Jean +LaysTileAt,SNCF,611,F5,SW +CompanyRevenue,SNCF,550 +CompanyPaysOutFull,SNCF,550 +Payout,Mark,55,1,10 +Payout,Jean,330,6,10 +Payout,Mike,55,1,10 +PRICE_MOVES_LOG,SNCF,90,E4,100,F4 + +EndOfOperatingRound,4.2 +ORWorthIncrease,John,4.2,857 +ORWorthIncrease,Mike,4.2,963 +ORWorthIncrease,Mark,4.2,1095 +ORWorthIncrease,Jean,4.2,1248 +Has,SNCB,10 +Has,NS,162 +Has,KBS,5 +Has,KPEV,21 +Has,KKÖB,65 +Has,FS,394 +Has,SNCF,20 +Has,DR,100 +Has,John,1229 +Has,Mike,1430 +Has,Mark,1519 +Has,Jean,2033 +StartStockRound,5 +HasPriority,Mark +BUY_SHARE_LOG,Mark,10,DR,Pool,180 +SELL_SHARE_LOG,Jean,10,KKÖB,100 +PRICE_MOVES_LOG,KKÖB,100,F4,90,F5 +BUY_SHARE_LOG,Jean,10,DR,Pool,180 +BUY_SHARE_LOG,John,10,DR,Pool,180 +BUY_SHARE_LOG,Mike,10,SNCF,Pool,100 +BUY_SHARE_LOG,Mark,10,SNCF,Pool,100 +Autopasses,Jean +BUY_SHARE_LOG,John,10,KPEV,Pool,122 +Autopasses,Mike +Autopasses,Mark +Autopasses,Jean +BUY_SHARE_LOG,John,10,KPEV,Pool,122 +Autopasses,Mike +Autopasses,Mark +Autopasses,Jean +BUY_SHARE_LOG,John,10,KPEV,Pool,122 +Autopasses,Mike +Autopasses,Mark +Autopasses,Jean +SELL_SHARE_LOG,John,10,KKÖB,90 +BUY_SHARE_LOG,John,10,KPEV,Pool,122 +Autopasses,Mike +Autopasses,Mark +Autopasses,Jean +PASSES,John + +END_SR,5 +SoldOut,FS +PRICE_MOVES_LOG,FS,245,M2,270,M1 +SoldOut,DR +PRICE_MOVES_LOG,DR,180,K3,200,K2 +SoldOut,KBS +PRICE_MOVES_LOG,KBS,180,J2,200,J1 +SoldOut,SNCB +PRICE_MOVES_LOG,SNCB,150,I3,165,I2 +SoldOut,SNCF +PRICE_MOVES_LOG,SNCF,100,F4,110,F3 +Has,SNCB,10 +Has,NS,162 +Has,KBS,5 +Has,KPEV,21 +Has,KKÖB,65 +Has,FS,394 +Has,SNCF,20 +Has,DR,100 +Has,John,651 +Has,Mike,1330 +Has,Mark,1239 +Has,Jean,1953 +START_OR,5.1 + +CompanyOperates,FS,Mark +LaysTileAt,FS,611,T5,N +CompanyRevenue,FS,630 +CompanyPaysOutFull,FS,630 +Payout,Mark,378,6,10 +Payout,Mike,126,2,10 +Payout,John,126,2,10 +PRICE_MOVES_LOG,FS,270,M1,300,N1 + +CompanyOperates,DR,Mike +LaysTileAt,DR,14,K10,NW +CompanyRevenue,DR,740 +CompanyPaysOutFull,DR,740 +Payout,Mark,148,2,10 +Payout,Jean,74,1,10 +Payout,Mike,444,6,10 +Payout,John,74,1,10 +PRICE_MOVES_LOG,DR,200,K2,220,L2 + +CompanyOperates,KBS,John +LaysTileAt,KBS,513,F5,S +CompanyRevenue,KBS,680 +CompanyPaysOutFull,KBS,680 +Payout,Mark,68,1,10 +Payout,Jean,204,3,10 +Payout,John,408,6,10 +PRICE_MOVES_LOG,KBS,200,J1,220,K1 + +CompanyOperates,SNCB,Jean +LaysTileAt,SNCB,147,E4,SE +CompanyRevenue,SNCB,680 +CompanyPaysOutFull,SNCB,680 +Payout,Mark,136,2,10 +Payout,Jean,408,6,10 +Payout,Mike,136,2,10 +PRICE_MOVES_LOG,SNCB,165,I2,180,J2 + +CompanyOperates,KPEV,Mark +LaysTileAt,KPEV,145,L11,S +LAYS_FREE_TOKEN_ON,KPEV,K10 +CompanyRevenue,KPEV,450 +CompanyPaysOutFull,KPEV,450 +Payout,Mark,225,5,10 +Payout,John,180,4,10 +PRICE_MOVES_LOG,KPEV,122,G3,135,H3 + +CompanyOperates,NS,John +LaysTileAt,NS,14,I6,SW +LAYS_FREE_TOKEN_ON,NS,I6 +CompanyRevenue,NS,390 +CompanyPaysOutFull,NS,390 +Payout,John,195,5,10 +PRICE_MOVES_LOG,NS,122,G3,135,H3 + +CompanyOperates,SNCF,Jean +LaysTileAt,SNCF,611,G4,NE +CompanyRevenue,SNCF,600 +CompanyPaysOutFull,SNCF,600 +Payout,Mark,120,2,10 +Payout,Jean,360,6,10 +Payout,Mike,120,2,10 +PRICE_MOVES_LOG,SNCF,110,F3,122,G3 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,144,T7,SW +CompanyRevenue,KKÖB,470 +CompanyPaysOutFull,KKÖB,470 +Payout,Jean,94,2,10 +Payout,Mike,282,6,10 +PRICE_MOVES_LOG,KKÖB,90,F5,100,F4 + +EndOfOperatingRound,5.1 +ORWorthIncrease,John,5.1,1300 +ORWorthIncrease,Mike,5.1,1402 +ORWorthIncrease,Mark,5.1,1434 +ORWorthIncrease,Jean,5.1,1402 +Has,SNCB,10 +Has,NS,162 +Has,KBS,5 +Has,KPEV,21 +Has,KKÖB,65 +Has,FS,394 +Has,SNCF,20 +Has,DR,100 +Has,John,1634 +Has,Mike,2438 +Has,Mark,2314 +Has,Jean,3093 +START_OR,5.2 + +CompanyOperates,FS,Mark +LaysTileAt,FS,513,T5,S +CompanyRevenue,FS,660 +CompanyPaysOutFull,FS,660 +Payout,Mark,396,6,10 +Payout,Mike,132,2,10 +Payout,John,132,2,10 +PRICE_MOVES_LOG,FS,300,N1,330,O1 + +CompanyOperates,DR,Mike +LaysTileAt,DR,611,K10,N +CompanyRevenue,DR,770 +CompanyPaysOutFull,DR,770 +Payout,Mark,154,2,10 +Payout,Jean,77,1,10 +Payout,Mike,462,6,10 +Payout,John,77,1,10 +PRICE_MOVES_LOG,DR,220,L2,245,M2 + +CompanyOperates,KBS,John +LaysTileAt,KBS,611,I6,SE +CompanyRevenue,KBS,700 +CompanyPaysOutFull,KBS,700 +Payout,Mark,70,1,10 +Payout,Jean,210,3,10 +BankIsBrokenReportText +Payout,John,420,6,10 +PRICE_MOVES_LOG,KBS,220,K1,245,L1 + +CompanyOperates,SNCB,Jean +LaysTileAt,SNCB,513,G4,S +CompanyRevenue,SNCB,770 +CompanyPaysOutFull,SNCB,770 +Payout,Mark,154,2,10 +Payout,Jean,462,6,10 +Payout,Mike,154,2,10 +PRICE_MOVES_LOG,SNCB,180,J2,200,K2 + +CompanyOperates,KPEV,Mark +LaysTileAt,KPEV,513,K10,S +CompanyRevenue,KPEV,500 +CompanyPaysOutFull,KPEV,500 +Payout,Mark,250,5,10 +Payout,John,200,4,10 +PRICE_MOVES_LOG,KPEV,135,H3,150,I3 + +CompanyOperates,NS,John +LaysTileAt,NS,146,P3,SE +CompanyRevenue,NS,400 +CompanyPaysOutFull,NS,400 +Payout,John,200,5,10 +PRICE_MOVES_LOG,NS,135,H3,150,I3 + +CompanyOperates,SNCF,Jean +LaysTileAt,SNCF,146,F3,NW +CompanyRevenue,SNCF,630 +CompanyPaysOutFull,SNCF,630 +Payout,Mark,126,2,10 +Payout,Jean,378,6,10 +Payout,Mike,126,2,10 +PRICE_MOVES_LOG,SNCF,122,G3,135,H3 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,147,T7,SW +CompanyRevenue,KKÖB,480 +CompanyPaysOutFull,KKÖB,480 +Payout,Jean,96,2,10 +Payout,Mike,288,6,10 +PRICE_MOVES_LOG,KKÖB,100,F4,110,G4 + +EndOfOperatingRound,5.2 +ORWorthIncrease,John,5.2,1399 +ORWorthIncrease,Mike,5.2,1498 +ORWorthIncrease,Mark,5.2,1546 +ORWorthIncrease,Jean,5.2,1541 +Has,SNCB,10 +Has,NS,162 +Has,KBS,5 +Has,KPEV,21 +Has,KKÖB,65 +Has,FS,394 +Has,SNCF,20 +Has,DR,100 +Has,John,2663 +Has,Mike,3600 +Has,Mark,3464 +Has,Jean,4316 +GameOver +EoGWinnerMark! +EoGFinalRanking : +1. 7599 Mark +2. 7526 Jean +3. 7060 Mike +4. 6388 John diff --git a/src/test/resources/data/real/18EUU43.rails b/src/test/resources/data/real/18EUU43.rails new file mode 100644 index 000000000..c1763cfe2 Binary files /dev/null and b/src/test/resources/data/real/18EUU43.rails differ diff --git a/src/test/resources/data/real/18EUU43.report b/src/test/resources/data/real/18EUU43.report new file mode 100644 index 000000000..fd7e13c6f --- /dev/null +++ b/src/test/resources/data/real/18EUU43.report @@ -0,0 +1,1790 @@ +GameIs,18EU +PlayerIs,1,Mark +PlayerIs,2,Mike +PlayerIs,3,John +PlayerIs,4,Barry +PlayerCash,350 +BankHas,10600 +StartOfPhase,2 +BankSizeIs,10600 +StartOfInitialRound,1 +HasPriority,Mark + +SelectForAuctioning,Mark,7 +DeclinedToBid,Mike +DeclinedToBid,John +DeclinedToBid,Barry +ITEM_PRICE_REDUCED,7,90 +BuysItemFor,Mark,7,90 +Floats,7 + +SelectForAuctioning,Mike,13 +DeclinedToBid,John +DeclinedToBid,Barry +BID_ITEM,Mark,100,13 +PASSES,Mike +PASSES,John +PASSES,Barry +BuysItemFor,Mark,13,100 +Floats,13 + +SelectForAuctioning,John,1 +BID_ITEM,Barry,100,1 +PASSES,Mark +PASSES,Mike +BID_ITEM,John,105,1 +PASSES,Barry +BuysItemFor,John,1,105 +Floats,1 + +SelectForAuctioning,Barry,2 +DeclinedToBid,Mark +BID_ITEM,Mike,100,2 +BID_ITEM,John,120,2 +PASSES,Barry +PASSES,Mark +PASSES,Mike +BuysItemFor,John,2,120 +Floats,2 + +SelectForAuctioning,Mark,8 +DeclinedToBid,Mike +DeclinedToBid,John +DeclinedToBid,Barry +ITEM_PRICE_REDUCED,8,90 +DeclinedToBid,Mark +DeclinedToBid,Mike +DeclinedToBid,John +DeclinedToBid,Barry +ITEM_PRICE_REDUCED,8,80 +BuysItemFor,Mark,8,80 +Floats,8 + +SelectForAuctioning,Mike,12 +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,12,90 +DeclinedToBid,Mike +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,12,80 +BuysItemFor,Mike,12,80 +Floats,12 + +SelectForAuctioning,John,5 +DeclinedToBid,Barry +DeclinedToBid,Mark +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,5,90 +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,5,80 +DeclinedToBid,John +BuysItemFor,Barry,5,80 +Floats,5 + +SelectForAuctioning,Barry,3 +DeclinedToBid,Mark +DeclinedToBid,Mike +DeclinedToBid,John +ITEM_PRICE_REDUCED,3,90 +DeclinedToBid,Barry +DeclinedToBid,Mark +DeclinedToBid,Mike +DeclinedToBid,John +ITEM_PRICE_REDUCED,3,80 +BuysItemFor,Barry,3,80 +Floats,3 + +SelectForAuctioning,Mark,14 +DeclinedToBid,Mike +DeclinedToBid,John +BID_ITEM,Barry,100,14 +PASSES,Mark +PASSES,Mike +PASSES,John +BuysItemFor,Barry,14,100 +Floats,14 + +SelectForAuctioning,Mike,9 +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,9,90 +DeclinedToBid,Mike +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,9,80 +BuysItemFor,Mike,9,80 +Floats,9 + +SelectForAuctioning,John,10 +DeclinedToBid,Barry +DeclinedToBid,Mark +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,10,90 +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,10,80 +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,10,70 +BuysItemFor,John,10,70 +Floats,10 + +SelectForAuctioning,Barry,15 +DeclinedToBid,Mark +DeclinedToBid,Mike +DeclinedToBid,John +ITEM_PRICE_REDUCED,15,90 +BuysItemFor,Barry,15,90 +Floats,15 + +SelectForAuctioning,Mark,4 +DeclinedToBid,Mike +DeclinedToBid,John +DeclinedToBid,Barry +ITEM_PRICE_REDUCED,4,90 +DeclinedToBid,Mark +DeclinedToBid,Mike +DeclinedToBid,John +DeclinedToBid,Barry +ITEM_PRICE_REDUCED,4,80 +BuysItemFor,Mark,4,80 +Floats,4 + +SelectForAuctioning,Mike,6 +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,6,90 +DeclinedToBid,Mike +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,6,80 +DeclinedToBid,Mike +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,6,70 +DeclinedToBid,Mike +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,6,60 +DeclinedToBid,Mike +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +ITEM_PRICE_REDUCED,6,50 +BuysItemFor,Mike,6,50 +Floats,6 + +SelectForAuctioning,John,11 +DeclinedToBid,Barry +DeclinedToBid,Mark +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,11,90 +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,11,80 +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,11,70 +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +DeclinedToBid,Mike +ITEM_PRICE_REDUCED,11,60 +DeclinedToBid,John +DeclinedToBid,Barry +DeclinedToBid,Mark +BuysItemFor,Mike,11,60 +NewTrainAvailable,2,3 +Floats,11 +Has,1,0 +Has,2,0 +Has,3,0 +Has,4,0 +Has,5,0 +Has,6,0 +Has,7,0 +Has,8,0 +Has,9,0 +Has,10,0 +Has,11,0 +Has,12,0 +Has,13,0 +Has,14,0 +Has,15,0 +Has,Mark,0 +Has,Mike,80 +Has,John,55 +Has,Barry,0 +START_OR,0.1 + +CompanyOperates,1,John +LaysTileAt,1,9,I2,SW +LaysTileAt,1,202,H3,NE +CompanyRevenue,1,70 +CompanySplits,1,70 +RECEIVES,1,35 +Payout,John,35,1,100 + +CompanyOperates,2,John +LaysTileAt,2,3,F3,S +LaysTileAt,2,58,G2,NW +CompanyRevenue,2,90 +CompanySplits,2,90 +RECEIVES,2,45 +Payout,John,45,1,100 + +CompanyOperates,3,Barry +LaysTileAt,3,8,K2,S +LaysTileAt,3,4,M2,S +CompanyRevenue,3,50 +CompanySplits,3,50 +RECEIVES,3,25 +Payout,Barry,25,1,100 + +CompanyOperates,4,Mark +LaysTileAt,4,202,G10,NW +LaysTileAt,4,4,H9,SW +CompanyRevenue,4,40 +CompanySplits,4,40 +RECEIVES,4,20 +Payout,Mark,20,1,100 + +CompanyOperates,5,Barry +LaysTileAt,5,201,S8,SW +LaysTileAt,5,8,U8,SW +CompanyRevenue,5,60 +CompanySplits,5,60 +RECEIVES,5,30 +Payout,Barry,30,1,100 + +CompanyOperates,6,Mike +LaysTileAt,6,58,L11,S +LaysTileAt,6,57,K10,NW +CompanyRevenue,6,60 +CompanySplits,6,60 +RECEIVES,6,30 +Payout,Mike,30,1,100 + +CompanyOperates,7,Mark +LaysTileAt,7,9,F9,SW +LaysTileAt,7,58,G8,NW +CompanyRevenue,7,40 +CompanySplits,7,40 +RECEIVES,7,20 +Payout,Mark,20,1,100 + +CompanyOperates,8,Mark +LaysTileAt,8,202,P13,S +LaysTileAt,8,9,N13,S +CompanyRevenue,8,60 +CompanySplits,8,60 +RECEIVES,8,30 +Payout,Mark,30,1,100 + +CompanyOperates,9,Mike +LaysTileAt,9,58,D11,SE +LaysTileAt,9,4,E12,NW +CompanyRevenue,9,50 +CompanySplits,9,50 +RECEIVES,9,25 +Payout,Mike,25,1,100 + +CompanyOperates,10,John +LaysTileAt,10,201,R5,S +LaysTileAt,10,57,T5,S +CompanyRevenue,10,60 +CompanySplits,10,60 +RECEIVES,10,30 +Payout,John,30,1,100 + +CompanyOperates,11,Mike +LaysTileAt,11,9,Q10,SW +LaysTileAt,11,57,R9,SW +CompanyRevenue,11,50 +CompanySplits,11,50 +RECEIVES,11,25 +Payout,Mike,25,1,100 + +CompanyOperates,12,Mike +LaysTileAt,12,202,C4,S +LaysTileAt,12,8,D5,NW +CompanyRevenue,12,40 +CompanySplits,12,40 +RECEIVES,12,20 +Payout,Mike,20,1,100 + +CompanyOperates,13,Mark +LaysTileAt,13,201,L7,N +LaysTileAt,13,58,J7,NE +CompanyRevenue,13,40 +CompanySplits,13,40 +RECEIVES,13,20 +Payout,Mark,20,1,100 + +CompanyOperates,14,Barry +LaysTileAt,14,202,M4,SW +LaysTileAt,14,58,O4,SW +CompanyRevenue,14,40 +CompanySplits,14,40 +RECEIVES,14,20 +Payout,Barry,20,1,100 + +CompanyOperates,15,Barry +LaysTileAt,15,201,Q2,NE +LaysTileAt,15,4,P3,SW +CompanyRevenue,15,80 +CompanySplits,15,80 +RECEIVES,15,40 +Payout,Barry,40,1,100 + +EndOfOperatingRound,0.1 +ORWorthIncrease,Mark,0.1,90 +ORWorthIncrease,Mike,0.1,100 +ORWorthIncrease,John,0.1,110 +ORWorthIncrease,Barry,0.1,115 +Has,1,35 +Has,2,45 +Has,3,25 +Has,4,20 +Has,5,30 +Has,6,30 +Has,7,20 +Has,8,30 +Has,9,25 +Has,10,30 +Has,11,25 +Has,12,20 +Has,13,20 +Has,14,20 +Has,15,40 +Has,Mark,90 +Has,Mike,180 +Has,John,165 +Has,Barry,115 +START_OR,0.2 + +CompanyOperates,1,John +CompanyRevenue,1,70 +CompanySplits,1,70 +RECEIVES,1,35 +Payout,John,35,1,100 + +CompanyOperates,2,John +CompanyRevenue,2,90 +CompanySplits,2,90 +RECEIVES,2,45 +Payout,John,45,1,100 + +CompanyOperates,3,Barry +LaysTileAt,3,9,O2,S +CompanyRevenue,3,80 +CompanySplits,3,80 +RECEIVES,3,40 +Payout,Barry,40,1,100 + +CompanyOperates,4,Mark +LaysTileAt,4,9,I8,SW +CompanyRevenue,4,80 +CompanySplits,4,80 +RECEIVES,4,40 +Payout,Mark,40,1,100 + +CompanyOperates,5,Barry +LaysTileAt,5,4,T7,SW +CompanyRevenue,5,70 +CompanySplits,5,70 +RECEIVES,5,35 +Payout,Barry,35,1,100 + +CompanyOperates,6,Mike +CompanyRevenue,6,60 +CompanySplits,6,60 +RECEIVES,6,30 +Payout,Mike,30,1,100 + +CompanyOperates,7,Mark +LaysTileAt,7,58,F7,SE +CompanyRevenue,7,50 +CompanySplits,7,50 +RECEIVES,7,25 +Payout,Mark,25,1,100 + +CompanyOperates,8,Mark +LaysTileAt,8,8,L13,S +CompanyRevenue,8,60 +CompanySplits,8,60 +RECEIVES,8,30 +Payout,Mark,30,1,100 + +CompanyOperates,9,Mike +LaysTileAt,9,8,F13,NW +CompanyRevenue,9,70 +CompanySplits,9,70 +RECEIVES,9,35 +Payout,Mike,35,1,100 + +CompanyOperates,10,John +LaysTileAt,10,8,S6,S +CompanyRevenue,10,60 +CompanySplits,10,60 +RECEIVES,10,30 +Payout,John,30,1,100 + +CompanyOperates,11,Mike +CompanyRevenue,11,50 +CompanySplits,11,50 +RECEIVES,11,25 +Payout,Mike,25,1,100 + +CompanyOperates,12,Mike +LaysTileAt,12,4,C6,SW +CompanyRevenue,12,80 +CompanySplits,12,80 +RECEIVES,12,40 +Payout,Mike,40,1,100 + +CompanyOperates,13,Mark +LaysTileAt,13,58,K6,N +CompanyRevenue,13,90 +CompanySplits,13,90 +RECEIVES,13,45 +Payout,Mark,45,1,100 + +CompanyOperates,14,Barry +LaysTileAt,14,4,L5,SW +CompanyRevenue,14,90 +CompanySplits,14,90 +RECEIVES,14,45 +Payout,Barry,45,1,100 + +CompanyOperates,15,Barry +CompanyRevenue,15,100 +CompanySplits,15,100 +RECEIVES,15,50 +Payout,Barry,50,1,100 + +EndOfOperatingRound,0.2 +ORWorthIncrease,Mark,0.2,140 +ORWorthIncrease,Mike,0.2,130 +ORWorthIncrease,John,0.2,110 +ORWorthIncrease,Barry,0.2,170 +Has,1,70 +Has,2,90 +Has,3,65 +Has,4,60 +Has,5,65 +Has,6,60 +Has,7,45 +Has,8,60 +Has,9,60 +Has,10,60 +Has,11,50 +Has,12,60 +Has,13,65 +Has,14,65 +Has,15,90 +Has,Mark,230 +Has,Mike,310 +Has,John,275 +Has,Barry,285 +StartStockRound,1 +HasPriority,Mark +PASSES,Mark +START_COMPANY_LOG,Mike,KKÖB,100,200,2,20,KKÖB +MERGE_MINOR_LOG,Mike,11,KKÖB,50,1 +GetShareForMinor,Mike,10,KKÖB,11 +SharesPutInTreasury,70,KKÖB +PaysForTokens,KKÖB,100,5 +START_COMPANY_LOG,John,SNCF,90,180,2,20,SNCF +MERGE_MINOR_LOG,John,2,SNCF,90,1 +GetShareForMinor,John,10,SNCF,2 +SharesPutInTreasury,70,SNCF +PaysForTokens,SNCF,100,5 +BUY_SHARE_LOG,Barry,10,SNCF,SNCF,90 +PASSES,Mark +MERGE_MINOR_LOG,Mike,6,KKÖB,60,1 +GetShareForMinor,Mike,10,KKÖB,6 +ExchangesBaseToken,KKÖB,6,N11 +MinorCloses,6 +MERGE_MINOR_LOG,John,1,SNCF,70,1 +GetShareForMinor,John,10,SNCF,1 +ExchangesBaseToken,SNCF,1,J1 +MinorCloses,1 +Floats,SNCF +BUY_SHARE_LOG,Barry,10,KKÖB,KKÖB,100 +Floats,KKÖB +PASSES,Mark +BUY_SHARE_LOG,Mike,10,KKÖB,KKÖB,100 +BUY_SHARE_LOG,John,10,SNCF,SNCF,90 +PASSES,Barry +PASSES,Mark +PASSES,Mike +PASSES,John + +END_SR,1 +Has,3,65 +Has,4,60 +Has,5,65 +Has,7,45 +Has,8,60 +Has,9,60 +Has,10,60 +Has,12,60 +Has,13,65 +Has,14,65 +Has,15,90 +Has,KKÖB,410 +Has,SNCF,420 +Has,Mark,230 +Has,Mike,10 +Has,John,5 +Has,Barry,95 +START_OR,1.1 + +CompanyOperates,3,Barry +CompanyRevenue,3,80 +CompanySplits,3,80 +RECEIVES,3,40 +Payout,Barry,40,1,100 + +CompanyOperates,4,Mark +CompanyRevenue,4,80 +CompanySplits,4,80 +RECEIVES,4,40 +Payout,Mark,40,1,100 +BuysTrain,4,2,7,99 + +CompanyOperates,5,Barry +LaysTileAt,5,3,U6,N +CompanyRevenue,5,80 +CompanySplits,5,80 +RECEIVES,5,40 +Payout,Barry,40,1,100 + +CompanyOperates,7,Mark +LaysTileAt,7,8,G6,NE +CompanyDoesNotPayDividend,7 +BuysTrain,7,2,8,143 + +CompanyOperates,8,Mark +LaysTileAt,8,9,K12,NW +CompanyDoesNotPayDividend,8 +BuysTrain,8,3,IPO,200 +FirstTrainBought,3 +StartOfPhase,3 + +CompanyOperates,9,Mike +CompanyRevenue,9,70 +CompanySplits,9,70 +RECEIVES,9,35 +Payout,Mike,35,1,100 + +CompanyOperates,10,John +CompanyRevenue,10,80 +CompanySplits,10,80 +RECEIVES,10,40 +Payout,John,40,1,100 + +CompanyOperates,12,Mike +LaysTileAt,12,9,C8,NW +CompanyRevenue,12,80 +CompanySplits,12,80 +RECEIVES,12,40 +Payout,Mike,40,1,100 + +CompanyOperates,13,Mark +LaysTileAt,13,57,I6,S +CompanyRevenue,13,100 +CompanySplits,13,100 +RECEIVES,13,50 +Payout,Mark,50,1,100 +BuysTrain,13,2,4,60 + +CompanyOperates,14,Barry +CompanyRevenue,14,90 +CompanySplits,14,90 +RECEIVES,14,45 +Payout,Barry,45,1,100 +BuysTrain,14,2,15,110 + +CompanyOperates,15,Barry +CompanyDoesNotPayDividend,15 +BuysTrain,15,3,IPO,200 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,581,N11,SW +LAYS_FREE_TOKEN_ON,KKÖB,R9 +CompanyRevenue,KKÖB,150 +CompanyPaysOutFull,KKÖB,150 +Payout,Mike,75,5,10 +Payout,Barry,15,1,10 +Payout,KKÖB,60,4,10 +PRICE_MOVES_LOG,KKÖB,100,E3,110,F3 +BuysTrain,KKÖB,3,IPO,200 +BuysTrain,KKÖB,3,IPO,200 + +CompanyOperates,SNCF,John +LaysTileAt,SNCF,580,J1,S +CompanyRevenue,SNCF,180 +CompanyPaysOutFull,SNCF,180 +Payout,John,90,5,10 +Payout,Barry,18,1,10 +Payout,SNCF,72,4,10 +PRICE_MOVES_LOG,SNCF,90,E4,100,F4 +BuysTrain,SNCF,3,IPO,200 +NewTrainAvailable,3,4 + +EndOfOperatingRound,1.1 +ORWorthIncrease,Mark,1.1,90 +ORWorthIncrease,Mike,1.1,200 +ORWorthIncrease,John,1.1,180 +ORWorthIncrease,Barry,1.1,178 +Has,3,105 +Has,4,61 +Has,5,105 +Has,7,1 +Has,8,3 +Has,9,95 +Has,10,100 +Has,12,100 +Has,13,55 +Has,14,0 +Has,15,0 +Has,KKÖB,70 +Has,SNCF,292 +Has,Mark,320 +Has,Mike,160 +Has,John,135 +Has,Barry,253 +START_OR,1.2 + +CompanyOperates,3,Barry +CompanyRevenue,3,80 +CompanySplits,3,80 +RECEIVES,3,40 +Payout,Barry,40,1,100 + +CompanyOperates,4,Mark +LaysTileAtFor,4,8,H11,S,60 +CompanyRevenue,4,80 +CompanySplits,4,80 +RECEIVES,4,40 +Payout,Mark,40,1,100 + +CompanyOperates,5,Barry +CompanyRevenue,5,80 +CompanySplits,5,80 +RECEIVES,5,40 +Payout,Barry,40,1,100 + +CompanyOperates,7,Mark +CompanyRevenue,7,80 +CompanySplits,7,80 +RECEIVES,7,40 +Payout,Mark,40,1,100 + +CompanyOperates,8,Mark +LaysTileAt,8,8,J11,N +CompanyRevenue,8,90 +CompanySplits,8,90 +RECEIVES,8,45 +Payout,Mark,45,1,100 + +CompanyOperates,9,Mike +CompanyRevenue,9,70 +CompanySplits,9,70 +RECEIVES,9,35 +Payout,Mike,35,1,100 + +CompanyOperates,10,John +CompanyRevenue,10,80 +CompanySplits,10,80 +RECEIVES,10,40 +Payout,John,40,1,100 +BuysTrain,10,2,SNCF,139 + +CompanyOperates,12,Mike +LaysTileAt,12,8,D9,NW +CompanyRevenue,12,80 +CompanySplits,12,80 +RECEIVES,12,40 +Payout,Mike,40,1,100 +BuysTrain,12,3,KKÖB,1 + +CompanyOperates,13,Mark +CompanyRevenue,13,160 +CompanySplits,13,160 +RECEIVES,13,80 +Payout,Mark,80,1,100 + +CompanyOperates,14,Barry +CompanyRevenue,14,120 +CompanySplits,14,120 +RECEIVES,14,60 +Payout,Barry,60,1,100 + +CompanyOperates,15,Barry +CompanyRevenue,15,150 +CompanySplits,15,150 +RECEIVES,15,75 +Payout,Barry,75,1,100 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,577,S8,NE +CompanyRevenue,KKÖB,210 +CompanyPaysOutFull,KKÖB,210 +Payout,Mike,105,5,10 +Payout,Barry,21,1,10 +Payout,KKÖB,84,4,10 +PRICE_MOVES_LOG,KKÖB,110,F3,122,G3 + +CompanyOperates,SNCF,John +LaysTileAt,SNCF,9,H1,S +CompanyRevenue,SNCF,250 +CompanyPaysOutFull,SNCF,250 +Payout,Barry,25,1,10 +Payout,John,125,5,10 +Payout,SNCF,100,4,10 +PRICE_MOVES_LOG,SNCF,100,F4,110,G4 + +EndOfOperatingRound,1.2 +ORWorthIncrease,Mark,1.2,205 +ORWorthIncrease,Mike,1.2,240 +ORWorthIncrease,John,1.2,215 +ORWorthIncrease,Barry,1.2,283 +Has,3,145 +Has,4,41 +Has,5,145 +Has,7,41 +Has,8,48 +Has,9,130 +Has,10,1 +Has,12,139 +Has,13,135 +Has,14,60 +Has,15,75 +Has,KKÖB,155 +Has,SNCF,531 +Has,Mark,525 +Has,Mike,340 +Has,John,300 +Has,Barry,514 +StartStockRound,2 +HasPriority,Barry +BUY_SHARE_LOG,Barry,10,SNCF,SNCF,110 +BUY_SHARE_LOG,Mark,10,SNCF,SNCF,110 +START_COMPANY_LOG,Mike,NS,82,164,2,20,NS +MERGE_MINOR_LOG,Mike,12,NS,139,2 +GetShareForMinor,Mike,10,NS,12 +SharesPutInTreasury,70,NS +PaysForTokens,NS,100,5 +BUY_SHARE_LOG,John,10,SNCF,SNCF,110 +START_COMPANY_LOG,Barry,SNCB,100,200,2,20,SNCB +MERGE_MINOR_LOG,Barry,15,SNCB,75,1 +GetShareForMinor,Barry,10,SNCB,15 +SharesPutInTreasury,70,SNCB +PaysForTokens,SNCB,100,5 +BUY_SHARE_LOG,Mark,10,SNCF,SNCF,110 +BUY_SHARE_LOG,Mike,10,NS,NS,82 +PASSES,John +BUY_SHARE_LOG,Barry,10,SNCB,SNCB,100 +START_COMPANY_LOG,Mark,DR,100,200,2,20,DR +MERGE_MINOR_LOG,Mark,4,DR,41,1 +GetShareForMinor,Mark,10,DR,4 +SharesPutInTreasury,70,DR +PaysForTokens,DR,100,5 +BUY_SHARE_LOG,Mike,10,NS,NS,82 +Floats,NS +BUY_SHARE_LOG,John,10,SNCB,SNCB,100 +Floats,SNCB +MERGE_MINOR_LOG,Barry,3,SNCB,145,1 +GetShareForMinor,Barry,10,SNCB,3 +ExchangesBaseToken,SNCB,3,J1 +MinorCloses,3 +MERGE_MINOR_LOG,Mark,8,DR,48,1 +GetShareForMinor,Mark,10,DR,8 +ExchangesBaseToken,DR,8,P13 +MinorCloses,8 +PASSES,Mike +PASSES,John +MERGE_MINOR_LOG,Barry,14,SNCB,60,2 +GetShareForMinor,Barry,10,SNCB,14 +ExchangesBaseToken,SNCB,14,M4 +MinorCloses,14 +MERGE_MINOR_LOG,Mark,13,DR,135,2 +GetShareForMinor,Mark,10,DR,13 +ExchangesBaseToken,DR,13,L7 +MinorCloses,13 +Floats,DR +PASSES,Mike +PASSES,John +BUY_SHARE_LOG,Barry,10,DR,DR,100 +BUY_SHARE_LOG,Mark,10,SNCB,SNCB,100 +PASSES,Mike +PASSES,John +PASSES,Barry +PASSES,Mark + +END_SR,2 +SoldOut,SNCF +PRICE_MOVES_LOG,SNCF,110,G4,122,G3 +Has,5,145 +Has,7,41 +Has,9,130 +Has,10,1 +Has,SNCB,680 +Has,NS,367 +Has,KKÖB,155 +Has,SNCF,971 +Has,DR,424 +Has,Mark,5 +Has,Mike,12 +Has,John,90 +Has,Barry,4 +START_OR,2.1 + +CompanyOperates,5,Barry +CompanyRevenue,5,90 +CompanySplits,5,90 +RECEIVES,5,45 +Payout,Barry,45,1,100 +BuysTrain,5,2,SNCB,190 + +CompanyOperates,7,Mark +CompanyRevenue,7,80 +CompanySplits,7,80 +RECEIVES,7,40 +Payout,Mark,40,1,100 +BuysTrain,7,2,DR,80 + +CompanyOperates,9,Mike +CompanyRevenue,9,70 +CompanySplits,9,70 +RECEIVES,9,35 +Payout,Mike,35,1,100 +BuysTrain,9,2,KKÖB,165 + +CompanyOperates,10,John +CompanyRevenue,10,150 +CompanySplits,10,150 +RECEIVES,10,75 +Payout,John,75,1,100 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,15,K10,NW +LAYS_FREE_TOKEN_ON,KKÖB,K10 +CompanyRevenue,KKÖB,200 +CompanyPaysOutFull,KKÖB,200 +Payout,Barry,20,1,10 +Payout,Mike,100,5,10 +Payout,KKÖB,80,4,10 +PRICE_MOVES_LOG,KKÖB,122,G3,135,H3 +BuysTrain,KKÖB,2,NS,100 +BuysTrain,KKÖB,4,IPO,300 +FirstTrainBought,4 +StartOfPhase,4 +TrainsRusted,2 + +CompanyOperates,SNCF,John +LaysTileAt,SNCF,577,H3,SW +CompanyRevenue,SNCF,160 +CompanyPaysOutFull,SNCF,160 +Payout,Barry,32,2,10 +Payout,John,96,6,10 +Payout,Mark,32,2,10 +PRICE_MOVES_LOG,SNCF,122,G3,135,H3 +BuysTrain,SNCF,4,IPO,300 +BuysTrain,SNCF,4,IPO,300 + +CompanyOperates,SNCB,Barry +LaysTileAt,SNCB,144,K6,S +CompanyRevenue,SNCB,170 +CompanyPaysOutFull,SNCB,170 +Payout,Barry,102,6,10 +Payout,John,17,1,10 +Payout,Mark,17,1,10 +Payout,SNCB,34,2,10 +PRICE_MOVES_LOG,SNCB,100,E3,110,F3 +BuysTrain,SNCB,4,IPO,300 +NewTrainAvailable,4,5 + +CompanyOperates,DR,Mark +LaysTileAt,DR,581,E10,SW +LAYS_FREE_TOKEN_ON,DR,I6 +CompanyRevenue,DR,160 +CompanyPaysOutFull,DR,160 +Payout,Barry,16,1,10 +Payout,Mark,80,5,10 +Payout,DR,64,4,10 +PRICE_MOVES_LOG,DR,100,E3,110,F3 +BuysTrain,DR,5,IPO,500 +FirstTrainBought,5 +StartOfPhase,5 +CompanyDiscardsTrain,SNCF,3,Pool + +CompanyOperates,NS,Mike +LaysTileAt,NS,7,C10,S +CompanyRevenue,NS,150 +CompanyPaysOutFull,NS,150 +Payout,Mike,75,5,10 +Payout,NS,75,5,10 +PRICE_MOVES_LOG,NS,82,D4,90,E4 +BuysTrain,NS,5,IPO,500 + +EndOfOperatingRound,2.1 +ORWorthIncrease,Mark,2.1,255 +ORWorthIncrease,Mike,2.1,315 +ORWorthIncrease,John,2.1,276 +ORWorthIncrease,Barry,2.1,324 +Has,5,0 +Has,7,1 +Has,9,0 +Has,10,76 +Has,SNCB,604 +Has,NS,42 +Has,KKÖB,0 +Has,SNCF,371 +Has,DR,68 +Has,Mark,174 +Has,Mike,222 +Has,John,278 +Has,Barry,219 +START_OR,2.2 + +CompanyOperates,5,Barry +CompanyDoesNotPayDividend,5 + +CompanyOperates,7,Mark +CompanyDoesNotPayDividend,7 + +CompanyOperates,9,Mike +CompanyDoesNotPayDividend,9 + +CompanyOperates,10,John +CompanyDoesNotPayDividend,10 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,582,S8,NE +LAYS_FREE_TOKEN_ON,KKÖB,S8 +CompanyRevenue,KKÖB,270 +CompanyPaysOutFull,KKÖB,270 +Payout,Barry,27,1,10 +Payout,Mike,135,5,10 +Payout,KKÖB,108,4,10 +PRICE_MOVES_LOG,KKÖB,135,H3,150,I3 +SELL_SHARES_LOG,KKÖB,4,10,40,KKÖB,600 + +CompanyOperates,SNCF,John +LaysTileAt,SNCF,57,G4,SW +CompanyRevenue,SNCF,320 +CompanyPaysOutFull,SNCF,320 +Payout,Barry,64,2,10 +Payout,John,192,6,10 +Payout,Mark,64,2,10 +PRICE_MOVES_LOG,SNCF,135,H3,150,I3 + +CompanyOperates,SNCB,Barry +LaysTileAt,SNCB,83,K2,SW +CompanyRevenue,SNCB,230 +CompanyPaysOutFull,SNCB,230 +Payout,Barry,138,6,10 +Payout,John,23,1,10 +Payout,Mark,23,1,10 +Payout,SNCB,46,2,10 +PRICE_MOVES_LOG,SNCB,110,F3,122,G3 + +CompanyOperates,DR,Mark +LaysTileAt,DR,584,E10,S +LAYS_FREE_TOKEN_ON,DR,E10 +CompanyRevenue,DR,400 +CompanyPaysOutFull,DR,400 +Payout,Barry,40,1,10 +Payout,Mark,200,5,10 +Payout,DR,160,4,10 +PRICE_MOVES_LOG,DR,110,F3,122,G3 + +CompanyOperates,NS,Mike +LaysTileAt,NS,579,C4,SW +CompanyRevenue,NS,210 +CompanyPaysOutFull,NS,210 +Payout,Mike,105,5,10 +Payout,NS,105,5,10 +PRICE_MOVES_LOG,NS,90,E4,100,F4 + +EndOfOperatingRound,2.2 +ORWorthIncrease,Mark,2.2,389 +ORWorthIncrease,Mike,2.2,365 +ORWorthIncrease,John,2.2,317 +ORWorthIncrease,Barry,2.2,398 +Has,5,0 +Has,7,1 +Has,9,0 +Has,10,76 +Has,SNCB,650 +Has,NS,147 +Has,KKÖB,708 +Has,SNCF,371 +Has,DR,228 +Has,Mark,461 +Has,Mike,462 +Has,John,493 +Has,Barry,488 +StartFinalMinorExchangeRound +HasFirstTurn,Mark +MERGE_MINOR_LOG,Mark,7,NS,1,0 +GetShareForMinor,Mark,10,NS,7 +ExchangesBaseToken,NS,7,E10 +MinorCloses,7 +MERGE_MINOR_LOG,Mike,9,DR,0,0 +GetShareForMinor,Mike,10,DR,9 +NoBaseTokenExchange,DR,9,E10 +MinorCloses,9 +MERGE_MINOR_LOG,John,10,KKÖB,76,0 +GetShareForMinor,John,10,KKÖB,10 +NoBaseTokenExchange,KKÖB,10,R5 +MinorCloses,10 +MERGE_MINOR_LOG,Barry,5,KKÖB,0,0 +GetShareForMinor,Barry,10,KKÖB,5 +NoBaseTokenExchange,KKÖB,5,S8 +MinorCloses,5 + +END_SR,2 +Has,SNCB,650 +Has,NS,148 +Has,KKÖB,708 +Has,SNCF,371 +Has,DR,228 +Has,Mark,461 +Has,Mike,462 +Has,John,493 +Has,Barry,488 +StartStockRound,3 +HasPriority,Mike +SELL_SHARE_LOG,Mike,10,DR,122 +PRICE_MOVES_LOG,DR,122,G3,110,G4 +START_COMPANY_LOG,Mike,KPEV,100,200,2,20,KPEV +SelectedHomeBase,KPEV,Hex E10 (Berlin) +SharesPutInTreasury,80,KPEV +PaysForTokens,KPEV,100,5 +SELL_SHARE_LOG,John,10,SNCB,122 +PRICE_MOVES_LOG,SNCB,122,G3,110,G4 +START_COMPANY_LOG,John,KBS,100,200,2,20,KBS +SelectedHomeBase,KBS,Hex G4 (Cologne) +SharesPutInTreasury,80,KBS +PaysForTokens,KBS,100,5 +SELL_SHARES_LOG,Barry,2,10,20,SNCF,300 +START_COMPANY_LOG,Barry,FS,100,200,2,20,FS +SelectedHomeBase,FS,Hex F5 (Dortmund) +SharesPutInTreasury,80,FS +PaysForTokens,FS,100,5 +BUY_SHARE_LOG,Mark,10,DR,Pool,110 +BUY_SHARE_LOG,Mike,10,KPEV,KPEV,100 +BUY_SHARE_LOG,John,10,KBS,KBS,100 +BUY_SHARE_LOG,Barry,10,DR,DR,110 +BUY_SHARE_LOG,Mark,10,KKÖB,Pool,150 +BUY_SHARE_LOG,Mike,10,KPEV,KPEV,100 +BUY_SHARE_LOG,John,10,KBS,KBS,100 +BUY_SHARE_LOG,Barry,10,FS,FS,100 +BUY_SHARE_LOG,Mark,10,SNCB,Pool,110 +BUY_SHARE_LOG,Mike,10,KPEV,KPEV,100 +Floats,KPEV +MonetiseTreasuryShares,KPEV,500 +BUY_SHARE_LOG,John,10,KBS,KBS,100 +Floats,KBS +MonetiseTreasuryShares,KBS,500 +BUY_SHARE_LOG,Barry,10,FS,FS,100 +PASSES,Mark +PASSES,Mike +BUY_SHARE_LOG,John,10,DR,DR,110 +BUY_SHARE_LOG,Barry,10,FS,FS,100 +Floats,FS +MonetiseTreasuryShares,FS,500 +PASSES,Mark +PASSES,Mike +PASSES,John +BUY_SHARE_LOG,Barry,10,FS,Pool,100 +PASSES,Mark +PASSES,Mike +PASSES,John +PASSES,Barry + +END_SR,3 +Has,SNCB,650 +Has,NS,148 +Has,KBS,900 +Has,KPEV,900 +Has,KKÖB,708 +Has,FS,900 +Has,SNCF,371 +Has,DR,448 +Has,Mark,91 +Has,Mike,84 +Has,John,5 +Has,Barry,78 +START_OR,3.1 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,81,J11,S +CompanyRevenue,KKÖB,300 +CompanyPaysOutFull,KKÖB,300 +Payout,Barry,60,2,10 +Payout,Mike,150,5,10 +Payout,John,30,1,10 +Payout,Mark,30,1,10 +PRICE_MOVES_LOG,KKÖB,150,I3,165,J3 + +CompanyOperates,SNCF,John +LaysTileAt,SNCF,15,G4,SW +LAYS_FREE_TOKEN_ON,SNCF,G4 +CompanyRevenue,SNCF,330 +CompanyWithholds,SNCF,330 +PRICE_MOVES_LOG,SNCF,150,I3,135,H3 + +CompanyOperates,DR,Mark +LaysTileAt,DR,579,G10,SW +CompanyRevenue,DR,470 +CompanySplits,DR,470 +RECEIVES,DR,230 +Payout,Barry,48,2,10 +Payout,John,24,1,10 +Payout,Mark,144,6,10 +Payout,DR,24,1,10 +PRICE_MOVES_LOG,DR,110,G4,122,H4 +SELL_SHARES_LOG,DR,1,10,10,DR,122 + +CompanyOperates,SNCB,Barry +LaysTileAt,SNCB,15,I6,S +CompanyRevenue,SNCB,320 +CompanySplits,SNCB,320 +RECEIVES,SNCB,160 +Payout,Barry,96,6,10 +Payout,Mark,32,2,10 +Payout,SNCB,32,2,10 +PRICE_MOVES_LOG,SNCB,110,G4,122,H4 +SELL_SHARES_LOG,SNCB,1,10,10,SNCB,122 + +CompanyOperates,NS,Mike +LaysTileAt,NS,58,D3,NE +CompanyRevenue,NS,330 +CompanyPaysOutFull,NS,330 +Payout,Mike,165,5,10 +Payout,Mark,33,1,10 +Payout,NS,132,4,10 +PRICE_MOVES_LOG,NS,100,F4,110,G4 + +CompanyOperates,KPEV,Mike +LaysTileAt,KPEV,582,C4,N +LAYS_FREE_TOKEN_ON,KPEV,C4 +CompanyDoesNotPayDividend,KPEV +PRICE_MOVES_LOG,KPEV,100,E3,90,D3 +BuysTrain,KPEV,3,KKÖB,200 +BuysTrain,KPEV,5,IPO,500 +NewTrainAvailable,5,6 + +CompanyOperates,KBS,John +LaysTileAt,KBS,582,H3,SW +LAYS_FREE_TOKEN_ON,KBS,H3 +CompanyDoesNotPayDividend,KBS +PRICE_MOVES_LOG,KBS,100,E3,90,D3 +BuysTrain,KBS,4,SNCF,199 +BuysTrain,KBS,6,IPO,600 +FirstTrainBought,6 +StartOfPhase,6 +TrainsRusted,3 + +CompanyOperates,FS,Barry +LaysTileAt,FS,57,F5,SW +CompanyDoesNotPayDividend,FS +PRICE_MOVES_LOG,FS,100,E3,90,D3 +BuysTrain,FS,6,IPO,600 +NewTrainAvailable,6,8 +BuysTrain,FS,P,Pool,100 +BUY_SHARES_LOG,FS,2,10,20,FS,Pool,180 + +EndOfOperatingRound,3.1 +ORWorthIncrease,Mark,3.1,330 +ORWorthIncrease,Mike,3.1,390 +ORWorthIncrease,John,3.1,-59 +ORWorthIncrease,Barry,3.1,270 +Has,SNCB,964 +Has,NS,280 +Has,KBS,101 +Has,KPEV,200 +Has,KKÖB,908 +Has,FS,20 +Has,SNCF,900 +Has,DR,824 +Has,Mark,330 +Has,Mike,399 +Has,John,59 +Has,Barry,282 +START_OR,3.2 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,584,N11,S +DuplicateTokenRemoved,KKÖB,N11 +CompanyRevenue,KKÖB,190 +CompanyPaysOutFull,KKÖB,190 +Payout,Mike,95,5,10 +Payout,Barry,38,2,10 +Payout,Mark,19,1,10 +Payout,John,19,1,10 +PRICE_MOVES_LOG,KKÖB,165,J3,180,K3 +BuysTrain,KKÖB,8,IPO,800 +FirstTrainBought,8 +StartOfPhase,8 +TrainsRusted,4 +BuysTrain,KKÖB,P,Pool,100 + +CompanyOperates,SNCF,John +LaysTileAt,SNCF,143,F3,NW +CompanyDoesNotPayDividend,SNCF +PRICE_MOVES_LOG,SNCF,135,H3,122,G3 +BuysTrain,SNCF,8,IPO,800 +BuysTrain,SNCF,P,Pool,100 + +CompanyOperates,DR,Mark +LaysTileAt,DR,576,P13,SE +CompanyRevenue,DR,330 +CompanyPaysOutFull,DR,330 +Payout,Barry,66,2,10 +Payout,Mark,198,6,10 +Payout,John,33,1,10 +PRICE_MOVES_LOG,DR,122,H4,135,H3 +BuysTrain,DR,8,IPO,800 + +CompanyOperates,SNCB,Barry +LaysTileAt,SNCB,81,G6,SW +CompanyDoesNotPayDividend,SNCB +PRICE_MOVES_LOG,SNCB,122,H4,110,G4 +BuysTrain,SNCB,8,IPO,800 +BuysTrain,SNCB,P,Pool,100 + +CompanyOperates,NS,Mike +LaysTileAt,NS,147,F3,NE +CompanyRevenue,NS,390 +CompanyPaysOutFull,NS,390 +Payout,Mike,195,5,10 +Payout,Mark,39,1,10 +Payout,NS,156,4,10 +PRICE_MOVES_LOG,NS,110,G4,122,H4 +SELL_SHARES_LOG,NS,4,10,40,NS,488 + +CompanyOperates,KPEV,Mike +LaysTileAt,KPEV,582,G10,SW +CompanyRevenue,KPEV,390 +CompanyPaysOutFull,KPEV,390 +Payout,Mike,195,5,10 +PRICE_MOVES_LOG,KPEV,90,D3,100,E3 +BuysTrain,KPEV,P,Pool,100 + +CompanyOperates,KBS,John +LaysTileAt,KBS,583,J1,S +LAYS_FREE_TOKEN_ON,KBS,J1 +CompanyRevenue,KBS,280 +CompanyPaysOutFull,KBS,280 +Payout,John,140,5,10 +PRICE_MOVES_LOG,KBS,90,D3,100,E3 + +CompanyOperates,FS,Barry +LaysTileAt,FS,14,F5,SW +CompanyRevenue,FS,230 +CompanyPaysOutFull,FS,230 +Payout,Barry,138,6,10 +Payout,FS,46,2,10 +PRICE_MOVES_LOG,FS,90,D3,100,E3 + +EndOfOperatingRound,3.2 +ORWorthIncrease,Mark,3.2,311 +ORWorthIncrease,Mike,3.2,670 +ORWorthIncrease,John,3.2,192 +ORWorthIncrease,Barry,3.2,286 +Has,SNCB,64 +Has,NS,924 +Has,KBS,101 +Has,KPEV,100 +Has,KKÖB,8 +Has,FS,66 +Has,SNCF,0 +Has,DR,24 +Has,Mark,586 +Has,Mike,884 +Has,John,251 +Has,Barry,524 +StartStockRound,4 +HasPriority,Mark +BUY_SHARE_LOG,Mark,10,KKÖB,Pool,180 +BUY_SHARE_LOG,Mike,10,DR,Pool,135 +BUY_SHARE_LOG,John,10,SNCB,Pool,110 +BUY_SHARE_LOG,Barry,10,SNCF,Pool,122 +BUY_SHARE_LOG,Mark,10,SNCF,Pool,122 +BUY_SHARE_LOG,Mike,10,NS,Pool,122 +BUY_SHARE_LOG,John,10,SNCB,SNCB,110 +BUY_SHARE_LOG,Barry,10,KPEV,Pool,100 +BUY_SHARE_LOG,Mark,10,NS,Pool,122 +BUY_SHARE_LOG,Mike,10,KPEV,Pool,100 +PASSES,John +PASSES,Barry +BUY_SHARE_LOG,Mark,10,NS,Pool,122 +BUY_SHARE_LOG,Mike,10,KBS,Pool,100 +PASSES,John +PASSES,Barry +PASSES,Mark +PASSES,Mike + +END_SR,4 +SoldOut,KKÖB +PRICE_MOVES_LOG,KKÖB,180,K3,200,K2 +SoldOut,DR +PRICE_MOVES_LOG,DR,135,H3,150,H2 +SoldOut,SNCF +PRICE_MOVES_LOG,SNCF,122,G3,135,G2 +SoldOut,SNCB +PRICE_MOVES_LOG,SNCB,110,G4,122,G3 +Has,SNCB,174 +Has,NS,924 +Has,KBS,101 +Has,KPEV,100 +Has,KKÖB,8 +Has,FS,66 +Has,SNCF,0 +Has,DR,24 +Has,Mark,40 +Has,Mike,427 +Has,John,31 +Has,Barry,302 +START_OR,4.1 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,582,P13,SE +LAYS_FREE_TOKEN_ON,KKÖB,P13 +CompanyRevenue,KKÖB,530 +CompanyPaysOutFull,KKÖB,530 +Payout,Mike,265,5,10 +Payout,Barry,106,2,10 +Payout,Mark,106,2,10 +Payout,John,53,1,10 +PRICE_MOVES_LOG,KKÖB,200,K2,220,L2 + +CompanyOperates,DR,Mark +LaysTileAt,DR,611,I6,S +CompanyRevenue,DR,740 +CompanyPaysOutFull,DR,740 +Payout,Mike,74,1,10 +Payout,Barry,148,2,10 +Payout,Mark,444,6,10 +Payout,John,74,1,10 +PRICE_MOVES_LOG,DR,150,H2,165,I2 + +CompanyOperates,SNCF,John +LaysTileAt,SNCF,8,E6,SW +CompanyRevenue,SNCF,500 +CompanyPaysOutFull,SNCF,500 +Payout,Mark,150,3,10 +Payout,Barry,50,1,10 +Payout,John,300,6,10 +PRICE_MOVES_LOG,SNCF,135,G2,150,H2 + +CompanyOperates,NS,Mike +LaysTileAt,NS,611,K10,N +LAYS_FREE_TOKEN_ON,NS,G10 +CompanyRevenue,NS,390 +CompanyPaysOutFull,NS,390 +Payout,Mike,234,6,10 +Payout,Mark,117,3,10 +PRICE_MOVES_LOG,NS,122,H4,135,H3 +BuysTrain,NS,8,IPO,800 + +CompanyOperates,SNCB,Barry +LaysTileAt,SNCB,513,I6,S +LAYS_FREE_TOKEN_ON,SNCB,F5 +CompanyRevenue,SNCB,410 +CompanyPaysOutFull,SNCB,410 +Payout,Mark,82,2,10 +Payout,Barry,246,6,10 +Payout,John,82,2,10 +PRICE_MOVES_LOG,SNCB,122,G3,135,H3 + +CompanyOperates,KPEV,Mike +LaysTileAt,KPEV,7,F11,SW +CompanyRevenue,KPEV,460 +CompanyPaysOutFull,KPEV,460 +Payout,Mike,276,6,10 +Payout,Barry,46,1,10 +PRICE_MOVES_LOG,KPEV,100,E3,110,F3 + +CompanyOperates,KBS,John +CompanyRevenue,KBS,310 +CompanyPaysOutFull,KBS,310 +Payout,Mike,31,1,10 +Payout,John,155,5,10 +PRICE_MOVES_LOG,KBS,100,E3,110,F3 + +CompanyOperates,FS,Barry +LaysTileAt,FS,144,J7,SW +CompanyRevenue,FS,190 +CompanyPaysOutFull,FS,190 +Payout,Barry,114,6,10 +Payout,FS,38,2,10 +PRICE_MOVES_LOG,FS,100,E3,110,F3 + +EndOfOperatingRound,4.1 +ORWorthIncrease,Mark,4.1,1139 +ORWorthIncrease,Mike,4.1,1143 +ORWorthIncrease,John,4.1,865 +ORWorthIncrease,Barry,4.1,943 +Has,SNCB,174 +Has,NS,124 +Has,KBS,101 +Has,KPEV,100 +Has,KKÖB,8 +Has,FS,104 +Has,SNCF,0 +Has,DR,24 +Has,Mark,939 +Has,Mike,1307 +Has,John,695 +Has,Barry,1012 +START_OR,4.2 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,513,K10,S +CompanyRevenue,KKÖB,560 +CompanyPaysOutFull,KKÖB,560 +Payout,Mike,280,5,10 +Payout,Barry,112,2,10 +Payout,Mark,112,2,10 +Payout,John,56,1,10 +PRICE_MOVES_LOG,KKÖB,220,L2,245,M2 + +CompanyOperates,DR,Mark +LaysTileAt,DR,578,L7,NW +CompanyRevenue,DR,780 +CompanyPaysOutFull,DR,780 +Payout,Mike,78,1,10 +Payout,Barry,156,2,10 +Payout,Mark,468,6,10 +Payout,John,78,1,10 +PRICE_MOVES_LOG,DR,165,I2,180,J2 + +CompanyOperates,SNCF,John +LaysTileAt,SNCF,611,G4,NW +CompanyRevenue,SNCF,420 +CompanyPaysOutFull,SNCF,420 +Payout,Mark,126,3,10 +Payout,Barry,42,1,10 +Payout,John,252,6,10 +PRICE_MOVES_LOG,SNCF,150,H2,165,I2 + +CompanyOperates,NS,Mike +LaysTileAt,NS,15,R9,SW +LAYS_FREE_TOKEN_ON,NS,R9 +CompanyRevenue,NS,870 +CompanyPaysOutFull,NS,870 +Payout,Mike,522,6,10 +Payout,Mark,261,3,10 +PRICE_MOVES_LOG,NS,135,H3,150,I3 + +CompanyOperates,SNCB,Barry +LaysTileAt,SNCB,513,G4,S +CompanyRevenue,SNCB,520 +CompanyPaysOutFull,SNCB,520 +Payout,Mark,104,2,10 +Payout,Barry,312,6,10 +Payout,John,104,2,10 +PRICE_MOVES_LOG,SNCB,135,H3,150,I3 + +CompanyOperates,KPEV,Mike +LaysTileAt,KPEV,143,D3,SW +CompanyRevenue,KPEV,460 +CompanyPaysOutFull,KPEV,460 +Payout,Mike,276,6,10 +Payout,Barry,46,1,10 +PRICE_MOVES_LOG,KPEV,110,F3,122,G3 + +CompanyOperates,KBS,John +LaysTileAt,KBS,9,H5,NW +CompanyRevenue,KBS,420 +CompanyPaysOutFull,KBS,420 +Payout,Mike,42,1,10 +Payout,John,210,5,10 +PRICE_MOVES_LOG,KBS,110,F3,122,G3 + +CompanyOperates,FS,Barry +LaysTileAt,FS,142,C6,SE +CompanyRevenue,FS,440 +CompanyPaysOutFull,FS,440 +Payout,Barry,264,6,10 +Payout,FS,88,2,10 +PRICE_MOVES_LOG,FS,110,F3,122,G3 + +EndOfOperatingRound,4.2 +ORWorthIncrease,Mark,4.2,1331 +ORWorthIncrease,Mike,4.2,1512 +ORWorthIncrease,John,4.2,920 +ORWorthIncrease,Barry,4.2,1201 +Has,SNCB,174 +Has,NS,124 +Has,KBS,101 +Has,KPEV,100 +Has,KKÖB,8 +Has,FS,192 +Has,SNCF,0 +Has,DR,24 +Has,Mark,2010 +Has,Mike,2505 +Has,John,1395 +Has,Barry,1944 +StartStockRound,5 +HasPriority,John +BUY_SHARE_LOG,John,10,NS,Pool,150 +SELL_SHARE_LOG,Barry,10,SNCF,165 +PRICE_MOVES_LOG,SNCF,165,I2,150,I3 +BUY_SHARE_LOG,Barry,10,KPEV,Pool,122 +BUY_SHARE_LOG,Mark,10,SNCF,Pool,150 +SELL_SHARE_LOG,Mike,10,KBS,122 +PRICE_MOVES_LOG,KBS,122,G3,110,G4 +BUY_SHARE_LOG,Mike,10,FS,Pool,122 +BUY_SHARE_LOG,John,10,FS,Pool,122 +PASSES,Barry +PASSES,Mark +PASSES,Mike +BUY_SHARE_LOG,John,10,FS,FS,122 +PASSES,Barry +PASSES,Mark +PASSES,Mike +PASSES,John + +END_SR,5 +SoldOut,KKÖB +PRICE_MOVES_LOG,KKÖB,245,M2,270,M1 +SoldOut,DR +PRICE_MOVES_LOG,DR,180,J2,200,J1 +SoldOut,NS +PRICE_MOVES_LOG,NS,150,I3,165,I2 +SoldOut,SNCB +PRICE_MOVES_LOG,SNCB,150,I3,165,I2 +SoldOut,SNCF +PRICE_MOVES_LOG,SNCF,150,I3,165,I2 +Has,SNCB,174 +Has,NS,124 +Has,KBS,101 +Has,KPEV,100 +Has,KKÖB,8 +Has,FS,314 +Has,SNCF,0 +Has,DR,24 +Has,Mark,1860 +Has,Mike,2505 +Has,John,1001 +Has,Barry,1987 +START_OR,5.1 + +CompanyOperates,KKÖB,Mike +LaysTileAt,KKÖB,611,R9,SW +CompanyRevenue,KKÖB,580 +CompanyPaysOutFull,KKÖB,580 +Payout,Mike,290,5,10 +Payout,Mark,116,2,10 +Payout,Barry,116,2,10 +Payout,John,58,1,10 +PRICE_MOVES_LOG,KKÖB,270,M1,300,N1 + +CompanyOperates,DR,Mark +LaysTileAt,DR,582,L7,S +CompanyRevenue,DR,930 +CompanyPaysOutFull,DR,930 +Payout,Mike,93,1,10 +Payout,Mark,558,6,10 +Payout,Barry,186,2,10 +Payout,John,93,1,10 +PRICE_MOVES_LOG,DR,200,J1,220,K1 + +CompanyOperates,NS,Mike +LaysTileAt,NS,513,R9,S +LAYS_FREE_TOKEN_ON,NS,S8 +CompanyRevenue,NS,970 +CompanyPaysOutFull,NS,970 +Payout,Mike,582,6,10 +Payout,Mark,291,3,10 +Payout,John,97,1,10 +PRICE_MOVES_LOG,NS,165,I2,180,J2 + +CompanyOperates,SNCB,Barry +LaysTileAt,SNCB,58,E4,S +CompanyRevenue,SNCB,600 +CompanyPaysOutFull,SNCB,600 +Payout,Mark,120,2,10 +Payout,Barry,360,6,10 +Payout,John,120,2,10 +PRICE_MOVES_LOG,SNCB,165,I2,180,J2 + +CompanyOperates,SNCF,John +LaysTileAt,SNCF,143,G8,SE +LAYS_FREE_TOKEN_ON,SNCF,L7 +CompanyRevenue,SNCF,570 +CompanyPaysOutFull,SNCF,570 +Payout,Mark,228,4,10 +Payout,John,342,6,10 +PRICE_MOVES_LOG,SNCF,165,I2,180,J2 + +CompanyOperates,KPEV,Mike +LaysTileAt,KPEV,142,E4,SW +CompanyRevenue,KPEV,470 +CompanyPaysOutFull,KPEV,470 +BankIsBrokenReportText +Payout,Mike,282,6,10 +Payout,Barry,94,2,10 +PRICE_MOVES_LOG,KPEV,122,G3,135,H3 + +CompanyOperates,FS,Barry +LaysTileAt,FS,80,C10,SW +CompanyRevenue,FS,460 +CompanyPaysOutFull,FS,460 +Payout,Mike,46,1,10 +Payout,Barry,276,6,10 +Payout,John,92,2,10 +Payout,FS,46,1,10 +PRICE_MOVES_LOG,FS,122,G3,135,H3 + +CompanyOperates,KBS,John +LaysTileAt,KBS,8,E8,S +CompanyRevenue,KBS,440 +CompanyPaysOutFull,KBS,440 +Payout,John,220,5,10 +PRICE_MOVES_LOG,KBS,110,G4,122,H4 + +EndOfOperatingRound,5.1 +ORWorthIncrease,Mark,5.1,1628 +ORWorthIncrease,Mike,5.1,1644 +ORWorthIncrease,John,5.1,1293 +ORWorthIncrease,Barry,5.1,1326 +Has,SNCB,174 +Has,NS,124 +Has,KBS,101 +Has,KPEV,100 +Has,KKÖB,8 +Has,FS,360 +Has,SNCF,0 +Has,DR,24 +Has,Mark,3173 +Has,Mike,3798 +Has,John,2023 +Has,Barry,3019 +START_OR,5.2 + +CompanyOperates,KKÖB,Mike +CompanyRevenue,KKÖB,600 +CompanyPaysOutFull,KKÖB,600 +Payout,Mike,300,5,10 +Payout,Mark,120,2,10 +Payout,Barry,120,2,10 +Payout,John,60,1,10 +PRICE_MOVES_LOG,KKÖB,300,N1,330,O1 + +CompanyOperates,DR,Mark +LaysTileAt,DR,147,E4,SW +CompanyRevenue,DR,960 +CompanyPaysOutFull,DR,960 +Payout,Mike,96,1,10 +Payout,Mark,576,6,10 +Payout,Barry,192,2,10 +Payout,John,96,1,10 +PRICE_MOVES_LOG,DR,220,K1,245,L1 + +CompanyOperates,NS,Mike +LaysTileAt,NS,147,G8,SW +CompanyRevenue,NS,980 +CompanyPaysOutFull,NS,980 +Payout,Mike,588,6,10 +Payout,Mark,294,3,10 +Payout,John,98,1,10 +PRICE_MOVES_LOG,NS,180,J2,200,K2 + +CompanyOperates,SNCB,Barry +LaysTileAt,SNCB,142,D11,S +CompanyRevenue,SNCB,550 +CompanyPaysOutFull,SNCB,550 +Payout,Mark,110,2,10 +Payout,Barry,330,6,10 +Payout,John,110,2,10 +PRICE_MOVES_LOG,SNCB,180,J2,200,K2 + +CompanyOperates,SNCF,John +LaysTileAt,SNCF,8,D7,N +CompanyRevenue,SNCF,670 +CompanyPaysOutFull,SNCF,670 +Payout,Mark,268,4,10 +Payout,John,402,6,10 +PRICE_MOVES_LOG,SNCF,180,J2,200,K2 + +CompanyOperates,KPEV,Mike +LaysTileAt,KPEV,146,C6,NW +CompanyRevenue,KPEV,500 +CompanyPaysOutFull,KPEV,500 +Payout,Mike,300,6,10 +Payout,Barry,100,2,10 +PRICE_MOVES_LOG,KPEV,135,H3,150,I3 + +CompanyOperates,FS,Barry +LaysTileAt,FS,611,F5,NW +LAYS_FREE_TOKEN_ON,FS,G4 +CompanyRevenue,FS,540 +CompanyPaysOutFull,FS,540 +Payout,Mike,54,1,10 +Payout,Barry,324,6,10 +Payout,John,108,2,10 +Payout,FS,54,1,10 +PRICE_MOVES_LOG,FS,135,H3,150,I3 + +CompanyOperates,KBS,John +LaysTileAt,KBS,146,D11,N +CompanyRevenue,KBS,470 +CompanyPaysOutFull,KBS,470 +Payout,John,235,5,10 +PRICE_MOVES_LOG,KBS,122,H4,135,H3 + +EndOfOperatingRound,5.2 +ORWorthIncrease,Mark,5.2,1758 +ORWorthIncrease,Mike,5.2,1738 +ORWorthIncrease,John,5.2,1439 +ORWorthIncrease,Barry,5.2,1416 +Has,SNCB,174 +Has,NS,124 +Has,KBS,101 +Has,KPEV,100 +Has,KKÖB,8 +Has,FS,414 +Has,SNCF,0 +Has,DR,24 +Has,Mark,4541 +Has,Mike,5136 +Has,John,3132 +Has,Barry,4085 +GameOver +EoGWinnerMike! +EoGFinalRanking : +1. 9281 Mike +2. 8471 Mark +3. 7635 Barry +4. 6482 John diff --git a/src/test/resources/data/real/18VAZ22.rails b/src/test/resources/data/real/18VAZ22.rails new file mode 100644 index 000000000..bc45f8dcb Binary files /dev/null and b/src/test/resources/data/real/18VAZ22.rails differ diff --git a/src/test/resources/data/real/18VAZ22.report b/src/test/resources/data/real/18VAZ22.report new file mode 100644 index 000000000..ce05f238d --- /dev/null +++ b/src/test/resources/data/real/18VAZ22.report @@ -0,0 +1,1355 @@ +GameIs,18VA +PlayerIs,1,Paul +PlayerIs,2,Peter +PlayerIs,3,Stephen +PlayerCash,400 +BankHas,6800 +StartOfPhase,2 +BankSizeIs,6800 +StartOfInitialRound,1 +HasPriority,Paul +BID_ITEM_LOG,Paul,40,REA,360 +BID_ITEM_LOG,Peter,200,B&O,200 +BID_ITEM_LOG,Stephen,60,TIW,340 +BID_ITEM_LOG,Paul,65,TIW,295 +PASSES,Peter +BID_ITEM_LOG,Stephen,80,PY,260 +BID_ITEM_LOG,Paul,85,PY,210 +PASSES,Peter +PASSES,Stephen +PASSES,Paul +ALL_PASSED +BuysItemFor,Paul,REA,40 +BuysItemFor,Paul,TIW,65 +BuysItemFor,Paul,PY,85 +BuysItemFor,Peter,PRES_CERT_NAME,B&O,20,200 +Has,B&O,200 +Has,Paul,210 +Has,Peter,200 +Has,Stephen,400 +StartStockRound,1 +HasPriority,Peter +BUY_SHARE_LOG,Peter,10,B&O,B&O,100 +START_COMPANY_LOG,Stephen,NW,82,164,2,40,BANK +FloatsWithCash,NW,164 +START_COMPANY_LOG,Paul,VGN,70,140,2,40,BANK +FloatsWithCash,VGN,140 +BUY_SHARE_LOG,Peter,10,B&O,B&O,100 +PASSES,Stephen +PASSES,Paul +PASSES,Peter + +END_SR,1 +Has,B&O,400 +Has,NW,164 +Has,VGN,140 +Has,Paul,70 +Has,Peter,0 +Has,Stephen,236 +START_OR,1.1 +ReceivesFor,Paul,10,REA +ReceivesFor,Paul,15,TIW +ReceivesFor,Paul,20,PY + +CompanyOperates,B&O,Peter +LaysTileAt,B&O,6,C8,NE +LAYS_TOKEN_ON,B&O,A8,40 +CompanyDoesNotPayDividend,B&O +PRICE_MOVES_LOG,B&O,100,E3,90,D3 +BuysTrain,B&O,2,IPO,100 +FirstTrainBought,2/1G + +CompanyOperates,NW,Stephen +LaysTileAt,NW,57,M6,S +CompanyDoesNotPayDividend,NW +PRICE_MOVES_LOG,NW,82,D4,75,C4 +BuysTrain,NW,2,IPO,100 + +CompanyOperates,VGN,Paul +LaysTileAt,VGN,5,L3,N +CompanyDoesNotPayDividend,VGN +PRICE_MOVES_LOG,VGN,70,C5,65,B5 +BuysTrain,VGN,1G,IPO,100 + +EndOfOperatingRound,1.1 +ORWorthIncrease,Paul,1.1,35 +ORWorthIncrease,Peter,1.1,-40 +ORWorthIncrease,Stephen,1.1,-14 +Has,B&O,260 +Has,NW,64 +Has,VGN,40 +Has,Paul,115 +Has,Peter,0 +Has,Stephen,236 +StartStockRound,2 +HasPriority,Stephen +BUY_SHARE_LOG,Stephen,20,NW,NW,75 +PASSES,Paul +PASSES,Peter +BUY_SHARE_LOG,Stephen,20,VGN,VGN,65 +PASSES,Paul +PASSES,Peter +BUY_SHARE_LOG,Stephen,20,VGN,VGN,65 +PASSES,Paul +PASSES,Peter +PASSES,Stephen + +END_SR,2 +Has,B&O,260 +Has,NW,139 +Has,VGN,170 +Has,Paul,115 +Has,Peter,0 +Has,Stephen,31 +START_OR,2.1 +ReceivesFor,Paul,10,REA +ReceivesFor,Paul,15,TIW +ReceivesFor,Paul,20,PY + +CompanyOperates,B&O,Peter +LaysTileAt,B&O,57,D7,SW +CompanyRevenue,B&O,100 +CompanyPaysOutFull,B&O,100 +Payout,Peter,40,4,10 +PRICE_MOVES_LOG,B&O,90,D3,100,E3 +BuysTrain,B&O,2,IPO,100 + +CompanyOperates,NW,Stephen +LaysTileAt,NW,9,O6,S +LAYS_TOKEN_ON,NW,Q6,40 +CompanyRevenue,NW,80 +CompanyPaysOutFull,NW,80 +Payout,Stephen,48,3,20 +PRICE_MOVES_LOG,NW,75,C4,82,D4 + +CompanyOperates,VGN,Paul +LaysTileAt,VGN,58,M2,NW +CompanyRevenue,VGN,50 +CompanyPaysOutFull,VGN,50 +Payout,Paul,20,2,20 +Payout,Stephen,20,2,20 +PRICE_STAYS_LOG,VGN,65,B5 + +EndOfOperatingRound,2.1 +ORWorthIncrease,Paul,2.1,65 +ORWorthIncrease,Peter,2.1,80 +ORWorthIncrease,Stephen,2.1,89 +Has,B&O,160 +Has,NW,99 +Has,VGN,170 +Has,Paul,180 +Has,Peter,40 +Has,Stephen,99 +StartStockRound,3 +HasPriority,Paul +BUY_SHARE_LOG,Paul,20,VGN,VGN,65 +PASSES,Peter +SELL_SHARE_LOG,Stephen,20,NW,82 +PRICE_MOVES_LOG,NW,82,D4,75,D5 +BUY_SHARE_LOG,Stephen,10,B&O,B&O,100 +PASSES,Paul +PASSES,Peter +PASSES,Stephen + +END_SR,3 +Has,B&O,260 +Has,NW,99 +Has,VGN,235 +Has,Paul,115 +Has,Peter,40 +Has,Stephen,81 +START_OR,3.1 +ReceivesFor,Paul,10,REA +ReceivesFor,Paul,15,TIW +ReceivesFor,Paul,20,PY + +CompanyOperates,B&O,Peter +LaysTileAt,B&O,6,E6,SW +CompanyRevenue,B&O,140 +CompanyPaysOutFull,B&O,140 +Payout,Stephen,14,1,10 +Payout,Peter,56,4,10 +PRICE_MOVES_LOG,B&O,100,E3,110,F3 +BuysTrain,B&O,2,IPO,100 + +CompanyOperates,NW,Stephen +LaysTileAt,NW,57,K6,S +CompanyRevenue,NW,80 +CompanyPaysOutFull,NW,80 +Payout,Stephen,32,2,20 +Payout,NW,16,1,20 +PRICE_MOVES_LOG,NW,75,D5,82,E5 +BuysTrain,NW,2,IPO,100 +NewTrainAvailable,2/1G,3/2G + +CompanyOperates,VGN,Paul +CompanyRevenue,VGN,50 +CompanyPaysOutFull,VGN,50 +Payout,Paul,30,3,20 +Payout,Stephen,20,2,20 +PRICE_STAYS_LOG,VGN,65,B5 + +EndOfOperatingRound,3.1 +ORWorthIncrease,Paul,3.1,75 +ORWorthIncrease,Peter,3.1,96 +ORWorthIncrease,Stephen,3.1,90 +Has,B&O,160 +Has,NW,15 +Has,VGN,235 +Has,Paul,190 +Has,Peter,96 +Has,Stephen,147 +StartStockRound,4 +HasPriority,Paul +PASSES,Paul +BUY_SHARE_LOG,Peter,20,NW,NW,82 +SELL_SHARE_LOG,Stephen,20,VGN,65 +PRICE_MOVES_LOG,VGN,65,B5,60,B6 +BUY_SHARE_LOG,Stephen,20,NW,NW,82 +PASSES,Paul +PASSES,Peter +BUY_SHARE_LOG,Stephen,10,B&O,B&O,110 +SELL_SHARES_LOG,B&O,4,10,40,B&O,440 +PASSES,Paul +PASSES,Peter +PASSES,Stephen + +END_SR,4 +Has,B&O,710 +Has,NW,179 +Has,VGN,235 +Has,Paul,190 +Has,Peter,14 +Has,Stephen,20 +START_OR,4.1 +ReceivesFor,Paul,10,REA +ReceivesFor,Paul,15,TIW +ReceivesFor,Paul,20,PY + +CompanyOperates,B&O,Peter +LaysTileAt,B&O,5,G6,NE +LAYS_TOKEN_ON,B&O,E6,100 +CompanyRevenue,B&O,180 +CompanyPaysOutFull,B&O,180 +Payout,Stephen,36,2,10 +Payout,Peter,72,4,10 +Payout,B&O,72,4,10 +PRICE_MOVES_LOG,B&O,110,F3,122,G3 +BuysTrain,B&O,3,IPO,200 +FirstTrainBought,3/2G +StartOfPhase,3 + +CompanyOperates,NW,Stephen +LaysTileAt,NW,14,M6,NW +CompanyRevenue,NW,140 +CompanyPaysOutFull,NW,140 +Payout,Peter,28,1,20 +Payout,Stephen,84,3,20 +Payout,NW,28,1,20 +PRICE_MOVES_LOG,NW,82,E5,90,F5 + +CompanyOperates,VGN,Paul +LaysTileAt,VGN,14,L3,SW +LAYS_TOKEN_ON,VGN,L1,40 +CompanyRevenue,VGN,80 +CompanyDividesEarnings,VGN,80,60,20 +CompanyPaysOutFull,VGN,60 +Payout,Stephen,12,1,20 +Payout,Paul,36,3,20 +Payout,VGN,12,1,20 +PRICE_MOVES_LOG,VGN,60,B6,65,C6 +BuysTrain,VGN,2G,IPO,200 + +EndOfOperatingRound,4.1 +ORWorthIncrease,Paul,4.1,96 +ORWorthIncrease,Peter,4.1,156 +ORWorthIncrease,Stephen,4.1,185 +Has,B&O,482 +Has,NW,207 +Has,VGN,27 +Has,Paul,271 +Has,Peter,114 +Has,Stephen,152 +StartStockRound,5 +HasPriority,Paul +BUY_SHARE_LOG,Paul,10,B&O,Pool,122 +SELL_SHARE_LOG,Peter,20,NW,90 +BUY_SHARE_LOG,Peter,10,B&O,Pool,122 +BUY_SHARE_LOG,Stephen,10,B&O,Pool,122 +BUY_SHARE_LOG,Paul,10,B&O,Pool,122 +BUY_SHARE_LOG,Peter,20,VGN,Pool,65 +PASSES,Stephen +PASSES,Paul +PASSES,Peter + +END_SR,5 +SoldOut,B&O +PRICE_MOVES_LOG,B&O,122,G3,135,G2 +Has,B&O,482 +Has,NW,207 +Has,VGN,27 +Has,Paul,27 +Has,Peter,17 +Has,Stephen,30 +START_OR,5.1 +ReceivesFor,Paul,10,REA +ReceivesFor,Paul,15,TIW +ReceivesFor,Paul,20,PY + +CompanyOperates,B&O,Peter +LaysTileAt,B&O,14,D7,SW +CompanyRevenue,B&O,260 +CompanyPaysOutFull,B&O,260 +Payout,Stephen,78,3,10 +Payout,Peter,130,5,10 +Payout,Paul,52,2,10 +PRICE_MOVES_LOG,B&O,135,G2,150,H2 + +CompanyOperates,NW,Stephen +LaysTileAt,NW,14,K6,NW +CompanyRevenue,NW,150 +CompanyPaysOutFull,NW,150 +Payout,Stephen,90,3,20 +Payout,NW,60,2,20 +PRICE_MOVES_LOG,NW,90,F5,100,F4 + +CompanyOperates,VGN,Paul +LaysTileAt,VGN,58,K2,SE +CompanyRevenue,VGN,200 +CompanyDividesEarnings,VGN,200,140,60 +CompanyPaysOutFull,VGN,140 +Payout,Stephen,28,1,20 +Payout,Peter,28,1,20 +Payout,Paul,84,3,20 +PRICE_MOVES_LOG,VGN,65,C6,70,D6 + +EndOfOperatingRound,5.1 +ORWorthIncrease,Paul,5.1,226 +ORWorthIncrease,Peter,5.1,238 +ORWorthIncrease,Stephen,5.1,276 +Has,B&O,482 +Has,NW,267 +Has,VGN,87 +Has,Paul,208 +Has,Peter,175 +Has,Stephen,226 +START_OR,5.2 +ReceivesFor,Paul,10,REA +ReceivesFor,Paul,15,TIW +ReceivesFor,Paul,20,PY + +CompanyOperates,B&O,Peter +LaysTileAt,B&O,15,C8,S +CompanyRevenue,B&O,280 +CompanyPaysOutFull,B&O,280 +Payout,Stephen,84,3,10 +Payout,Peter,140,5,10 +Payout,Paul,56,2,10 +PRICE_MOVES_LOG,B&O,150,H2,165,I2 + +CompanyOperates,NW,Stephen +LaysTileAt,NW,9,I6,S +CompanyRevenue,NW,150 +CompanyPaysOutFull,NW,150 +Payout,Stephen,90,3,20 +Payout,NW,60,2,20 +PRICE_MOVES_LOG,NW,100,F4,110,G4 + +CompanyOperates,VGN,Paul +LaysTileAt,VGN,8,K4,SW +CompanyRevenue,VGN,200 +CompanyDividesEarnings,VGN,200,140,60 +CompanyPaysOutFull,VGN,140 +Payout,Stephen,28,1,20 +Payout,Peter,28,1,20 +Payout,Paul,84,3,20 +PRICE_MOVES_LOG,VGN,70,D6,75,E6 + +EndOfOperatingRound,5.2 +ORWorthIncrease,Paul,5.2,230 +ORWorthIncrease,Peter,5.2,248 +ORWorthIncrease,Stephen,5.2,282 +Has,B&O,482 +Has,NW,327 +Has,VGN,147 +Has,Paul,393 +Has,Peter,343 +Has,Stephen,428 +StartStockRound,6 +HasPriority,Stephen +SELL_SHARES_LOG,Stephen,2,10,20,B&O,330 +PRICE_MOVES_LOG,B&O,165,I2,150,I3 +START_COMPANY_LOG,Stephen,RFP,100,200,2,40,BANK +FloatsWithCash,RFP,200 +START_COMPANY_LOG,Paul,C&O,90,180,2,40,BANK +FloatsWithCash,C&O,180 +START_COMPANY_LOG,Peter,SR,100,200,2,40,BANK +FloatsWithCash,SR,200 +START_COMPANY_LOG,Stephen,WM,100,200,2,40,BANK +FloatsWithCash,WM,200 +BUY_SHARE_LOG,Paul,20,C&O,C&O,90 +BUY_SHARE_LOG,Peter,20,SR,SR,100 +BUY_SHARE_LOG,Stephen,20,RFP,RFP,100 +BUY_SHARE_LOG,Paul,20,NW,Pool,110 +PASSES,Peter +BUY_SHARE_LOG,Stephen,20,WM,WM,100 +PASSES,Paul +PASSES,Peter +BUY_SHARE_LOG,Stephen,20,SR,SR,100 +PASSES,Paul +PASSES,Peter +PASSES,Stephen + +END_SR,6 +Has,B&O,482 +Has,C&O,270 +Has,NW,327 +Has,RFP,300 +Has,SR,400 +Has,VGN,147 +Has,WM,300 +Has,Paul,13 +Has,Peter,43 +Has,Stephen,58 +START_OR,6.1 +ReceivesFor,Paul,10,REA +ReceivesFor,Paul,15,TIW +ReceivesFor,Paul,20,PY + +CompanyOperates,B&O,Peter +LaysTileAt,B&O,15,E6,NE +CompanyRevenue,B&O,300 +CompanyPaysOutFull,B&O,300 +Payout,Stephen,30,1,10 +Payout,Peter,150,5,10 +Payout,Paul,60,2,10 +Payout,B&O,60,2,10 +PRICE_MOVES_LOG,B&O,150,I3,165,J3 + +CompanyOperates,NW,Stephen +CompanyHasGrown,NW,10 +PhaseDependentTrainLimitsSetTo,NW,[4, 3, 2],4 +LaysTileAt,NW,15,G6,S +CompanyRevenue,NW,150 +CompanyPaysOutFull,NW,150 +Payout,Stephen,45,3,10 +Payout,Paul,15,1,10 +Payout,NW,15,1,10 +PRICE_MOVES_LOG,NW,110,G4,122,H4 +BuysTrain,NW,3,IPO,200 + +CompanyOperates,RFP,Stephen +LaysTileAt,RFP,9,F5,NW +LAYS_TOKEN_ON,RFP,C8,40 +CompanyDoesNotPayDividend,RFP +PRICE_MOVES_LOG,RFP,100,E3,90,D3 +BuysTrain,RFP,2,NW,60 +BuysTrain,RFP,3,IPO,200 + +CompanyOperates,SR,Peter +LaysTileAt,SR,8,L5,SE +LAYS_TOKEN_ON,SR,E6,40 +CompanyDoesNotPayDividend,SR +PRICE_MOVES_LOG,SR,100,E3,90,D3 +BuysTrain,SR,3,IPO,200 +NewTrainAvailable,3/2G,4/3G + +CompanyOperates,WM,Stephen +LaysTileAt,WM,6,D3,NW +CompanyDoesNotPayDividend,WM +PRICE_MOVES_LOG,WM,100,E3,90,D3 +BuysTrain,WM,3G,IPO,300 +FirstTrainBought,4/3G +StartOfPhase,4 +TrainsRusted,2/1G + +CompanyOperates,C&O,Paul +LaysTileAt,C&O,5,I4,NW +BuysPrivateFromFor,C&O,TIW,Paul,90 +LAYS_TOKEN_ON,C&O,L1,40 +CompanyDoesNotPayDividend,C&O +PRICE_MOVES_LOG,C&O,90,E4,82,D4 +BuysTrainUsingSP,C&O,3G,IPO,100,TIW +PrivateCloses,TIW + +CompanyOperates,VGN,Paul +LaysTileAt,VGN,15,I4,S +CompanyRevenue,VGN,150 +CompanyDividesEarnings,VGN,150,110,40 +CompanyPaysOutFull,VGN,110 +Payout,Stephen,22,1,20 +Payout,Peter,22,1,20 +Payout,Paul,66,3,20 +PRICE_MOVES_LOG,VGN,75,E6,82,E5 + +EndOfOperatingRound,6.1 +ORWorthIncrease,Paul,6.1,255 +ORWorthIncrease,Peter,6.1,224 +ORWorthIncrease,Stephen,6.1,85 +Has,B&O,542 +Has,C&O,40 +Has,NW,202 +Has,RFP,0 +Has,SR,160 +Has,VGN,187 +Has,WM,0 +Has,Paul,289 +Has,Peter,215 +Has,Stephen,155 +START_OR,6.2 +ReceivesFor,Paul,10,REA +ReceivesFor,Paul,20,PY + +CompanyOperates,B&O,Peter +LaysTileAt,B&O,8,J5,N +CompanyRevenue,B&O,140 +CompanyPaysOutFull,B&O,140 +Payout,Stephen,14,1,10 +Payout,Peter,70,5,10 +Payout,Paul,28,2,10 +Payout,B&O,28,2,10 +PRICE_STAYS_LOG,B&O,165,J3 +BuysTrain,B&O,4,IPO,300 + +CompanyOperates,NW,Stephen +LAYS_TOKEN_ON,NW,K6,100 +CompanyRevenue,NW,120 +CompanyPaysOutFull,NW,120 +Payout,Stephen,36,3,10 +Payout,Paul,12,1,10 +Payout,NW,12,1,10 +PRICE_STAYS_LOG,NW,122,H4 + +CompanyOperates,RFP,Stephen +CompanyRevenue,RFP,100 +CompanyPaysOutFull,RFP,100 +Payout,Stephen,60,3,20 +PRICE_MOVES_LOG,RFP,90,D3,100,E3 + +CompanyOperates,SR,Peter +LaysTileAt,SR,57,H5,S +CompanyRevenue,SR,90 +CompanyPaysOutFull,SR,90 +Payout,Stephen,18,1,20 +Payout,Peter,54,3,20 +PRICE_MOVES_LOG,SR,90,D3,100,E3 + +CompanyOperates,WM,Stephen +LaysTileAt,WM,4,E2,SW +CompanyRevenue,WM,90 +CompanyPaysOutFull,WM,90 +Payout,Stephen,54,3,20 +PRICE_MOVES_LOG,WM,90,D3,100,E3 + +CompanyOperates,VGN,Paul +CompanyHasGrown,VGN,10 +PhaseDependentTrainLimitsSetTo,VGN,[4, 3, 2],3 +LaysTileAt,VGN,141,K2,NW +BuysPrivateFromFor,VGN,REA,Paul,60 +LaysBonusTokenOn,VGN,Rea,10,L3 +PrivateCloses,REA +CompanyRevenue,VGN,160 +CompanyDividesEarnings,VGN,160,120,40 +CompanyPaysOutFull,VGN,120 +Payout,Stephen,12,1,10 +Payout,Peter,12,1,10 +Payout,Paul,36,3,10 +PRICE_MOVES_LOG,VGN,82,E5,90,F5 + +CompanyOperates,C&O,Paul +LaysTileAt,C&O,8,M4,NW +CompanyRevenue,C&O,220 +CompanyDividesEarnings,C&O,220,160,60 +CompanyPaysOutFull,C&O,160 +Payout,Paul,96,3,20 +PRICE_MOVES_LOG,C&O,82,D4,90,E4 +BuysPrivateFromFor,C&O,PY,Paul,100 + +EndOfOperatingRound,6.2 +ORWorthIncrease,Paul,6.2,290 +ORWorthIncrease,Peter,6.2,174 +ORWorthIncrease,Stephen,6.2,272 +Has,B&O,270 +Has,C&O,0 +Has,NW,114 +Has,RFP,0 +Has,SR,160 +Has,VGN,167 +Has,WM,0 +Has,Paul,651 +Has,Peter,351 +Has,Stephen,349 +StartStockRound,7 +HasPriority,Paul +SELL_SHARE_LOG,Paul,10,B&O,165 +BUY_SHARE_LOG,Paul,20,SR,SR,100 +BUY_SHARE_LOG,Peter,10,VGN,VGN,90 +SELL_SHARES_LOG,VGN,4,10,40,VGN,360 +BUY_SHARE_LOG,Stephen,10,B&O,Pool,165 +BUY_SHARE_LOG,Paul,10,VGN,Pool,90 +BUY_SHARE_LOG,Peter,10,VGN,Pool,90 +BUY_SHARE_LOG,Stephen,20,C&O,C&O,90 +BUY_SHARE_LOG,Paul,10,VGN,Pool,90 +BUY_SHARE_LOG,Peter,10,VGN,Pool,90 +SELL_SHARE_LOG,Stephen,20,WM,100 +PRICE_MOVES_LOG,WM,100,E3,90,E4 +BUY_SHARE_LOG,Stephen,10,NW,NW,122 +SELL_SHARES_LOG,NW,4,10,40,NW,488 +BUY_SHARE_LOG,Paul,20,RFP,RFP,100 +PASSES,Peter +PASSES,Stephen +BUY_SHARE_LOG,Paul,20,WM,Pool,90 +PASSES,Peter +PASSES,Stephen +PASSES,Paul + +END_SR,7 +SoldOut,VGN +PRICE_MOVES_LOG,VGN,90,F5,100,F4 +Has,B&O,270 +Has,C&O,90 +Has,NW,724 +Has,RFP,100 +Has,SR,260 +Has,VGN,617 +Has,WM,0 +Has,Paul,346 +Has,Peter,81 +Has,Stephen,72 +START_OR,7.1 +ReceivesFor,C&O,20,PY + +CompanyOperates,B&O,Peter +LaysTileAt,B&O,7,F7,NW +CompanyRevenue,B&O,260 +CompanyPaysOutFull,B&O,260 +Payout,Paul,26,1,10 +Payout,Stephen,52,2,10 +Payout,Peter,130,5,10 +Payout,B&O,52,2,10 +PRICE_MOVES_LOG,B&O,165,J3,180,K3 + +CompanyOperates,NW,Stephen +LaysTileAt,NW,9,E4,NW +CompanyRevenue,NW,120 +CompanyPaysOutFull,NW,120 +Payout,Stephen,48,4,10 +Payout,Paul,12,1,10 +Payout,NW,60,5,10 +PRICE_STAYS_LOG,NW,122,H4 +BuysTrain,NW,4,IPO,300 +NewTrainAvailable,4/3G,5/4G + +CompanyOperates,VGN,Paul +LaysTileAt,VGN,9,J3,SW +LAYS_TOKEN_ON,VGN,M6,100 +CompanyRevenue,VGN,170 +CompanyDividesEarnings,VGN,170,130,40 +CompanyPaysOutFull,VGN,130 +Payout,Peter,52,4,10 +Payout,Stephen,13,1,10 +Payout,Paul,65,5,10 +PRICE_MOVES_LOG,VGN,100,F4,110,G4 + +CompanyOperates,RFP,Stephen +LaysTileAt,RFP,15,D3,NE +CompanyRevenue,RFP,100 +CompanyPaysOutFull,RFP,100 +Payout,Paul,20,1,20 +Payout,Stephen,60,3,20 +PRICE_MOVES_LOG,RFP,100,E3,110,F3 + +CompanyOperates,SR,Peter +LaysTileAt,SR,9,L7,NW +CompanyRevenue,SR,90 +CompanyPaysOutFull,SR,90 +Payout,Peter,54,3,20 +Payout,Stephen,18,1,20 +Payout,Paul,18,1,20 +PRICE_STAYS_LOG,SR,100,E3 + +CompanyOperates,C&O,Paul +LaysTileAt,C&O,6,H3,NW +CompanyRevenue,C&O,220 +CompanyDividesEarnings,C&O,220,160,60 +CompanyPaysOutFull,C&O,160 +Payout,Stephen,32,1,20 +Payout,Paul,96,3,20 +PRICE_MOVES_LOG,C&O,90,E4,100,F4 + +CompanyOperates,WM,Stephen +LaysTileAt,WM,82,F5,N +CompanyRevenue,WM,220 +CompanyWithholds,WM,220 +PRICE_MOVES_LOG,WM,90,E4,82,D4 + +EndOfOperatingRound,7.1 +ORWorthIncrease,Paul,7.1,334 +ORWorthIncrease,Peter,7.1,351 +ORWorthIncrease,Stephen,7.1,287 +Has,B&O,322 +Has,C&O,170 +Has,NW,484 +Has,RFP,100 +Has,SR,260 +Has,VGN,557 +Has,WM,220 +Has,Paul,583 +Has,Peter,317 +Has,Stephen,295 +START_OR,7.2 +ReceivesFor,C&O,20,PY + +CompanyOperates,B&O,Peter +LaysTileAt,B&O,7,B7,SE +CompanyRevenue,B&O,260 +CompanyPaysOutFull,B&O,260 +Payout,Paul,26,1,10 +Payout,Peter,130,5,10 +Payout,Stephen,52,2,10 +Payout,B&O,52,2,10 +PRICE_MOVES_LOG,B&O,180,K3,200,K2 + +CompanyOperates,NW,Stephen +LaysTileAt,NW,15,H5,S +CompanyRevenue,NW,240 +CompanyPaysOutFull,NW,240 +Payout,Paul,24,1,10 +Payout,Stephen,96,4,10 +Payout,NW,120,5,10 +PRICE_MOVES_LOG,NW,122,H4,135,H3 +BuysTrain,NW,3,RFP,603 + +CompanyOperates,VGN,Paul +LaysTileAt,VGN,58,I2,NE +CompanyRevenue,VGN,170 +CompanyDividesEarnings,VGN,170,130,40 +CompanyPaysOutFull,VGN,130 +Payout,Peter,52,4,10 +Payout,Stephen,13,1,10 +Payout,Paul,65,5,10 +PRICE_MOVES_LOG,VGN,110,G4,122,H4 +BuysTrain,VGN,4G,IPO,500 +FirstTrainBought,5/4G +StartOfPhase,5 +TrainsRusted,3/2G +CompanyHasGrown,C&O,10 +PhaseDependentTrainLimitsSetTo,C&O,[4, 3, 2],2 +CompanyHasGrown,RFP,10 +PhaseDependentTrainLimitsSetTo,RFP,[4, 3, 2],2 +CompanyHasGrown,SR,10 +PhaseDependentTrainLimitsSetTo,SR,[4, 3, 2],2 +CompanyHasGrown,WM,10 +PhaseDependentTrainLimitsSetTo,WM,[4, 3, 2],2 + +CompanyOperates,RFP,Stephen +LaysTileAt,RFP,170,K6,S +LAYS_TOKEN_ON,RFP,A8,100 +CompanyDoesNotPayDividend,RFP +PRICE_MOVES_LOG,RFP,110,F3,100,E3 +BuysTrain,RFP,5,IPO,500 + +CompanyOperates,C&O,Paul +LaysTileAt,C&O,63,L3,S +CompanyRevenue,C&O,240 +CompanyDividesEarnings,C&O,240,180,60 +CompanyPaysOutFull,C&O,180 +Payout,Paul,54,3,10 +Payout,Stephen,18,1,10 +PRICE_MOVES_LOG,C&O,100,F4,110,G4 + +CompanyOperates,SR,Peter +LaysTileAt,SR,170,M6,S +CompanyDoesNotPayDividend,SR +PRICE_MOVES_LOG,SR,100,E3,90,D3 +BuysTrain,SR,4,B&O,260 + +CompanyOperates,WM,Stephen +CorrectionModeActivate,Stephen,CORRECT_MAP +CorrectMapLaysTileAt,81,L5,S +CorrectionModeDeactivate,Stephen,CORRECT_MAP +LAYS_TOKEN_ON,WM,F1,40 +CompanyRevenue,WM,240 +CompanyDividesEarnings,WM,240,180,60 +CompanyPaysOutFull,WM,180 +Payout,Paul,18,1,10 +Payout,Stephen,36,2,10 +PRICE_MOVES_LOG,WM,82,D4,90,E4 + +EndOfOperatingRound,7.2 +ORWorthIncrease,Paul,7.2,298 +ORWorthIncrease,Peter,7.2,300 +ORWorthIncrease,Stephen,7.2,305 +Has,B&O,634 +Has,C&O,250 +Has,NW,1 +Has,RFP,103 +Has,SR,0 +Has,VGN,97 +Has,WM,240 +Has,Paul,770 +Has,Peter,499 +Has,Stephen,510 +StartStockRound,8 +HasPriority,Peter +BUY_SHARE_LOG,Peter,10,WM,WM,90 +SELL_SHARE_LOG,Stephen,10,C&O,110 +BUY_SHARE_LOG,Stephen,10,RFP,RFP,100 +BUY_SHARE_LOG,Paul,10,C&O,Pool,110 +BUY_SHARE_LOG,Peter,10,WM,WM,90 +BUY_SHARE_LOG,Stephen,10,WM,WM,90 +SELL_SHARES_LOG,WM,4,10,40,WM,360 +BUY_SHARE_LOG,Paul,10,C&O,C&O,110 +BUY_SHARE_LOG,Peter,10,WM,Pool,90 +BUY_SHARE_LOG,Stephen,10,WM,Pool,90 +BUY_SHARE_LOG,Paul,10,C&O,C&O,110 +SELL_SHARES_LOG,C&O,4,10,40,C&O,440 +BUY_SHARE_LOG,Peter,10,WM,Pool,90 +BUY_SHARE_LOG,Stephen,10,WM,Pool,90 +BUY_SHARE_LOG,Paul,10,B&O,Pool,200 +BUY_SHARE_LOG,Peter,10,SR,SR,90 +SELL_SHARES_LOG,SR,4,10,40,SR,360 +BUY_SHARE_LOG,Stephen,10,RFP,RFP,100 +SELL_SHARES_LOG,RFP,4,10,40,RFP,400 +BUY_SHARE_LOG,Paul,10,RFP,Pool,100 +PASSES,Peter +BUY_SHARE_LOG,Stephen,10,NW,Pool,135 +BUY_SHARE_LOG,Paul,10,SR,Pool,90 +PASSES,Peter +PASSES,Stephen +PASSES,Paul + +END_SR,8 +SoldOut,VGN +PRICE_MOVES_LOG,VGN,122,H4,135,H3 +SoldOut,WM +PRICE_MOVES_LOG,WM,90,E4,100,E3 +Has,B&O,634 +Has,C&O,910 +Has,NW,1 +Has,RFP,703 +Has,SR,450 +Has,VGN,97 +Has,WM,870 +Has,Paul,50 +Has,Peter,49 +Has,Stephen,15 +START_OR,8.1 +ReceivesFor,C&O,20,PY + +CompanyOperates,B&O,Peter +LaysTileAt,B&O,170,D7,SE +LAYS_TOKEN_ON,B&O,D7,100 +CompanyDoesNotPayDividend,B&O +PRICE_MOVES_LOG,B&O,200,K2,180,J2 +BuysTrain,B&O,5,IPO,500 +NewTrainAvailable,5/4G,6/5G + +CompanyOperates,NW,Stephen +LaysTileAt,NW,63,H5,S +CompanyRevenue,NW,240 +CompanyPaysOutFull,NW,240 +Payout,Paul,24,1,10 +Payout,Stephen,120,5,10 +Payout,NW,96,4,10 +PRICE_MOVES_LOG,NW,135,H3,150,I3 +BuysTrain,NW,5,RFP,97 + +CompanyOperates,VGN,Paul +LaysTileAt,VGN,63,I4,S +CompanyRevenue,VGN,360 +CompanyDividesEarnings,VGN,360,280,80 +CompanyPaysOutFull,VGN,280 +Payout,Stephen,28,1,10 +Payout,Paul,140,5,10 +Payout,Peter,112,4,10 +PRICE_MOVES_LOG,VGN,135,H3,150,I3 + +CompanyOperates,C&O,Paul +LaysTileAt,C&O,82,J5,S +CompanyRevenue,C&O,270 +CompanyDividesEarnings,C&O,270,210,60 +CompanyPaysOutFull,C&O,210 +Payout,Paul,126,6,10 +Payout,C&O,84,4,10 +PRICE_MOVES_LOG,C&O,110,G4,122,H4 +BuysTrain,C&O,5G,IPO,600 +FirstTrainBought,6/5G +StartOfPhase,6 + +CompanyOperates,RFP,Stephen +LaysTileAt,RFP,170,C8,S +CompanyDoesNotPayDividend,RFP +PRICE_MOVES_LOG,RFP,100,E3,90,D3 +BuysTrain,RFP,4D,IPO,800 +FirstTrainBought,4D +StartOfPhase,4D +TrainsRusted,4/3G + +CompanyOperates,WM,Stephen +LaysTileAt,WM,82,J3,SE +CompanyDoesNotPayDividend,WM +PRICE_MOVES_LOG,WM,100,E3,90,D3 +BuysTrain,WM,4D,IPO,800 + +CompanyOperates,SR,Peter +LaysTileAt,SR,546,F5,NW +CompanyDoesNotPayDividend,SR +PRICE_MOVES_LOG,SR,90,D3,82,C3 +PresidentAddsCash,SR,Peter,150 +BuysTrain,SR,6,IPO,600 + +EndOfOperatingRound,8.1 +ORWorthIncrease,Paul,8.1,366 +ORWorthIncrease,Peter,8.1,-150 +ORWorthIncrease,Stephen,8.1,90 +Has,B&O,34 +Has,C&O,474 +Has,NW,0 +Has,RFP,0 +Has,SR,0 +Has,VGN,177 +Has,WM,70 +Has,Paul,340 +Has,Peter,11 +Has,Stephen,163 +START_OR,8.2 +ReceivesFor,C&O,20,PY + +CompanyOperates,B&O,Peter +LaysTileAt,B&O,1172,D7,S +CompanyRevenue,B&O,320 +CompanyPaysOutFull,B&O,320 +Payout,Paul,64,2,10 +Payout,Stephen,64,2,10 +Payout,Peter,160,5,10 +Payout,B&O,32,1,10 +PRICE_MOVES_LOG,B&O,180,J2,200,K2 + +CompanyOperates,NW,Stephen +LaysTileAt,NW,170,E6,SE +CompanyRevenue,NW,290 +CompanyPaysOutFull,NW,290 +Payout,Paul,29,1,10 +Payout,Stephen,145,5,10 +Payout,NW,116,4,10 +PRICE_MOVES_LOG,NW,150,I3,165,J3 + +CompanyOperates,VGN,Paul +LaysTileAt,VGN,9,N7,NW +LAYS_TOKEN_ON,VGN,O8,100 +CompanyRevenue,VGN,370 +CompanyPaysOutFull,VGN,370 +Payout,Paul,185,5,10 +Payout,Stephen,37,1,10 +Payout,Peter,148,4,10 +PRICE_MOVES_LOG,VGN,150,I3,165,J3 + +CompanyOperates,C&O,Paul +LaysTileAt,C&O,1171,K6,S +LAYS_TOKEN_ON,C&O,M8,100 +CompanyRevenue,C&O,420 +CompanyDividesEarnings,C&O,420,320,100 +CompanyPaysOutFull,C&O,320 +Payout,Paul,192,6,10 +Payout,C&O,128,4,10 +PRICE_MOVES_LOG,C&O,122,H4,135,H3 + +CompanyOperates,RFP,Stephen +CorrectionModeActivate,Stephen,CORRECT_MAP +CorrectMapLaysTileAt,9,D5,NW +CorrectionModeDeactivate,Stephen,CORRECT_MAP +CompanyRevenue,RFP,600 +CompanyPaysOutFull,RFP,600 +Payout,Paul,120,2,10 +Payout,Stephen,300,5,10 +Payout,RFP,180,3,10 +PRICE_MOVES_LOG,RFP,90,D3,100,E3 + +CompanyOperates,WM,Stephen +LaysTileAt,WM,8,C4,SE +CompanyRevenue,WM,380 +CompanyPaysOutFull,WM,380 +Payout,Paul,38,1,10 +Payout,Stephen,190,5,10 +Payout,Peter,152,4,10 +PRICE_MOVES_LOG,WM,90,D3,100,E3 + +CompanyOperates,SR,Peter +CompanyRevenue,SR,300 +CompanyPaysOutFull,SR,300 +Payout,Paul,60,2,10 +Payout,Stephen,30,1,10 +Payout,Peter,120,4,10 +Payout,SR,90,3,10 +PRICE_MOVES_LOG,SR,82,C3,90,D3 + +EndOfOperatingRound,8.2 +ORWorthIncrease,Paul,8.2,942 +ORWorthIncrease,Peter,8.2,812 +ORWorthIncrease,Stephen,8.2,1004 +Has,B&O,66 +Has,C&O,622 +Has,NW,116 +Has,RFP,180 +Has,SR,90 +Has,VGN,77 +Has,WM,70 +Has,Paul,1028 +Has,Peter,591 +Has,Stephen,929 +START_OR,8.3 +ReceivesFor,C&O,20,PY + +CompanyOperates,B&O,Peter +CompanyRevenue,B&O,340 +CompanyPaysOutFull,B&O,340 +Payout,Paul,68,2,10 +Payout,Stephen,68,2,10 +Payout,Peter,170,5,10 +Payout,B&O,34,1,10 +PRICE_MOVES_LOG,B&O,200,K2,220,L2 + +CompanyOperates,NW,Stephen +CompanyRevenue,NW,300 +CompanyPaysOutFull,NW,300 +Payout,Paul,30,1,10 +Payout,Stephen,150,5,10 +Payout,NW,120,4,10 +PRICE_MOVES_LOG,NW,165,J3,180,K3 + +CompanyOperates,VGN,Paul +LaysTileAt,VGN,544,J5,NW +CompanyRevenue,VGN,390 +CompanyDividesEarnings,VGN,390,310,80 +CompanyPaysOutFull,VGN,310 +Payout,Paul,155,5,10 +Payout,Stephen,31,1,10 +Payout,Peter,124,4,10 +PRICE_MOVES_LOG,VGN,165,J3,180,K3 + +CompanyOperates,C&O,Paul +LaysTileAt,C&O,143,I2,SW +LAYS_TOKEN_ON,C&O,K6,100 +CompanyRevenue,C&O,420 +CompanyDividesEarnings,C&O,420,320,100 +CompanyPaysOutFull,C&O,320 +Payout,Paul,192,6,10 +Payout,C&O,128,4,10 +PRICE_MOVES_LOG,C&O,135,H3,150,I3 + +CompanyOperates,RFP,Stephen +LaysTileAt,RFP,9,G4,NW +CompanyRevenue,RFP,600 +CompanyPaysOutFull,RFP,600 +Payout,Paul,120,2,10 +Payout,Stephen,300,5,10 +Payout,RFP,180,3,10 +PRICE_MOVES_LOG,RFP,100,E3,110,F3 + +CompanyOperates,WM,Stephen +LaysTileAt,WM,8,F3,N +CompanyRevenue,WM,360 +CompanyPaysOutFull,WM,360 +Payout,Paul,36,1,10 +Payout,Stephen,180,5,10 +Payout,Peter,144,4,10 +PRICE_MOVES_LOG,WM,100,E3,110,F3 + +CompanyOperates,SR,Peter +CompanyRevenue,SR,300 +CompanyPaysOutFull,SR,300 +Payout,Paul,60,2,10 +Payout,Stephen,30,1,10 +Payout,Peter,120,4,10 +Payout,SR,90,3,10 +PRICE_MOVES_LOG,SR,90,D3,100,E3 + +EndOfOperatingRound,8.3 +ORWorthIncrease,Paul,8.3,931 +ORWorthIncrease,Peter,8.3,798 +ORWorthIncrease,Stephen,8.3,999 +Has,B&O,100 +Has,C&O,770 +Has,NW,236 +Has,RFP,360 +Has,SR,180 +Has,VGN,157 +Has,WM,70 +Has,Paul,1689 +Has,Peter,1149 +Has,Stephen,1688 +StartStockRound,9 +HasPriority,Peter +BUY_SHARE_LOG,Peter,10,RFP,Pool,110 +SELL_SHARE_LOG,Stephen,10,SR,100 +PRICE_MOVES_LOG,SR,100,E3,90,E4 +BUY_SHARE_LOG,Stephen,10,RFP,Pool,110 +BUY_SHARE_LOG,Paul,10,B&O,Pool,220 +BUY_SHARE_LOG,Peter,10,RFP,Pool,110 +BUY_SHARE_LOG,Stephen,10,C&O,Pool,150 +PASSES,Paul +PASSES,Peter +BUY_SHARE_LOG,Stephen,10,C&O,Pool,150 +PASSES,Paul +PASSES,Peter +PASSES,Stephen + +END_SR,9 +SoldOut,B&O +PRICE_MOVES_LOG,B&O,220,L2,245,L1 +SoldOut,VGN +PRICE_MOVES_LOG,VGN,180,K3,200,K2 +SoldOut,RFP +PRICE_MOVES_LOG,RFP,110,F3,122,F2 +SoldOut,WM +PRICE_MOVES_LOG,WM,110,F3,122,F2 +Has,B&O,100 +Has,C&O,770 +Has,NW,236 +Has,RFP,360 +Has,SR,180 +Has,VGN,157 +Has,WM,70 +Has,Paul,1469 +Has,Peter,929 +Has,Stephen,1378 +START_OR,9.1 +ReceivesFor,C&O,20,PY + +CompanyOperates,B&O,Peter +CompanyRevenue,B&O,340 +CompanyPaysOutFull,B&O,340 +Payout,Paul,102,3,10 +Payout,Stephen,68,2,10 +Payout,Peter,170,5,10 +PRICE_MOVES_LOG,B&O,245,L1,270,M1 + +CompanyOperates,VGN,Paul +LaysTileAt,VGN,83,G4,S +CompanyRevenue,VGN,380 +CompanyDividesEarnings,VGN,380,300,80 +CompanyPaysOutFull,VGN,300 +Payout,Paul,150,5,10 +Payout,Stephen,30,1,10 +Payout,Peter,120,4,10 +PRICE_MOVES_LOG,VGN,200,K2,220,L2 + +CompanyOperates,NW,Stephen +CompanyRevenue,NW,300 +CompanyPaysOutFull,NW,300 +Payout,Paul,30,1,10 +Payout,Stephen,150,5,10 +Payout,NW,120,4,10 +PRICE_MOVES_LOG,NW,180,K3,200,K2 + +CompanyOperates,C&O,Paul +LaysTileAt,C&O,14,H3,SW +CompanyRevenue,C&O,420 +CompanyDividesEarnings,C&O,420,320,100 +CompanyPaysOutFull,C&O,320 +Payout,Paul,192,6,10 +Payout,Stephen,64,2,10 +Payout,C&O,64,2,10 +PRICE_MOVES_LOG,C&O,150,I3,165,J3 + +CompanyOperates,RFP,Stephen +LAYS_TOKEN_ON,RFP,D7,100 +CompanyRevenue,RFP,600 +CompanyPaysOutFull,RFP,600 +Payout,Paul,120,2,10 +Payout,Stephen,360,6,10 +Payout,Peter,120,2,10 +PRICE_MOVES_LOG,RFP,122,F2,135,G2 + +CompanyOperates,WM,Stephen +CompanyRevenue,WM,360 +CompanyPaysOutFull,WM,360 +Payout,Paul,36,1,10 +Payout,Stephen,180,5,10 +Payout,Peter,144,4,10 +PRICE_MOVES_LOG,WM,122,F2,135,G2 + +CompanyOperates,SR,Peter +CompanyRevenue,SR,300 +CompanyPaysOutFull,SR,300 +BankIsBrokenReportText +Payout,Paul,60,2,10 +Payout,Peter,120,4,10 +Payout,SR,120,4,10 +PRICE_MOVES_LOG,SR,90,E4,100,F4 + +EndOfOperatingRound,9.1 +ORWorthIncrease,Paul,9.1,1034 +ORWorthIncrease,Peter,9.1,997 +ORWorthIncrease,Stephen,9.1,1195 +Has,B&O,100 +Has,C&O,954 +Has,NW,356 +Has,RFP,260 +Has,SR,300 +Has,VGN,237 +Has,WM,70 +Has,Paul,2159 +Has,Peter,1603 +Has,Stephen,2230 +START_OR,9.2 +ReceivesFor,C&O,20,PY + +CompanyOperates,B&O,Peter +CompanyRevenue,B&O,340 +CompanyPaysOutFull,B&O,340 +Payout,Paul,102,3,10 +Payout,Stephen,68,2,10 +Payout,Peter,170,5,10 +PRICE_MOVES_LOG,B&O,270,M1,300,N1 + +CompanyOperates,VGN,Paul +LaysTileAt,VGN,63,H3,S +CompanyRevenue,VGN,380 +CompanyDividesEarnings,VGN,380,300,80 +CompanyPaysOutFull,VGN,300 +Payout,Paul,150,5,10 +Payout,Stephen,30,1,10 +Payout,Peter,120,4,10 +PRICE_MOVES_LOG,VGN,220,L2,245,M2 + +CompanyOperates,NW,Stephen +CompanyRevenue,NW,300 +CompanyPaysOutFull,NW,300 +Payout,Paul,30,1,10 +Payout,Stephen,150,5,10 +Payout,NW,120,4,10 +PRICE_MOVES_LOG,NW,200,K2,220,L2 + +CompanyOperates,C&O,Paul +LaysTileAt,C&O,83,I6,SW +LAYS_FREE_TOKEN_ON,C&O,M6 +PrivateCloses,PY +CompanyRevenue,C&O,430 +CompanyDividesEarnings,C&O,430,330,100 +CompanyPaysOutFull,C&O,330 +Payout,Paul,198,6,10 +Payout,Stephen,66,2,10 +Payout,C&O,66,2,10 +PRICE_MOVES_LOG,C&O,165,J3,180,K3 +BuysTrain,C&O,4D,IPO,800 + +CompanyOperates,RFP,Stephen +CompanyRevenue,RFP,600 +CompanyPaysOutFull,RFP,600 +Payout,Paul,120,2,10 +Payout,Stephen,360,6,10 +Payout,Peter,120,2,10 +PRICE_MOVES_LOG,RFP,135,G2,150,H2 + +CompanyOperates,WM,Stephen +CompanyRevenue,WM,360 +CompanyPaysOutFull,WM,360 +Payout,Paul,36,1,10 +Payout,Stephen,180,5,10 +Payout,Peter,144,4,10 +PRICE_MOVES_LOG,WM,135,G2,150,H2 + +CompanyOperates,SR,Peter +CompanyRevenue,SR,300 +CompanyPaysOutFull,SR,300 +Payout,Paul,60,2,10 +Payout,Peter,120,4,10 +Payout,SR,120,4,10 +PRICE_MOVES_LOG,SR,100,F4,110,G4 + +EndOfOperatingRound,9.2 +ORWorthIncrease,Paul,9.2,1086 +ORWorthIncrease,Peter,9.2,1054 +ORWorthIncrease,Stephen,9.2,1234 +Has,B&O,100 +Has,C&O,340 +Has,NW,476 +Has,RFP,260 +Has,SR,420 +Has,VGN,317 +Has,WM,70 +Has,Paul,2855 +Has,Peter,2277 +Has,Stephen,3084 +START_OR,9.3 + +CompanyOperates,B&O,Peter +CompanyRevenue,B&O,340 +CompanyPaysOutFull,B&O,340 +Payout,Stephen,68,2,10 +Payout,Paul,102,3,10 +Payout,Peter,170,5,10 +PRICE_MOVES_LOG,B&O,300,N1,330,O1 + +CompanyOperates,VGN,Paul +CompanyRevenue,VGN,380 +CompanyDividesEarnings,VGN,380,300,80 +CompanyPaysOutFull,VGN,300 +Payout,Stephen,30,1,10 +Payout,Paul,150,5,10 +Payout,Peter,120,4,10 +PRICE_MOVES_LOG,VGN,245,M2,270,N2 + +CompanyOperates,NW,Stephen +CompanyRevenue,NW,300 +CompanyPaysOutFull,NW,300 +Payout,Paul,30,1,10 +Payout,Stephen,150,5,10 +Payout,NW,120,4,10 +PRICE_MOVES_LOG,NW,220,L2,245,M2 + +CompanyOperates,C&O,Paul +CompanyRevenue,C&O,830 +CompanyDividesEarnings,C&O,830,730,100 +CompanyPaysOutFull,C&O,730 +Payout,Stephen,146,2,10 +Payout,Paul,438,6,10 +Payout,C&O,146,2,10 +PRICE_MOVES_LOG,C&O,180,K3,200,K2 + +CompanyOperates,RFP,Stephen +CompanyRevenue,RFP,600 +CompanyPaysOutFull,RFP,600 +Payout,Paul,120,2,10 +Payout,Stephen,360,6,10 +Payout,Peter,120,2,10 +PRICE_MOVES_LOG,RFP,150,H2,165,I2 + +CompanyOperates,WM,Stephen +CompanyRevenue,WM,360 +CompanyPaysOutFull,WM,360 +Payout,Paul,36,1,10 +Payout,Stephen,180,5,10 +Payout,Peter,144,4,10 +PRICE_MOVES_LOG,WM,150,H2,165,I2 + +CompanyOperates,SR,Peter +CompanyRevenue,SR,300 +CompanyPaysOutFull,SR,300 +Payout,Paul,60,2,10 +Payout,Peter,120,4,10 +Payout,SR,120,4,10 +PRICE_MOVES_LOG,SR,110,G4,122,H4 + +EndOfOperatingRound,9.3 +ORWorthIncrease,Paul,9.3,1365 +ORWorthIncrease,Peter,9.3,1062 +ORWorthIncrease,Stephen,9.3,1349 +Has,B&O,100 +Has,C&O,586 +Has,NW,596 +Has,RFP,260 +Has,SR,540 +Has,VGN,397 +Has,WM,70 +Has,Paul,3791 +Has,Peter,2951 +Has,Stephen,4018 +GameOver +EoGWinnerStephen! +EoGFinalRanking : +1. 8388 Stephen +2. 8315 Paul +3. 7159 Peter