Skip to content

add game states and fix bugs (when gametick was off) #98

Merged
merged 1 commit into from
May 13, 2026
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public record BankAppController(BankApp bankApp, Player player) implements AppCo
* @param player the player model
*/
public BankAppController {
nextTick();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,26 @@
import edu.ntnu.idi.idatt2003.gruppe42.View.Apps.StockApp;
import java.math.BigDecimal;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.ListCell;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;

/**
* Controller for the {@link StockApp}.
* Handles user interactions for buying and selling stocks,
* and updates the UI in real-time.
*/
public final class StockAppController implements AppController {

private final MarketController marketController;
private final StockApp stockApp;
private final Player player;
private Stock currentStock;

/**
* Constructs a new StockAppController.
Expand All @@ -34,67 +44,149 @@ public StockAppController(
this.marketController = marketController;
this.player = player;

stockApp.getStockList().getItems().addAll(
marketController.getExchange().getAllStocks()
);
stockApp.getStockList().getItems()
.addAll(marketController.getExchange().getAllStocks());

stockApp.getStockList().setCellFactory(lv -> createStockCell());

stockApp.getSearchField().textProperty().addListener(
(obs, old, newValue) -> {
if (stockApp.getCurrentStock() != null && !newValue.isEmpty()) {
stockApp.openSearchPage();
if (currentStock != null && !newValue.isEmpty()) {
navigateToSearch();
}
stockApp.getStockList().getItems().setAll(
marketController.getMarket(newValue)
);
stockApp.getStockList().getItems()
.setAll(marketController.getMarket(newValue));
});

stockApp.getQuantitySpinner().valueProperty().addListener(
(obs, old, newValue) -> {
if (stockApp.getCurrentStock() != null) {
if (currentStock != null) {
updateReceipt();
}
});

stockApp.getConfirmButton().setOnAction(event -> {
handleTransaction();
});
stockApp.getConfirmButton().setOnAction(e -> handleTransaction());
}

/**
* Navigates to the detail page for the given stock.
*
* @param stock the stock to view
*/
private void navigateToStock(final Stock stock) {
currentStock = stock;
stock.getStockGraph().setVisibility(true);
Platform.runLater(stock::updateStockGraph);
stockApp.showStockPage(stock);
updateReceipt();
}

/**
* Navigates back to the stock search page.
*/
private void navigateToSearch() {
if (currentStock != null) {
currentStock.getStockGraph().setVisibility(false);
}
currentStock = null;
stockApp.showSearchPage();
}

/**
* Creates a list cell for displaying a stock row.
*
* @return a configured list cell
*/
private ListCell<Stock> createStockCell() {
return new ListCell<>() {
private final HBox row = new HBox(15);
private final Label symbolLabel = new Label();
private final Label companyLabel = new Label();
private final Label priceLabel = new Label();
private final Label changeLabel = new Label();

{
row.setPadding(new Insets(10));
row.setAlignment(Pos.CENTER_LEFT);
row.getStyleClass().add("stock-list-item");

VBox names = new VBox(2, symbolLabel, companyLabel);
symbolLabel.getStyleClass().add("stock-symbol");
companyLabel.getStyleClass().add("stock-company");

Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);

VBox priceInfo = new VBox(2, priceLabel, changeLabel);
priceInfo.setAlignment(Pos.CENTER_RIGHT);
priceLabel.getStyleClass().add("stock-price");
changeLabel.getStyleClass().add("stock-price-change");

row.getChildren().addAll(names, spacer, priceInfo);
row.setOnMouseClicked(e -> {
Stock stock = getItem();
if (stock != null) {
navigateToStock(stock);
}
});
}

@Override
protected void updateItem(final Stock stock, final boolean empty) {
super.updateItem(stock, empty);
if (empty || stock == null) {
setGraphic(null);
return;
}
symbolLabel.setText(stock.getSymbol());
companyLabel.setText(stock.getCompany());
priceLabel.setText("$" + String.format("%,.2f", stock.getSalesPrice()));

BigDecimal change = stock.getLatestPriceChange();
changeLabel.setText(
(change.compareTo(BigDecimal.ZERO) >= 0 ? "+" : "")
+ String.format("%,.2f", change)
);
changeLabel.getStyleClass()
.removeAll("stock-price-positive", "stock-price-negative");
changeLabel.getStyleClass().add(
change.compareTo(BigDecimal.ZERO) >= 0
? "stock-price-positive" : "stock-price-negative"
);
setGraphic(row);
}
};
}

/**
* Handles the buy or sell transaction based on the quantity spinner value.
* Handles the trade button action based on the spinner value.
*/
private void handleTransaction() {
Stock currentStock = stockApp.getCurrentStock();
if (currentStock == null) {
return;
}

int quantityValue = stockApp.getQuantitySpinner().getValue();
if (quantityValue == 0) {
int value = stockApp.getQuantitySpinner().getValue();
if (value == 0) {
return;
}

BigDecimal quantity = new BigDecimal(Math.abs(quantityValue));

if (quantityValue > 0) {
BigDecimal quantity = new BigDecimal(Math.abs(value));
if (value > 0) {
handleBuy(currentStock, quantity);
} else {
handleSell(currentStock, quantity);
}
}

/**
* Performs a buy transaction.
* Performs a buy transaction for the given stock.
*
* @param stock the stock to buy
* @param quantity the amount to buy
* @param quantity the quantity to buy
*/
private void handleBuy(final Stock stock, final BigDecimal quantity) {
try {
Transaction transaction = marketController.getExchange().buy(
stock.getSymbol(), quantity, player
);

Transaction transaction = marketController.getExchange()
.buy(stock.getSymbol(), quantity, player);
if (transaction != null) {
transaction.commit(player);
player.getPortfolio().addShare(transaction.getShare());
Expand All @@ -105,10 +197,10 @@ private void handleBuy(final Stock stock, final BigDecimal quantity) {
}

/**
* Performs a sell transaction.
* Performs a sell transaction for the given stock.
*
* @param stock the stock to sell
* @param quantity the amount to sell
* @param quantity the quantity to sell
*/
private void handleSell(final Stock stock, final BigDecimal quantity) {
player.getPortfolio().getShares().stream()
Expand All @@ -118,10 +210,8 @@ private void handleSell(final Stock stock, final BigDecimal quantity) {
if (existingShare.getQuantity().compareTo(quantity) < 0) {
return;
}

Transaction transaction = marketController.getExchange().sell(
existingShare, quantity, player
);
Transaction transaction = marketController.getExchange()
.sell(existingShare, quantity, player);
if (transaction != null) {
transaction.commit(player);
player.getPortfolio().removeShare(transaction.getShare());
Expand All @@ -130,10 +220,9 @@ private void handleSell(final Stock stock, final BigDecimal quantity) {
}

/**
* Updates the receipt in the stock app.
* Updates the receipt display based on the current stock and spinner value.
*/
private void updateReceipt() {
Stock currentStock = stockApp.getCurrentStock();
if (currentStock != null) {
Platform.runLater(() ->
stockApp.getReceipt().update(
Expand All @@ -146,17 +235,14 @@ private void updateReceipt() {

/**
* Updates the app state on each simulation tick.
* Refreshes the market data and updates UI components.
*/
@Override
public void nextTick() {
marketController.updateMarket();
Platform.runLater(() -> stockApp.getStockList().refresh());
Stock currentStockInView = stockApp.getCurrentStock();
if (currentStockInView != null) {
stockApp.updatePriceLabel(currentStockInView);
if (currentStock != null) {
stockApp.updatePriceLabel(currentStock);
updateReceipt();
// Graph is updated within marketController.updateMarket() if visible
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package edu.ntnu.idi.idatt2003.gruppe42.Controller;

import edu.ntnu.idi.idatt2003.gruppe42.Controller.AppControllers.AppController;
import edu.ntnu.idi.idatt2003.gruppe42.Model.GameState;
import edu.ntnu.idi.idatt2003.gruppe42.Model.Player;

import java.util.ArrayList;
Expand All @@ -15,6 +16,7 @@ public final class GameController {
private final Player player;
private final List<AppController> appControllers = new ArrayList<>();
private Timer timer;
private GameState gameState;

/**
* Constructs a new GameController.
Expand All @@ -34,6 +36,10 @@ public void addAppController(final AppController appController) {
appControllers.add(appController);
}

public void setGameState(GameState gameState) {
this.gameState = gameState;
}

/**
* Starts the game simulation timer.
*/
Expand All @@ -45,14 +51,24 @@ public void startGame() {
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {

if (isWeekend()) {
stopGame();
}

for (AppController controller : appControllers) {
controller.nextTick();

}
}
}, delay, period);

}

public boolean isWeekend() {
return !(gameState == GameState.WORKDAY);
}

/**
* Stops the game simulation timer.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package edu.ntnu.idi.idatt2003.gruppe42.Controller;

import edu.ntnu.idi.idatt2003.gruppe42.Controller.AppControllers.AppController;
import edu.ntnu.idi.idatt2003.gruppe42.Model.Day;
import edu.ntnu.idi.idatt2003.gruppe42.Model.GameState;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Random;
Expand All @@ -23,11 +25,12 @@ public class TimeAndWeatherController implements AppController {
private final Random random = new Random();
private final GameController gameController;

private static final String[] DAYS = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
private static final Day[] DAYS = {Day.SUN, Day.MON, Day.TUE, Day.WED, Day.THU, Day.FRI, Day.SAT};

public TimeAndWeatherController(GameController gameController) {
this.gameController = gameController;
updateWeather();
updateGameState();
}

@Override
Expand All @@ -37,14 +40,10 @@ public void nextTick() {
hour.set(0);
dayIndex.set((dayIndex.get() + 1) % 7);
updateWeather();
updateGameState();
} else {
hour.set(nextHour);
}

if (dayIndex.get() > 5) {
gameController.stopGame();

}
}

private void updateWeather() {
Expand Down Expand Up @@ -89,6 +88,17 @@ public String getTimeString() {
}

public String getDayOfWeekString() {
return DAYS[dayIndex.get()];
return DAYS[dayIndex.get()].toString();
}

public void updateGameState() {
if (dayIndex.equals(new SimpleIntegerProperty(6))) {
gameController.setGameState(GameState.RENTDAY);
return;
} else if (dayIndex.equals(new SimpleIntegerProperty(0))) {
gameController.setGameState(GameState.FREEDAY);
return;
}
gameController.setGameState(GameState.WORKDAY);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public DesktopViewController(

bankApp.setOnShareSelected(share -> {
popupsController.show(App.STOCK);
stockApp.openStockPage(share.getStock());
stockApp.showStockPage(share.getStock());
});

this.desktopView = new DesktopView(this);
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt2003/gruppe42/Model/Day.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package edu.ntnu.idi.idatt2003.gruppe42.Model;

public enum Day {
MON, TUE, WED, THU, FRI, SAT, SUN;
}
Loading