Skip to content

slik #130

Merged

slik #130

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 36 additions & 5 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import edu.ntnu.idi.idatt2003.g40.mappe.engine.Exchange;
import edu.ntnu.idi.idatt2003.g40.mappe.model.Player;
import edu.ntnu.idi.idatt2003.g40.mappe.model.SaveGame;
import edu.ntnu.idi.idatt2003.g40.mappe.model.Stock;
import edu.ntnu.idi.idatt2003.g40.mappe.service.StockFileParser;
import edu.ntnu.idi.idatt2003.g40.mappe.service.StockFileManager;
import edu.ntnu.idi.idatt2003.g40.mappe.service.GameStateLoader;
import edu.ntnu.idi.idatt2003.g40.mappe.service.SaveGameService;
import edu.ntnu.idi.idatt2003.g40.mappe.service.StockFileManager;
import edu.ntnu.idi.idatt2003.g40.mappe.service.StockFileParser;
import edu.ntnu.idi.idatt2003.g40.mappe.service.event.EventManager;
import edu.ntnu.idi.idatt2003.g40.mappe.utils.ConfigValues;
import edu.ntnu.idi.idatt2003.g40.mappe.utils.ThemeManager;
Expand Down Expand Up @@ -86,14 +88,19 @@ public void start(final Stage stage) throws Exception {
ViewManager viewManager = new ViewManager(stage, eventManager);

List<Stock> stocksInFile;
StockFileManager parser1 = new StockFileManager("src/main/resources/sp500.csv");
StockFileManager fileManager = new StockFileManager("src/main/resources/sp500.csv");

StockFileParser converter1 = new StockFileParser();
stocksInFile = converter1.getStocksFromStrings(parser1.readFile());
StockFileParser fileParser = new StockFileParser();
stocksInFile = fileParser.getStocksFromStrings(fileManager.readFile());

Exchange exchange = new Exchange("Exchange", stocksInFile);
Player player = new Player("Player 1", new BigDecimal("10000"));

// Bridges the save list to the live player + exchange. Subscribes
// to LOAD_SAVE; mutates state; publishes STATE_RESET for widgets.
GameStateLoader gameStateLoader = new GameStateLoader(
player, exchange, stocksInFile, eventManager);

// Main menu
MainMenuView mainMenuView = new MainMenuView();
new MainMenuController(mainMenuView, eventManager);
Expand Down Expand Up @@ -210,6 +217,30 @@ public void start(final Stage stage) throws Exception {
new InGameSettingsController(inGameSettingsView, eventManager, inGameView);
topBarController.setSettingsAction(inGameSettingsController::show);

// Auto-save the currently active save when the player quits back
// to the main menu. Silent if no save is active (i.e. the user
// got into the in-game scene without going through the save list).
topBarController.setOnQuitToMainMenu(() -> {
System.out.println("[auto-save] Quit triggered, attempting snapshot...");
SaveGame snapshot = gameStateLoader.snapshotActiveSave();
if (snapshot == null) {
System.out.println("[auto-save] No active save - nothing to write.");
return;
}
System.out.println("[auto-save] Snapshot built for '" + snapshot.getName()
+ "', balance=" + snapshot.getBalance()
+ ", week=" + snapshot.getWeek()
+ ", shares=" + snapshot.getOwnedShares().size()
+ ", txns=" + snapshot.getTransactions().size());
try {
saveGameService.saveGame(snapshot);
System.out.println("[auto-save] Wrote save '" + snapshot.getName() + "' to disk.");
} catch (Exception e) {
System.err.println("[auto-save] Failed: " + e.getMessage());
e.printStackTrace();
}
});

// Register all views
viewManager.addView(mainMenuView);
viewManager.addView(playGameView);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,55 @@ public ReadOnlyIntegerProperty weekProperty() {
return week.getReadOnlyProperty();
}

/**
* Sets the current week directly.
*
* <p>
* Used by the save-loading flow when applying a
* {@link edu.ntnu.idi.idatt2003.g40.mappe.model.SaveGame} to the
* exchange. The {@link IntegerProperty} fires a change event so any
* listeners that re-render on week changes refresh themselves.
* </p>
*
* @param newWeek the value to set the week to.
*
* @throws IllegalArgumentException if newWeek is below 1.
* */
public void setWeek(final int newWeek) throws IllegalArgumentException {
if (newWeek < 1) {
throw new IllegalArgumentException("Week must be at least 1!");
}
week.set(newWeek);
}

/**
* Resets every known stock on the exchange back to a baseline sales
* price.
*
* <p>
* Wipes the price history of each stock that has a matching entry
* in {@code baselinePrices} and re-seeds it with the given value.
* Used by the save-loading flow so the exchange the loaded save
* sees matches the baseline the save started from, regardless of
* how the simulation had drifted before.
* </p>
*
* @param baselinePrices map of symbol to the price to seed with.
* Symbols that aren't on this exchange are
* skipped.
* */
public void resetStocksTo(final Map<String, BigDecimal> baselinePrices) {
if (baselinePrices == null) {
return;
}
for (Map.Entry<String, BigDecimal> entry : baselinePrices.entrySet()) {
Stock stock = stockMap.get(entry.getKey());
if (stock != null) {
stock.resetPrices(entry.getValue());
}
}
}

/**
* Method for checking whether exchange has a stock.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,18 @@ public boolean add(final Transaction transaction) {
return transactions.add(transaction);
}

/**
* Removes every transaction from the archive.
*
* <p>Used by the save-loading flow when applying a
* {@link edu.ntnu.idi.idatt2003.g40.mappe.model.SaveGame} to an
* existing player, to make sure no transactions from the previous
* save remain.</p>
* */
public void clear() {
transactions.clear();
}

/**
* Checks whether the archive is empty.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package edu.ntnu.idi.idatt2003.g40.mappe.model;

import java.math.BigDecimal;

/**
* Immutable data record describing a single owned share in a {@link SaveGame}.
*
* <p>
* Holds just enough information to recreate a {@link Share} when the save is
* loaded: the stock symbol, the quantity owned and the original purchase
* price. The actual {@link Stock} object is looked up on the live
* {@link edu.ntnu.idi.idatt2003.g40.mappe.engine.Exchange} when the save is
* applied.
* </p>
*
* <p>
* Kept as a separate data type (rather than serialising {@link Share}
* directly) so the on-disk format stays decoupled from the runtime model
* and is easy to read/write through the hand-written JSON parser in
* {@link edu.ntnu.idi.idatt2003.g40.mappe.service.SaveGameService}.
* </p>
*/
public final class OwnedShareData {

/** Stock symbol this share is for. */
private final String symbol;

/** Quantity of the stock owned. */
private final BigDecimal quantity;

/** Price per unit at the time of purchase. */
private final BigDecimal purchasePrice;

/**
* Constructor.
*
* @param symbol the stock symbol.
* @param quantity the quantity owned.
* @param purchasePrice the price per unit at purchase time.
*
* @throws IllegalArgumentException if any argument is null.
* */
public OwnedShareData(final String symbol,
final BigDecimal quantity,
final BigDecimal purchasePrice)
throws IllegalArgumentException {
if (symbol == null || quantity == null || purchasePrice == null) {
throw new IllegalArgumentException("Invalid owned share data!");
}
this.symbol = symbol;
this.quantity = quantity;
this.purchasePrice = purchasePrice;
}

/**
* Getter method for the symbol.
*
* @return the stock symbol.
* */
public String getSymbol() {
return symbol;
}

/**
* Getter method for the quantity.
*
* @return the quantity owned.
* */
public BigDecimal getQuantity() {
return quantity;
}

/**
* Getter method for the purchase price.
*
* @return the price per unit at purchase time.
* */
public BigDecimal getPurchasePrice() {
return purchasePrice;
}
}
34 changes: 34 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/model/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,40 @@ public void withdrawMoney(final BigDecimal amount)
updateObservableProperties();
}

/**
* Replaces the players current balance with the given value.
*
* <p>
* Used by the save-loading flow when applying a {@link SaveGame} to
* an existing player. Unlike {@link #addMoney} / {@link #withdrawMoney},
* this fully overwrites the current value rather than adjusting it.
* </p>
*
* @param newMoney the value to set the balance to.
*
* @throws IllegalArgumentException if newMoney is null.
* */
public void setMoney(final BigDecimal newMoney) throws IllegalArgumentException {
if (newMoney == null) {
throw new IllegalArgumentException("Money cannot be null!");
}
money = newMoney;
}

/**
* Re-publishes the players current money and net-worth to the
* {@link FloatProperty} listeners.
*
* <p>
* Used after the save-loading flow has mutated the player state
* (money, portfolio, archive) so listeners across the UI refresh.
* </p>
* */
public void refreshProperties() {
networthAsFloatProp.setValue(getNetWorth().floatValue());
moneyAsFloatProp.setValue(money);
}

/**
* Returns the players portfolio.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,18 @@ public List<Share> getShares() {
return List.copyOf(shares.values());
}

/**
* Removes every share from the portfolio.
*
* <p>Used by the save-loading flow when applying a
* {@link edu.ntnu.idi.idatt2003.g40.mappe.model.SaveGame} to an
* existing player, to make sure no shares from the previous save
* remain.</p>
* */
public void clear() {
shares.clear();
}

/**
* Returns an immutable snapshot of all shares whose
* stock symbol matches the given symbol.
Expand Down
Loading