Skip to content

Commit

Permalink
slik
Browse files Browse the repository at this point in the history
  • Loading branch information
EspenTinius committed May 25, 2026
1 parent f7b2825 commit 5b7728d
Show file tree
Hide file tree
Showing 20 changed files with 1,488 additions and 36 deletions.
31 changes: 31 additions & 0 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,9 +2,11 @@

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.FileConverter;
import edu.ntnu.idi.idatt2003.g40.mappe.service.FileParser;
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.event.EventManager;
import edu.ntnu.idi.idatt2003.g40.mappe.utils.ConfigValues;
Expand Down Expand Up @@ -94,6 +96,11 @@ public void start(final Stage stage) throws Exception {
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 IntegerProperty weekProperty() {
return week;
}

/**
* 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 @@ -33,6 +33,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 @@ -123,6 +123,40 @@ public void withdrawMoney(final BigDecimal amount) {
money = money.subtract(amount);
}

/**
* 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 @@ -72,6 +72,18 @@ public List<Share> getShares() {
return List.copyOf(shares);
}

/**
* 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

0 comments on commit 5b7728d

Please sign in to comment.