Передача состояния между функциональными шагами в Scala - PullRequest
2 голосов
/ 11 июня 2019

Есть ли лучший способ передать состояние между шагами.

Например, каждый раз, когда из колоды берется карта, мы должны создать новую колоду и вернуть ее, чтобы ее можно было использовать на следующем шаге и т. Д.

Есть ли лучший способ сделать это, например, с помощью Cats?

trait BlackjackSteps {
    def gamerTakesTwoCards(deck: Deck): (Gamer, Deck)
    def dealerTakesTwoCards(deck: Deck): (Dealer, Deck)
    def isBlackjack(gamer: Gamer, dealer: Dealer): Option[Player]
    def gamerToDrawCards(gamer: Gamer, deck: Deck): Gamer
    def dealerToDrawCards(dealer: Dealer, deck: Deck, gamer: Gamer): Dealer
    def determineWinner(gamer: Gamer, dealer: Dealer): Player
  }

The Game:

  • геймер и дилер играют
  • они обе вытягивают две карты
  • если нет 21 победителя
  • игроки продолжают рисовать карты до 17
  • игрок с наивысшим рейтингом не более 21 очка выигрывает

РЕДАКТИРОВАТЬ -----

Спасибо за ответы.Я просто хочу посмотреть, что люди думают об этом подходе?

Как насчет этого?

trait CardPicker {
    def pick(numberCards:Int): List[Card]
  }

  abstract class BlackjackSteps(cardPicker: CardPicker) {
    def gamerTakesTwoCards(gamer: Gamer): Gamer = {
      gamer.copy(cards = cardPicker.pick(2))
    }
    def dealerTakesTwoCards(dealer: Dealer): Dealer = {
      dealer.copy(cards = cardPicker.pick(2))
    }
    def isBlackjack(gamer: Gamer, dealer: Dealer): Option[Player] = {
     if(gamer.isBlackjack) Some(gamer)
     else if(dealer.isBlackjack) Some(dealer)
     else None
    }
    def gamerToDrawCards(gamer: Gamer): Gamer = {
      def drawCards(gamerPickingCards: Gamer): Gamer = gamer match {
        case _ if(gamerPickingCards.points < drawThreshold) =>
          drawCards(Gamer(gamerPickingCards.name, gamerPickingCards.cards ++ cardPicker.pick(1)))
        case _ => gamerPickingCards
      }
      drawCards(gamer)
    }
    def dealerToDrawCards(dealer: Dealer, gamer: Gamer): Dealer = {
      def drawCards(dealerPickingCards: Dealer): Dealer = dealer match {
        case _ if(dealerPickingCards.points < gamer.points) =>
          drawCards(Dealer(dealerPickingCards.name, dealerPickingCards.cards ++ cardPicker.pick(1)))
        case _ => dealerPickingCards
      }
      drawCards(dealer)
    }
    def determineWinner(gamer: Gamer, dealer: Dealer): Player = {
      if(gamer.points == dealer.points || gamer.points > dealer.points) gamer
      else dealer
    }
  }

Здесь у CardPicker есть побочные эффекты, которые мы можем отложить до конца света.

Это слишком безумно?

1 Ответ

5 голосов
/ 11 июня 2019

Звучит как отличный вариант использования для монады State. Вот что может помочь вам начать:

trait BlackjackSteps {
  def gamerTakesTwoCards: State[Deck, Gamer]
  def dealerTakesTwoCards: State[Deck, Dealer]
  def isBlackjack(gamer: Gamer, dealer: Dealer): State[Deck, Option[Player]]
  def gamerToDrawCards(gamer: Gamer): State[Deck, Gamer]
  def dealerToDrawCards(dealer: Dealer, gamer: Gamer): State[Deck, Dealer]
  def determineWinner(gamer: Gamer, dealer: Dealer): State[Deck, Player]
}

def gamerTakesTwoCards: State[Deck, Gamer] = 
  State { oldDeck => 
    val gamer = f(oldDeck)
    val newDeck = g(oldDeck)
    (newDeck, gamer)
  } 

Вы можете проверить официальную документацию по Cats, чтобы узнать больше: https://typelevel.org/cats/datatypes/state.html

...