Skip to content

Commit

Permalink
fixed gamebraking bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
peretr committed May 21, 2026
1 parent b533803 commit fd35068
Show file tree
Hide file tree
Showing 23 changed files with 177 additions and 109 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>6.0.1</version>
<version>5.11.4</version>
</dependency>

</dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ public void stopGame() {
/**
* Returns whether the current game state is a weekend.
*
* @return {@code true} if the game state is not {@link GameState#WORKDAY}.
* @return {@code true} if the game state is {@link GameState#FREEDAY}.
*/
public boolean isWeekend() {
return gameState != GameState.WORKDAY;
return gameState == GameState.FREEDAY;
}
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
package edu.ntnu.idi.idatt2003.gruppe42.controller;

import edu.ntnu.idi.idatt2003.gruppe42.controller.appcontrollers.AppController;
import edu.ntnu.idi.idatt2003.gruppe42.model.Exchange;
import edu.ntnu.idi.idatt2003.gruppe42.model.Stock;
import edu.ntnu.idi.idatt2003.gruppe42.model.StockFileHandler;
import edu.ntnu.idi.idatt2003.gruppe42.model.exceptions.StockFileParseException;
import java.io.IOException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Controller class for managing the stock market exchange.
*/
public final class MarketController {
public final class MarketController implements AppController {
private Exchange exchange;
private final int stockResolution;
private final Map<String, StockController> stockControllers = new HashMap<>();

/**
* Creates a new market controller and loads stock data from a file.
*
* @param path the path to the stock data file
*/
public MarketController(Path path) {
public MarketController(Path path) throws IOException, StockFileParseException {
this.stockResolution = 120;
try {
exchange = new Exchange(StockFileHandler.readFromFile(path));
startMarket();
System.out.println("Market loaded");
} catch (IOException exception) {
System.out.println("File not found");
} catch (StockFileParseException exception) {
System.out.println("Invalid stock file format");
exchange = new Exchange(StockFileHandler.readFromFile(path));
for (Stock stock : exchange.getAllStocks()) {
stockControllers.put(stock.getSymbol(), new StockController(stock));
}
startMarket();
System.out.println("Market loaded");
}

public Exchange getExchange() {
Expand All @@ -52,19 +53,29 @@ public List<Stock> getMarket(final String searchTerm) {
*/
public void updateMarket() {
for (Stock stock : exchange.getAllStocks()) {
stock.updatePrice();
stock.updateStockGraph();
StockController controller = stockControllers.get(stock.getSymbol());
if (controller != null) {
stock.addNewSalesPrice(controller.updatePrice());
}
}
}

@Override
public void nextTick() {
updateMarket();
}

/**
* Initializes the market by generating stock history and graphs.
*/
public void startMarket() {
for (Stock stock : exchange.getAllStocks()) {
stock.fakeHistory(stockResolution);
stock.updateStockGraph();

StockController controller = stockControllers.get(stock.getSymbol());
if (controller != null) {
for (int i = 0; i < stockResolution; i++) {
stock.addNewSalesPrice(controller.updatePrice());
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,15 @@ public StockAppController(
/** Navigates to stock detail page. */
public void navigateToStock(final Stock stock) {
currentStock = stock;
stock.getStockGraph().setVisibility(true);
Platform.runLater(stock::updateStockGraph);
stockApp.getStockGraph().setVisibility(true);
stockApp.showStockPage(stock);
stockApp.getStockGraph().update(stock);
updateReceipt();
}

/** Navigates to search page. */
private void navigateToSearch() {
if (currentStock != null) {
currentStock.getStockGraph().setVisibility(false);
}
stockApp.getStockGraph().setVisibility(false);
currentStock = null;
stockApp.showSearchPage();
}
Expand Down Expand Up @@ -270,12 +268,11 @@ private void handleTransaction() {
}
}

private void handleBuy(final Stock stock, final BigDecimal quantity) throws Exception {
private void handleBuy(final Stock stock, final BigDecimal quantity) {
Transaction transaction = marketController.getExchange()
.buy(stock.getSymbol(), quantity);
if (transaction != null) {
transaction.commit(player);
player.getPortfolio().addShare(transaction.getShare());
player.updateStatus();
}
}
Expand All @@ -292,12 +289,7 @@ private void handleSell(final Stock stock, final BigDecimal quantity) {
Transaction transaction =
marketController.getExchange().sell(existingShare, quantity);
if (transaction != null) {
try {
transaction.commit(player);
} catch (Exception e) {
System.out.println("Transaction failed");
}
player.getPortfolio().removeShare(transaction.getShare());
transaction.commit(player);
player.updateStatus();
}
});
Expand Down Expand Up @@ -334,7 +326,6 @@ private void updateStockList() {
/** Processes next tick. */
@Override
public void nextTick() {
marketController.updateMarket();
Platform.runLater(() -> stockApp.getStockList().refresh());
if (currentStock != null) {
stockApp.updatePriceLabel(currentStock);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,12 @@ public DesktopViewController(
this.timeAndWeatherController = new TimeAndWeatherController(gameController);
gameController.addAppController(timeAndWeatherController);

this.marketController = new MarketController(userSelectedPath);
try {
this.marketController = new MarketController(userSelectedPath);
} catch (Exception e) {
// In a real app we'd show an error dialog, but here we'll at least not swallow it silently
throw new RuntimeException("Failed to load market", e);
}
this.mailController = new MailController(timeAndWeatherController);
gameController.addAppController(mailController);

Expand Down Expand Up @@ -134,6 +139,7 @@ private List<Popup> initializeApps(GameController gameController) {
StockApp stockApp = new StockApp(player);
this.stockAppController = new StockAppController(stockApp, marketController, player);
gameController.addAppController(stockAppController);
gameController.addAppController(marketController);

final MailApp mailApp = new MailApp(mailController);
final NewsApp newsApp = new NewsApp();
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt2003/gruppe42/model/EventBus.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@ public <T> void subscribe(Class<T> type, Consumer<T> listener) {
.add((Consumer<Object>) listener);
}

/**
* Unsubscribes a listener from events of the given type.
*
* @param <T> the event type.
* @param type the class of the event.
* @param listener the listener to remove.
*/
public <T> void unsubscribe(Class<T> type, Consumer<T> listener) {
List<Consumer<Object>> handlers = listeners.get(type);
if (handlers != null) {
handlers.remove(listener);
}
}

/**
* Publishes an event to all subscribers of its type.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,15 @@ public class Exchange {
* @param stocks the stocks to list on this exchange.
*/
public Exchange(final List<Stock> stocks) {
if (stocks == null) {
throw new IllegalArgumentException("Stocks list cannot be null");
}
this.week = 0;
this.stockMap = new HashMap<>();
for (Stock stock : stocks) {
stockMap.put(stock.getSymbol(), stock);
if (stock != null) {
stockMap.put(stock.getSymbol(), stock);
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt2003/gruppe42/model/News.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ public News(String company, int trend) {
public String generateAuthor() {
List<String> authors = new ArrayList<>();
authors.add("market@news.com");
authors.add("financial@journal.com");
authors.add("insider@trading.com");
authors.add("economy@update.com");
return authors.get(random.nextInt(authors.size()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ public class Player {
* @param startingMoney the initial cash balance; must not be {@code null} or negative
*/
public Player(final String name, final BigDecimal startingMoney) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("Name cannot be null or blank");
}
if (startingMoney == null || startingMoney.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Starting money cannot be null or negative");
}
this.name.set(name);
this.startingMoney = startingMoney;
this.money = startingMoney;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public boolean removeShare(final Share newShare) {
}

public List<Share> getShares() {
return shares;
return List.copyOf(shares);
}

/**
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/edu/ntnu/idi/idatt2003/gruppe42/model/Share.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ public Share(
final BigDecimal quantity,
final BigDecimal purchasePrice
) {
if (stock == null) {
throw new IllegalArgumentException("Stock cannot be null");
}
if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Quantity must be positive");
}
if (purchasePrice == null || purchasePrice.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Purchase price cannot be negative");
}
this.stock = stock;
this.quantity = quantity;
this.purchasePrice = purchasePrice;
Expand Down Expand Up @@ -80,6 +89,10 @@ public boolean equals(Object object) {
*/
@Override
public int hashCode() {
return Objects.hash(stock.getSymbol(), quantity, purchasePrice);
return Objects.hash(
stock.getSymbol(),
quantity == null ? null : quantity.stripTrailingZeros(),
purchasePrice == null ? null : purchasePrice.stripTrailingZeros()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* <li>{@link #INVESTOR}: Achieved by trading for at least 10 distinct weeks
* and increasing net worth by at least 20%.</li>
* <li>{@link #SPECULATOR}: Achieved by trading for at least 20 distinct weeks
* and doubling net worth.</li>
* and increasing net worth by at least 5 times.</li>
* </ul>
*/
public enum Status {
Expand Down
56 changes: 12 additions & 44 deletions src/main/java/edu/ntnu/idi/idatt2003/gruppe42/model/Stock.java
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
package edu.ntnu.idi.idatt2003.gruppe42.model;

import edu.ntnu.idi.idatt2003.gruppe42.controller.StockController;
import edu.ntnu.idi.idatt2003.gruppe42.view.views.components.StockGraph;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
* Represents a publicly traded stock belonging to a company.
*
* <p>A stock maintains a full chronological price history, exposes summary
* statistics (highest, lowest, the latest change), and delegates price-update
* logic to a {@link StockController}. An optional {@link StockGraph} can be
* lazily attached for visual rendering.
* <p>A stock maintains a full chronological price history and exposes summary
* statistics (highest, lowest, the latest change).
*
* <p>Price history is append-only: new prices are recorded via
* {@link #addNewSalesPrice(BigDecimal)} or {@link #updatePrice()}, and the
* {@link #addNewSalesPrice(BigDecimal)} and the
* most recent entry is always considered the current market price.
*/
public class Stock {
private final String symbol;
private final String company;
private StockGraph stockGraph;
private final List<BigDecimal> prices = new ArrayList<>();
private final StockController stockController;

/** Constructs a new stock. */
public Stock(
final String symbol,
final String company,
final BigDecimal salesPrice
) {
if (symbol == null || symbol.isBlank()) {
throw new IllegalArgumentException("Symbol cannot be null or blank");
}
if (company == null || company.isBlank()) {
throw new IllegalArgumentException("Company cannot be null or blank");
}
if (salesPrice == null || salesPrice.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Sales price cannot be negative");
}
this.symbol = symbol;
this.company = company;
prices.add(salesPrice);
stockController = new StockController(this);
}

public String getSymbol() {
Expand Down Expand Up @@ -75,38 +77,4 @@ public BigDecimal getLatestPriceChange() {
int index120Ago = Math.max(0, prices.size() - 121);
return getSalesPrice().subtract(prices.get(index120Ago));
}

/** Updates the price. */
public void updatePrice() {
BigDecimal newPrice = stockController.updatePrice();
prices.add(newPrice);
}

/**
* Returns the {@link StockGraph} component associated with this stock,
* creating it lazily on the first call.
*
* @return the stock graph; never {@code null}
*/
public StockGraph getStockGraph() {
if (stockGraph == null) {
stockGraph = new StockGraph();
}
return stockGraph;
}

/** Generates fake history. */
public void fakeHistory(int stockResolution) {
for (int i = 0; i < stockResolution; i++) {
updatePrice();
}
java.util.Collections.reverse(prices);
}

/** Updates the stock graph. */
public void updateStockGraph() {
if (stockGraph != null && stockGraph.getVisibility()) {
stockGraph.update(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public static List<Stock> readFromFile(final Path path)
if (!SYMBOL_PATTERN.matcher(symbol).matches()) {
throw new StockFileParseException(lineNumber, trimmed,
String.format("Ticker symbol \"%s\" is invalid — "
+ "must be exactly 3 uppercase letters (A-Z)", symbol));
+ "must be 1-5 uppercase letters (A-Z) or dots (.)", symbol));
}

String company = parts[1].trim();
Expand Down
Loading

0 comments on commit fd35068

Please sign in to comment.