From: Erik V. <ev...@us...> - 2009-05-04 20:29:32
|
Update of /cvsroot/rails/18xx/rails/game/specific/_1856 In directory 23jxhf1.ch3.sourceforge.com:/tmp/cvs-serv29969/rails/game/specific/_1856 Modified Files: CGRFormationRound.java PublicCompany_1856.java OperatingRound_1856.java Added Files: GameUIManager_1856.java Log Message: 1856 CGR formation round --- NEW FILE: GameUIManager_1856.java --- package rails.game.specific._1856; import rails.game.action.PossibleActions; import rails.ui.swing.ActionPerformer; import rails.ui.swing.GameUIManager; public class GameUIManager_1856 extends GameUIManager { /* protected void updateStatus(ActionPerformer activeWindow) { PossibleActions possibleActions = PossibleActions.getInstance(); } */ } Index: OperatingRound_1856.java =================================================================== RCS file: /cvsroot/rails/18xx/rails/game/specific/_1856/OperatingRound_1856.java,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** OperatingRound_1856.java 4 Feb 2009 20:36:39 -0000 1.8 --- OperatingRound_1856.java 4 May 2009 20:29:14 -0000 1.9 *************** *** 2,5 **** --- 2,7 ---- import java.util.ArrayList; + import java.util.Arrays; + import java.util.Iterator; import java.util.List; *************** *** 432,436 **** // End of CGRFormationRound finalLoanRepaymentPending.set(false); ! if (setNextOperatingCompany(false)) { setStep(STEP_INITIAL); } else { --- 434,439 ---- // End of CGRFormationRound finalLoanRepaymentPending.set(false); ! resetOperatingCompanies(); ! if (operatingCompany != null) { setStep(STEP_INITIAL); } else { *************** *** 442,445 **** --- 445,496 ---- } + private void resetOperatingCompanies() { + + int lastOperatingCompanyIndex = operatingCompanyIndex; + // Find the first company that has not yet operated + // and is not closed. + while (setNextOperatingCompany(false) + && getOperatingCompany().isClosed()); + + List<PublicCompanyI> companies + = new ArrayList<PublicCompanyI>(Arrays.asList(operatingCompanyArray)); + PublicCompanyI company; + PublicCompanyI cgr = companyManager.getCompanyByName("CGR"); + int index = 0; + boolean cgrCanOperate = true; + for (Iterator<PublicCompanyI> it = companies.iterator(); + it.hasNext(); ) { + company = it.next(); + if (company.isClosed()) { + if (index <= lastOperatingCompanyIndex) cgrCanOperate = false; + it.remove(); + } + } + + if (operatingCompany != null) { + operatingCompanyIndex = companies.indexOf(operatingCompany); + } + + for (PublicCompanyI c : companies) { + log.debug("Now operating: "+c.getName()); + } + + String message; + if (cgrCanOperate) { + operatingCompanyIndex = Math.max (0, operatingCompanyIndex); + companies.add(operatingCompanyIndex, cgr); + operatingCompany = cgr; + message = LocalText.getText("CanOperate", cgr.getName()); + } else { + message = LocalText.getText("CannotOperate", cgr.getName()); + } + ReportBuffer.add (message); + DisplayBuffer.add(message); + + operatingCompanyArray = companies.toArray(new PublicCompanyI[0]); + operatingCompanyIndexObject.set(operatingCompanyIndex); + + log.debug ("Next operating company: "+operatingCompany.getName()); + } @Override Index: PublicCompany_1856.java =================================================================== RCS file: /cvsroot/rails/18xx/rails/game/specific/_1856/PublicCompany_1856.java,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** PublicCompany_1856.java 24 Jan 2009 15:10:29 -0000 1.2 --- PublicCompany_1856.java 4 May 2009 20:29:14 -0000 1.3 *************** *** 1,7 **** package rails.game.specific._1856; ! import rails.game.PublicCompany; ! import rails.game.StockSpaceI; ! import rails.game.TrainI; import rails.game.state.IntegerState; --- 1,5 ---- package rails.game.specific._1856; ! import rails.game.*; import rails.game.state.IntegerState; *************** *** 9,23 **** private IntegerState trainNumberAvailableAtStart; ! private IntegerState moneyInEscrow; ! public void start(StockSpaceI startSpace) { ! super.start(startSpace); ! ! TrainI nextAvailableTrain = gameManager.getTrainManager().getAvailableNewTrains().get(0); int trainNumber; ! try { trainNumber = Integer.parseInt(nextAvailableTrain.getName()); } catch (NumberFormatException e) { --- 7,25 ---- private IntegerState trainNumberAvailableAtStart; ! private IntegerState moneyInEscrow; ! ! /** Used for CGR */ ! private boolean hadPermanentTrain = false; ! ! @Override public void start(StockSpaceI startSpace) { ! super.start(startSpace); ! ! TrainI nextAvailableTrain = gameManager.getTrainManager().getAvailableNewTrains().get(0); int trainNumber; ! try { trainNumber = Integer.parseInt(nextAvailableTrain.getName()); } catch (NumberFormatException e) { *************** *** 27,43 **** = new IntegerState (name+"_trainAtStart"); trainNumberAvailableAtStart.set(trainNumber); ! if (trainNumber == 6) { this.capitalisation = CAPITALISE_FULL; } ! moneyInEscrow = new IntegerState (name+"_moneyInEscrow", 0); } ! public int getTrainNumberAvailableAtStart () { return trainNumberAvailableAtStart.intValue(); } ! public void setMoneyInEscrow (int amount) { moneyInEscrow.set(amount); --- 29,45 ---- = new IntegerState (name+"_trainAtStart"); trainNumberAvailableAtStart.set(trainNumber); ! if (trainNumber == 6) { this.capitalisation = CAPITALISE_FULL; } ! moneyInEscrow = new IntegerState (name+"_moneyInEscrow", 0); } ! public int getTrainNumberAvailableAtStart () { return trainNumberAvailableAtStart.intValue(); } ! public void setMoneyInEscrow (int amount) { moneyInEscrow.set(amount); *************** *** 47,53 **** moneyInEscrow.add(amount); } ! public int getMoneyInEscrow () { return moneyInEscrow.intValue(); } } --- 49,67 ---- moneyInEscrow.add(amount); } ! public int getMoneyInEscrow () { return moneyInEscrow.intValue(); } + + public boolean hadPermanentTrain() { + return hadPermanentTrain; + } + + @Override + public void buyTrain(TrainI train, int price) { + super.buyTrain (train, price); + if (train.getType().isPermanent()) hadPermanentTrain = true; + } + + } Index: CGRFormationRound.java =================================================================== RCS file: /cvsroot/rails/18xx/rails/game/specific/_1856/CGRFormationRound.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** CGRFormationRound.java 4 Feb 2009 20:36:39 -0000 1.1 --- CGRFormationRound.java 4 May 2009 20:29:14 -0000 1.2 *************** *** 4,18 **** import rails.game.*; ! import rails.game.action.RepayLoans; import rails.game.move.CashMove; import rails.util.LocalText; ! public class CGRFormationRound extends OperatingRound { ! /* This isn't really a stock round, but it must subclass one of the ! * three base types, otherwise the not-subclassable GameUIManager ! * cannot handle it. StockRound has been chosen because the UI ! * should show the StatusWindow. ! */ private Player startingPlayer; --- 4,17 ---- import rails.game.*; ! import rails.game.action.*; import rails.game.move.CashMove; + import rails.game.move.MoveSet; + import rails.game.state.IntegerState; import rails.util.LocalText; ! public class CGRFormationRound extends SwitchableUIRound { ! ! private final String CGRNAME = "CGR"; private Player startingPlayer; *************** *** 21,24 **** --- 20,35 ---- private int maxLoansToRepayByPresident = 0; private List<PublicCompanyI> mergingCompanies = new ArrayList<PublicCompanyI>(); + private PublicCompanyI cgr = gameManager.getCompanyManager().getCompanyByName(CGRNAME); + private String cgrName = CGRNAME; + private List<TrainI> trainsToDiscardFrom = null; + private boolean forcedTrainDiscard = true; + private List<ExchangeableToken> tokensToExchangeFrom = null; + private List<BaseToken> nonHomeTokens = null; + + private IntegerState stepObject = new IntegerState ("CGRFormStep", 0); + + public static final int STEP_REPAY_LOANS = 1; + public static final int STEP_DISCARD_TRAINS = 2; + public static final int STEP_EXCHANGE_TOKENS = 3; public CGRFormationRound (GameManagerI gameManager) { *************** *** 32,35 **** --- 43,47 ---- public Class<? extends RoundI> getRoundTypeForUI () { return StockRound.class; + //return OperatingRound.class; } *************** *** 60,67 **** --- 72,89 ---- } + setStep(STEP_REPAY_LOANS); + setCurrentPlayer (startingPlayer); setNextCompanyNeedingPresidentIntervention(); } + + private void setStep(int step) { + stepObject.set(step); + } + + private int getStep() { + return stepObject.intValue(); + } private boolean setNextCompanyNeedingPresidentIntervention () { *************** *** 164,181 **** public boolean setPossibleActions() { ! RepayLoans action = new RepayLoans (currentCompany, 0, ! maxLoansToRepayByPresident, ! currentCompany.getValuePerLoan()); ! possibleActions.add(action); ! operatingCompany = currentCompany; return true; } - @Override protected boolean repayLoans (RepayLoans action) { ! boolean result = super.repayLoans(action); ! if (action.getCompany().getCurrentNumberOfLoans() > 0) { mergingCompanies.add(currentCompany); String message = LocalText.getText("WillMergeInto", --- 186,252 ---- public boolean setPossibleActions() { ! int step = getStep(); ! if (step == STEP_REPAY_LOANS) { ! RepayLoans action = new RepayLoans (currentCompany, 0, ! maxLoansToRepayByPresident, ! currentCompany.getValuePerLoan()); ! possibleActions.add(action); ! roundTypeForUI = StockRound_1856.class; ! } else if (step == STEP_EXCHANGE_TOKENS) { ! int numberToExchange = cgr.getNumberOfFreeBaseTokens(); ! ExchangeTokens action = new ExchangeTokens (tokensToExchangeFrom, ! numberToExchange, numberToExchange); ! action.setCompany(cgr); ! possibleActions.add(action); ! roundTypeForUI = OperatingRound_1856.class; ! } else if (step == STEP_DISCARD_TRAINS) { ! DiscardTrain action = new DiscardTrain (cgr, ! trainsToDiscardFrom, forcedTrainDiscard); ! possibleActions.add(action); ! roundTypeForUI = OperatingRound_1856.class; ! } return true; } protected boolean repayLoans (RepayLoans action) { + + // TODO Validation skipped for now... ! MoveSet.start(true); ! ! PublicCompanyI company = action.getCompany(); ! int numberRepaid = action.getNumberRepaid(); ! int repayment = numberRepaid * company.getValuePerLoan(); ! ! if (repayment > 0) { ! ! int repaymentByCompany = Math.min (repayment, company.getCash()); ! int repaymentByPresident = repayment - repaymentByCompany; ! ! company.addLoans(-numberRepaid); ! if (repaymentByCompany > 0) { ! new CashMove (company, null, repaymentByCompany); ! ReportBuffer.add (LocalText.getText("CompanyRepaysLoans", ! company.getName(), ! Bank.format(repaymentByCompany), ! Bank.format(repayment), ! numberRepaid, ! Bank.format(company.getValuePerLoan()))); ! } ! if (repaymentByPresident > 0) { ! Player president = company.getPresident(); ! new CashMove (president, null, repaymentByPresident); ! ReportBuffer.add (LocalText.getText("CompanyRepaysLoansWithPresCash", ! company.getName(), ! Bank.format(repaymentByPresident), ! Bank.format(repayment), ! numberRepaid, ! Bank.format(company.getValuePerLoan()), ! president.getName())); ! } ! } ! ! if (action.getCompany().getCurrentNumberOfLoans() > 0) { mergingCompanies.add(currentCompany); String message = LocalText.getText("WillMergeInto", *************** *** 184,197 **** DisplayBuffer.add(message, true); ReportBuffer.add(message); } ! if (!setNextCompanyNeedingPresidentIntervention()) { gameManager.nextRound(this); } ! return result; } --- 255,680 ---- DisplayBuffer.add(message, true); ReportBuffer.add(message); + + } + + return true; + + } + + private void formCGR () { + + Player player; + Portfolio portfolio; + int count, cgrSharesUsed, oldShares, newShares; + PublicCertificateI cgrCert, poolCert; + List<PublicCertificateI> certs = new ArrayList<PublicCertificateI>(); + Portfolio scrapHeap = Bank.getScrapHeap(); + Portfolio pool = Bank.getPool(); + Portfolio unavailable = Bank.getUnavailable(); + Portfolio ipo = Bank.getIpo(); + Player temporaryPresident = null; + Player newPresident = null; + Player firstCGRowner = null; + int maxShares = 0; + + // Exchange the player shares + setCurrentPlayer(startingPlayer); + cgrSharesUsed = 0; + + do { + player = getCurrentPlayer(); + portfolio = player.getPortfolio(); + oldShares = newShares = 0; + certs.clear(); + poolCert = null; + + for (PublicCertificateI cert : player.getPortfolio().getCertificates()) { + if (mergingCompanies.contains(cert.getCompany())) { + certs.add((cert)); + oldShares++; + if (cert.isPresidentShare()) { + oldShares++; + } + } + } + if (oldShares > 0) { + + count = oldShares; + if (count >= 4 && temporaryPresident == null && cgrSharesUsed <= 18) { + cgrCert = cgr.getPresidentsShare(); + cgrCert.moveTo(portfolio); + count -= 4; + cgrSharesUsed += 2; + newShares += 2; + temporaryPresident = player; + } + while (count >= 2 && cgrSharesUsed <= 19) { + cgrCert = unavailable.findCertificate(cgr, false); + cgrCert.moveTo(portfolio); + count -= 2; + cgrSharesUsed++; + newShares++; + } + + String message = LocalText.getText("HasMergedShares", + player.getName(), + oldShares, + newShares, + "CGR"); + DisplayBuffer.add(message, false); + ReportBuffer.add(message); + + if (count == 1) { + // Should work OK even if this is a president's share. + // In the pool we will treat all certs equally. + poolCert = certs.get(certs.size()-1); + poolCert.moveTo(pool); + certs.remove(poolCert); + + message = LocalText.getText("HasPutShareInPool", + player.getName()); + DisplayBuffer.add(message, false); + ReportBuffer.add(message); + + } + // Note: old shares are removed when company is closed + + if (firstCGRowner == null) firstCGRowner = player; + + // Check for presidency + if (newShares > maxShares) { + maxShares = newShares; + newPresident = player; + } + } + + gameManager.setNextPlayer(); + + } while (getCurrentPlayer() != startingPlayer); + + // Exchange the pool shares + certs.clear(); + oldShares = newShares = 0; + + for (PublicCertificateI cert : pool.getCertificates()) { + if (mergingCompanies.contains(cert.getCompany())) { + certs.add((cert)); + oldShares++; + } + } + count = oldShares; + while (count >= 2 && cgrSharesUsed <= 19) { + cgrCert = unavailable.findCertificate(cgr, false); + cgrCert.moveTo(pool); + count -= 2; + cgrSharesUsed++; + newShares++; } ! String message = LocalText.getText("HasMergedShares", ! LocalText.getText("POOL"), ! oldShares, ! newShares, ! "CGR"); ! DisplayBuffer.add(message); ! ReportBuffer.add(message); ! ! for (PublicCertificateI discardCert : certs) { ! discardCert.moveTo(scrapHeap); ! } ! ! log.info(cgrSharesUsed+" CGR shares are now in play"); ! // Move the remaining CGR shares to the ipo. ! // Must clone the list first ! certs = new ArrayList<PublicCertificateI>(unavailable.getCertificatesPerCompany("CGR")); ! for (PublicCertificateI cert : certs) { ! cert.moveTo(ipo); ! } ! ! // Assign the new president ! if (temporaryPresident != newPresident) { ! temporaryPresident.getPortfolio().swapPresidentCertificate(cgr, ! newPresident.getPortfolio()); ! } ! ! newPresident.getPortfolio().getShareModel(cgr).setShare(); ! message = LocalText.getText("IS_NOW_PRES_OF", ! newPresident.getName(), cgrName); ! ReportBuffer.add(message); ! DisplayBuffer.add(message); ! ! // Collect the old token spots, and move cash and trains ! List<BaseToken> homeTokens = new ArrayList<BaseToken>(); ! nonHomeTokens = new ArrayList<BaseToken>(); ! BaseToken bt; ! MapHex hex; ! City city; ! for (PublicCompanyI comp : mergingCompanies) { ! for (TokenI token :comp.getTokens()) { ! if (token instanceof BaseToken) { ! bt = (BaseToken) token; ! if (!bt.isPlaced()) continue; ! city = (City) bt.getHolder(); ! hex = city.getHolder(); ! if (hex == comp.getHomeHex()) { ! homeTokens.add(bt); ! } else { ! nonHomeTokens.add(bt); ! } ! } ! } ! ! if (comp.getCash() > 0) { ! new CashMove (comp, cgr, comp.getCash()); ! } ! List<TrainI> trains = new ArrayList<TrainI> (comp.getPortfolio().getTrainList()); ! for (TrainI train : trains) { ! train.moveTo(cgr.getPortfolio()); ! } ! } ! ! // Replace the home tokens ! for (BaseToken token : homeTokens) { ! city = (City) token.getHolder(); ! hex = city.getHolder(); ! token.moveTo(token.getCompany()); ! if (hex.layBaseToken(cgr, city.getNumber())) { ! /* TODO: the false return value must be impossible. */ ! ReportBuffer.add(LocalText.getText("ExchangesBaseToken", ! cgrName, token.getCompany().getName(), ! city.getName())); ! cgr.layBaseToken(hex, 0); ! } ! } ! ! // Clean up any non-home tokens on cities now having a CGR token ! for (BaseToken token : new ArrayList<BaseToken>(nonHomeTokens)) { ! city = (City) token.getHolder(); ! hex = city.getHolder(); ! List<BaseToken> otherTokens = hex.getBaseTokens(); ! if (otherTokens != null) { ! for (BaseToken token2 : otherTokens) { ! if (token2.getCompany() == cgr) { ! ReportBuffer.add(LocalText.getText("DiscardsBaseToken", ! cgrName, token.getCompany().getName(), ! city.getName())); ! token.moveTo(token.getCompany()); ! nonHomeTokens.remove(token); ! break; ! } ! } ! } ! } ! ! // Prepare replacing the other tokens, if possible ! if (homeTokens.size() + nonHomeTokens.size() > cgr.getNumberOfBaseTokens()) { ! // CGR cannot replace all tokens, must choose ! // First collect old names per city ! Map<String, String> oldTokens = new HashMap<String, String>(); ! String cityName; ! for (BaseToken token : nonHomeTokens) { ! if (token.getHolder() instanceof City) { ! cityName = token.getHolder().getName(); ! if (oldTokens.containsKey(cityName)) { ! oldTokens.put(cityName, ! oldTokens.get(cityName)+","+token.getCompany().getName()); ! } else { ! oldTokens.put(cityName, token.getCompany().getName()); ! } ! } ! } ! // Then create list of exchange spots. Sort it on hexname/city number ! tokensToExchangeFrom = new ArrayList<ExchangeableToken>(); ! for (String key : new TreeSet<String> (oldTokens.keySet())) { ! tokensToExchangeFrom.add(new ExchangeableToken( ! key, oldTokens.get(key))); ! } ! } else { ! executeExchangeTokens (nonHomeTokens); ! } + // Close the absorbed companies and float the CGR + for (PublicCompanyI comp : mergingCompanies) { + comp.setClosed(); + } + cgr.start(100); // TODO: assign correct starting price + cgr.setFloated(); + + // Check the trains, autodiscard any excess non-permanent trains + int trainLimit = cgr.getTrainLimit(gameManager.getCurrentPlayerIndex()); + List<TrainI> trains = cgr.getPortfolio().getTrainList(); + outer: while (cgr.getNumberOfTrains() > trainLimit) { + for (TrainI train : trains) { + if (!train.getType().isPermanent()) { + train.moveTo(pool); + ReportBuffer.add(LocalText.getText("CompanyDiscardsTrain", + cgrName, train.getName())); + continue outer; + } + } + break; + } + } + + private void executeExchangeTokens (List<BaseToken> exchangedTokens) { + City city; + MapHex hex; + for (BaseToken token : exchangedTokens) { + // Remove old token + city = (City) token.getHolder(); + hex = city.getHolder(); + token.moveTo(token.getCompany()); + // Replace it with a CGR token + if (hex.layBaseToken(cgr, city.getNumber())) { + cgr.layBaseToken(hex, 0); + //log.debug("CGR exchanges a token at "+hex.getName()+" "+hex.getCityName()); + } else { + log.error("Error in laying CGR token on "+hex.getName()+" "+hex.getCityName()); + } + } + } + + public boolean process (PossibleAction action) { + + boolean result = false; + + if (action instanceof RepayLoans) { + result = repayLoans((RepayLoans)action); + } else if (action instanceof DiscardTrain) { + result = discardTrain((DiscardTrain)action); + } else if (action instanceof ExchangeTokens) { + result = exchangeTokens ((ExchangeTokens)action); + } + if (!result) return false; + + if (getStep() == STEP_REPAY_LOANS) { + + if (setNextCompanyNeedingPresidentIntervention()) { + return true; + } + + if (!mergingCompanies.isEmpty()) { + formCGR(); + setStep (STEP_EXCHANGE_TOKENS); + } + } + + if (getStep() == STEP_EXCHANGE_TOKENS) { + + if (action instanceof ExchangeTokens) { + tokensToExchangeFrom = null; + } else if (tokensToExchangeFrom != null + && !tokensToExchangeFrom.isEmpty()) { + return true; + } + setStep (STEP_DISCARD_TRAINS); + } + + if (getStep() == STEP_DISCARD_TRAINS) { + + if (checkForTrainsToDiscard()) return true; gameManager.nextRound(this); } ! return true; ! } ! ! ! private boolean checkForTrainsToDiscard () { + // Check if CGR must discard trains + if (cgr.getNumberOfTrains() > cgr.getCurrentTrainLimit()) { + log.debug("CGR must discard trains"); + if (getStep() != STEP_DISCARD_TRAINS) { + setStep(STEP_DISCARD_TRAINS); + } + trainsToDiscardFrom = cgr.getPortfolio().getTrainList(); + forcedTrainDiscard = true; + return true; + } else { + // Check if CGR still has non-permanent trains + // these may be discarded voluntarily + trainsToDiscardFrom = new ArrayList<TrainI>(); + for (TrainI train : cgr.getPortfolio().getTrainList()) { + if (!train.getType().isPermanent()) { + trainsToDiscardFrom.add(train); + } + } + if (!trainsToDiscardFrom.isEmpty()) { + if (getStep() != STEP_DISCARD_TRAINS) { + setStep(STEP_DISCARD_TRAINS); + } + forcedTrainDiscard = false; + return true; + } + } + return false; + } + + public boolean discardTrain(DiscardTrain action) { + + TrainI train = action.getDiscardedTrain(); + PublicCompanyI company = action.getCompany(); + String companyName = company.getName(); + + String errMsg = null; + + // Dummy loop to enable a quick jump out. + while (true) { + // Checks + // Must be CGR + if (company != cgr) { + errMsg = LocalText.getText("WrongCompany", + company.getName(), + cgrName); + break; + } + // Must be correct step + if (getStep() != STEP_DISCARD_TRAINS) { + errMsg = LocalText.getText("WrongActionNoDiscardTrain"); + break; + } + + if (train == null && action.isForced()) { + errMsg = LocalText.getText("NoTrainSpecified"); + break; + } + + // Does the company own such a train? + + if (train != null && !company.getPortfolio().getTrainList().contains(train)) { + errMsg = + LocalText.getText("CompanyDoesNotOwnTrain", + company.getName(), + train.getName() ); + break; + } + + break; + } + if (errMsg != null) { + DisplayBuffer.add(LocalText.getText("CannotDiscardTrain", + companyName, + train.getName(), + errMsg )); + return false; + } + + /* End of validation, start of execution */ + MoveSet.start(true); + + if (train != null) { + + if (action.isForced()) MoveSet.setLinkedToPrevious(); + + train.moveTo(Bank.getPool()); + ReportBuffer.add(LocalText.getText("CompanyDiscardsTrain", + companyName, + train.getName() )); + + } + + return true; } *************** *** 201,203 **** --- 684,687 ---- } + } |