Skip to content

Commit

Permalink
Feat: Updated various classes.
Browse files Browse the repository at this point in the history
  • Loading branch information
tommyah committed May 25, 2026
1 parent 7b3de60 commit f7aafc6
Show file tree
Hide file tree
Showing 6 changed files with 283 additions and 71 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package edu.ntnu.idi.idatt2003.g40.mappe.exceptions;

/**
* Exception primarily thrown when the active
* {@link edu.ntnu.idi.idatt2003.g40.mappe.model.Player} object
* does not have enough money for a transaction to complete.
* */
public class NotEnoughMoneyException extends RuntimeException {

/**
* Constructor.
*
* @param message the exception message.
* */
public NotEnoughMoneyException(final String message) {
super(message);
}
}
128 changes: 96 additions & 32 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 @@ -2,10 +2,11 @@

import edu.ntnu.idi.idatt2003.g40.mappe.controller.PlayerStatusController;
import edu.ntnu.idi.idatt2003.g40.mappe.engine.TransactionArchive;
import edu.ntnu.idi.idatt2003.g40.mappe.exceptions.NotEnoughMoneyException;
import edu.ntnu.idi.idatt2003.g40.mappe.utils.Validator;
import java.math.BigDecimal;
import javafx.beans.property.FloatProperty;
import javafx.beans.property.SimpleFloatProperty;
import javafx.beans.property.ReadOnlyFloatProperty;
import javafx.beans.property.ReadOnlyFloatWrapper;

/**
* Represents a player in the system.
Expand Down Expand Up @@ -37,14 +38,18 @@ public final class Player {
private BigDecimal money;

/**
* Current net-worth of player as a listenable {@link FloatProperty} object.
* Current net-worth of player as a listenable,
* read-only, {@link ReadOnlyFloatWrapper} object.
* */
private final FloatProperty networthAsFloatProp = new SimpleFloatProperty(0);
private final ReadOnlyFloatWrapper networthAsFloatProp =
new ReadOnlyFloatWrapper(0f);

/**
* Current money of player as a listenable {@link FloatProperty} object.
* Current money of player as a read-only
* {@link ReadOnlyFloatWrapper} object.
* */
private final FloatProperty moneyAsFloatProp = new SimpleFloatProperty(0);
private final ReadOnlyFloatWrapper moneyAsFloatProp
= new ReadOnlyFloatWrapper(0f);

