Skip to content
Snippets Groups Projects
EconomicsTest.scala 2.96 KiB
Newer Older
package concpar22final03

import scala.concurrent.Future

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.Random

trait EconomicsTest extends Economics:
  val ownedCards: collection.mutable.Set[Card] = collection.mutable.Set[Card]()
  def owned(c: Card): Boolean = ownedCards(c)
  def isMine(c: Card): Boolean = ownedCards(c)

  override def valueOf(cardName: String): Int = List(1, cardName.length).max

  /** This is a container for an exact amount of money that can be hold, spent,
    * or put in the bank
    */
  val moneyInMoneyBag = collection.mutable.Map[MoneyBag, Int]()
  def moneyIn(m: MoneyBag): Int = moneyInMoneyBag.getOrElse(m, 0)

  /** If you sell a card, at some point in the future you will get some money
    * (in a bag).
    */
  def sellCard(c: Card): Future[MoneyBag] =
    Future {
      Thread.sleep(sellWaitTime())
      synchronized(
        if owned(c) then
          ownedCards.remove(c)
          getMoneyBag(valueOf(c.name))
        else
          throw Exception(
            "This card doesn't belong to you or has already been sold, you can't sell it."
          )
      )
    }

  /** You can buy any "Scala: The Programming" card by providing a bag of money
    * with the appropriate amount and waiting for the transaction to take place
    */
  def buyCard(bag: MoneyBag, name: String): Future[Card] =
    Future {
      Thread.sleep(buyWaitTime())
      synchronized {
        if moneyIn(bag) != valueOf(name) then
          throw Exception(
            "You didn't provide the exact amount of money necessary to buy this card."
          )
        else moneyInMoneyBag.update(bag, 0)
        getCard(name)
      }

    }

  /** This simple bank account hold money for you. You can bring a money bag to
    * increase your account, or withdraw a money bag of any size not greater
    * than your account's balance.
    */
  private var balance_ = initialBalance()
  def balance: Int = balance_
  def withdraw(amount: Int): Future[MoneyBag] =
    Future {
      Thread.sleep(withdrawWaitTime())
      synchronized(
        if balance_ >= amount then
          balance_ -= amount
          getMoneyBag(amount)
        else
          throw new Exception(
            "You try to withdraw more money than you have on your account"
          )
      )
    }

  def deposit(bag: MoneyBag): Future[Unit] =
    Future {
      Thread.sleep(depositWaitTime())
      synchronized {
        if moneyInMoneyBag(bag) == 0 then
          throw new Exception("You are depositing en empty bag!")
        else
          balance_ += moneyIn(bag)
          moneyInMoneyBag.update(bag, 0)
      }
    }

  def sellWaitTime(): Int
  def buyWaitTime(): Int
  def withdrawWaitTime(): Int
  def depositWaitTime(): Int
  def initialBalance(): Int

  def getMoneyBag(i: Int) =
    val m = MoneyBag()
    synchronized(moneyInMoneyBag.update(m, i))
    m

  def getCard(n: String): Card =
    val c = Card(n)
    synchronized(ownedCards.update(c, true))
    c