3

I have these steps:

trait BlackjackSteps {
    def gamerTakesTwoCards(gamerName:String): State[Deck, Gamer]
    def dealerTakesTwoCards: State[Deck, Dealer]
    def isBlackjack(gamer: Gamer, dealer: Dealer): Option[Player]
    def gamerDrawsCards(gamer: Gamer): State[Deck, Gamer]
    def dealerDrawsCards(dealer: Dealer, gamer: Gamer): State[Deck, Dealer]
    def determineWinner(gamer: Gamer, dealer: Dealer): Player

    def program(gamerName:String): State[Deck, Player] = for {
      gamer <- gamerTakesTwoCards(gamerName)
      dealer <- dealerTakesTwoCards
      //winner = isBlackjack(gamer, dealer)
      gamerFinal <- gamerDrawsCards(gamer)
      dealerFinal <- dealerDrawsCards(dealer, gamerFinal)
      winnerFinal = determineWinner(gamerFinal, dealerFinal)
    } yield  winnerFinal
  }

Two questions:

  • How do i get the Deck resulting from gamerTakesTwoCards and pass it to dealerTakesTwoCards?

  • isBlackjack may result in a winner in which case I need to stop and return winner. How can I change the above code to do that?

The Game:

  • a gamer and dealer play
  • they both draw two cards
  • if no 21 winner
  • players keep drawing cards until 17
  • highest player not over 21 points wins!

Complete code here: https://bitbucket.org/jameskingconsulting/blackjack-scala/src/master/

Edit:

I've de-sugared the for-comprehension just make clear what's happening:

def program(gamerName:String): State[Deck, Player] =
      gamerTakesTwoCards(gamerName).flatMap( gamer =>
        dealerTakesTwoCards.flatMap(dealer =>
          isBlackjack(gamer, dealer).fold(

            gamerDrawsCards(gamer).flatMap( gamerFinal =>
              dealerDrawsCards(dealer, gamerFinal).map( dealerFinal =>
                determineWinner(gamerFinal, dealerFinal)
              )
            )

          )(State.pure[Deck, Player])
        ))
jakstack
  • 2,143
  • 3
  • 20
  • 37

1 Answers1

2
  1. Nothing to do. That's the whole point.
  2. You have to return a winner in both cases, regardless of whether isBlackjack returns a None or a Some. Either way, you have to return a State[Deck, Player]. For example, you could achieve it with fold on the Option, mapping the success-case through pure:

    def program(gamerName:String): State[Deck, Player] = for {
      gamer <- gamerTakesTwoCards(gamerName)
      dealer <- dealerTakesTwoCards
      winner <- isBlackjack(gamer, dealer).fold(for {
        gamerFinal <- gamerDrawsCards(gamer)
        dealerFinal <- dealerDrawsCards(dealer, gamerFinal)
        winnerFinal = determineWinner(gamerFinal, dealerFinal)
      } yield winnerFinal)(State.pure[Deck, Player])
    } yield winner
    
Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
  • thanks, for (1) I actually had a bug in my code that made me think Deck wasn't being passed correctly but now it's working fine. The one thing that i can't seem to visualise is the transfer of Deck from one step another. Can you share a link that explains how this happens? – jakstack Jun 12 '19 at 18:14
  • @jakstack [Here](https://stackoverflow.com/q/34407212/2707792) is a nice toy example. A `State[S, A]` is essentially just `S => (A, S)`, i.e. it takes old state, returns an `A` with the new state. Given a `State[S, A]` and an `f: A => State[S, B]`, you do the following: you start with the first state `s0` and feed it to the `State[S, A]`, which returns `(a, s1)`, where `s1` is the first modified state. Now you apply `f` to `a` and feed it with the updated state `s1`. This will return a `b: B` and an again updated state `s2`. The `(b, s2)` is the result that is returned in the end. – Andrey Tyukin Jun 12 '19 at 18:20
  • thanks, is the f: A => State[S, B] one of the steps in BlackjackSteps like gamerTakesTwoCards? – jakstack Jun 12 '19 at 18:51
  • @jakstack The signature says it already: `gamerTakeTwoCards(s)` is of type `State[Deck, Gamer]`, which, as described above, is essentially just a fancy name for `Deck => (Gamer, Deck)`. – Andrey Tyukin Jun 12 '19 at 20:12