/**
* The players' portfolio, holding their shares.
Expand All @@ -63,19 +68,28 @@ public final class Player {
* @param name the name of the player
* @param startingMoney the starting amount of money
*
* @throws IllegalArgumentException if name is null.
* @throws IllegalArgumentException if name is empty,
* or starting money is null,
* zero or negative.
*/
public Player(final String name, final BigDecimal startingMoney) throws IllegalArgumentException {
public Player(final String name,
final BigDecimal startingMoney)
throws IllegalArgumentException {
if (!Validator.NOT_EMPTY.isValid(name)) {
throw new IllegalArgumentException("Invalid name!");
throw new IllegalArgumentException("Player name cannot be empty!");
}
if (startingMoney == null
|| startingMoney.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException(
"Starting money cannot be null, zero, or negative!"
);
}
this.name = name;
this.startingMoney = startingMoney;
this.money = this.startingMoney;
this.networthAsFloatProp.setValue(this.startingMoney);
this.moneyAsFloatProp.setValue(this.startingMoney);
this.portfolio = new Portfolio();
this.transactionArchive = new TransactionArchive();
updateObservableProperties();
}

/**
Expand Down Expand Up @@ -109,18 +123,42 @@ public BigDecimal getMoney() {
* Adds money to the players balance.
*
* @param amount the amount to add
*
* @throws IllegalArgumentException if money to add is negative or zero.
*/
public void addMoney(final BigDecimal amount) {
public void addMoney(final BigDecimal amount)
throws IllegalArgumentException {
if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException(
"Can only add positive values to player!"
);
}
money = money.add(amount);
updateObservableProperties();
}

/**
* Withdraws money from the players balance.
*
* @param amount the amount to withdraw
*
* @throws IllegalArgumentException if money to withdraw is negative or zero,
* or if amount is more than current money.
*/
public void withdrawMoney(final BigDecimal amount) {
public void withdrawMoney(final BigDecimal amount)
throws IllegalArgumentException {
if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException(
"Amount to withdraw must be positive!"
);
}
if (money.compareTo(amount) < 0) {
throw new IllegalArgumentException(
"Cannot withdraw more money than available balance!"
);
}
money = money.subtract(amount);
updateObservableProperties();
}

/**
Expand Down Expand Up @@ -152,21 +190,23 @@ public BigDecimal getNetWorth() {
}

/**
* Get net-worth as a {@link FloatProperty} object, allowing listening for changes.
* Get net-worth as a {@link ReadOnlyFloatProperty} object,
* allowing listening for changes.
*
* @return FloatProperty.
* @return networth as an immutable value.
* */
public FloatProperty getNetWorthAsFloatProperty() {
return networthAsFloatProp;
public ReadOnlyFloatProperty getNetWorthAsFloatProperty() {
return networthAsFloatProp.getReadOnlyProperty();
}

/**
* Get money as a {@link FloatProperty} object, allowing listening for changes.
* Get money as a {@link ReadOnlyFloatProperty} object,
* allowing listening for changes.
*
* @return FloatProperty.
* @return money as an immutable value.
* */
public FloatProperty getMoneyAsFloatProperty() {
return moneyAsFloatProp;
public ReadOnlyFloatProperty getMoneyAsFloatProperty() {
return moneyAsFloatProp.getReadOnlyProperty();
}

/**
Expand All @@ -184,22 +224,46 @@ public PlayerStatus getStatus() {
* Method for handling a transaction for the player.
*
* @param transaction the transaction to handle.
*
* @throws IllegalArgumentException if transaction is null.
* @throws NotEnoughMoneyException if player does not have enough
* money for the transaction.
* */
public void handleTransaction(final Transaction transaction) {
public void handleTransaction(final Transaction transaction)
throws IllegalArgumentException, NotEnoughMoneyException {
if (transaction == null) {
throw new IllegalArgumentException("Cannot handle null transaction!");
}

if (transaction instanceof Purchase purchase) {
if (money.floatValue() > transaction.getCalculator().calculateTotal().floatValue()) {
BigDecimal totalCost = purchase.getCalculator().calculateTotal();
if (this.money.compareTo(totalCost) < 0) {
throw new NotEnoughMoneyException("Not enough money for transaction!");
}
}

switch (transaction) {
case Purchase purchase -> {
withdrawMoney(purchase.getCalculator().calculateTotal());
portfolio.addShare(purchase.getShare());
transactionArchive.add(transaction);
transaction.commit(this);
}
} else if (transaction instanceof Sale sale) {
addMoney(sale.getCalculator().calculateTotal());
portfolio.removeShare(sale.getShare());
transactionArchive.add(transaction);
transaction.commit(this);
case Sale sale -> {
addMoney(sale.getCalculator().calculateTotal());
portfolio.removeShare(sale.getShare());
}
default -> throw new IllegalStateException("Unexpected value: " + transaction);
}
networthAsFloatProp.setValue(getNetWorth().floatValue());
moneyAsFloatProp.setValue(money);
transactionArchive.add(transaction);
transaction.commit(this);

updateObservableProperties();
}

/**
* Helper method to synchronize the listener values.
*/
private void updateObservableProperties() {
this.moneyAsFloatProp.setValue(this.money.floatValue());
this.networthAsFloatProp.setValue(this.getNetWorth().floatValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* expected to be loaded with the default bundled stock data file.
* </p>
*/
public class SaveGame {
public final class SaveGame {

/** Display name of the save. */
private final String name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,17 @@ private TransactionFactory() {
public static Transaction createTransaction(final TransactionType
transactionType,
final Share share,
final int week,
final TransactionCalculator
calculator)
final int week)
throws IllegalArgumentException {
if (transactionType == null
|| share == null
|| !Validator.VALID_POSITIVE_INT.isValid(Integer.toString(week))
|| calculator == null) {
|| !Validator.VALID_WEEK.isValid(Integer.toString(week))
) {
throw new IllegalArgumentException("Null or empty parameters for factory!");
} else {
return switch (transactionType) {
case SALE -> new Sale(share, week, calculator);
case PURCHASE -> new Purchase(share, week, calculator);
case SALE -> new Sale(share, week, new SaleCalculator(share));
case PURCHASE -> new Purchase(share, week, new PurchaseCalculator(share));
default -> throw new
IllegalArgumentException("Invalid transaction type!");
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ void getStatusAfterDoubleIncreaseReturnsBetterStatus() {

@Test
void gettingStatusWhenNegativeDifferenceReturnsWorstStatus() {
testPlayer.addMoney(new BigDecimal(-1000));
testPlayer.withdrawMoney(new BigDecimal(1000));
assertEquals(PlayerStatus.NOOB, testPlayer.getStatus());
}

Expand All @@ -40,10 +40,10 @@ void multipleChangesInValueCauseCorrectStatus() {
testPlayer.addMoney(new BigDecimal(2000));
assertEquals(PlayerStatus.PRO, testPlayer.getStatus());

testPlayer.addMoney(new BigDecimal(-1000));
testPlayer.withdrawMoney(new BigDecimal(1000));
assertEquals(PlayerStatus.TRYHARD, testPlayer.getStatus());

testPlayer.addMoney(new BigDecimal(-500));
testPlayer.withdrawMoney(new BigDecimal(500));
assertEquals(PlayerStatus.GOOD, testPlayer.getStatus());
}
}
}
Loading

0 comments on commit f7aafc6

Please sign in to comment.