编程:Scala从一副牌中抽出一张牌,直到它空了

  • 本文关键字:一张 Scala 一副 编程 scala
  • 更新时间 :
  • 英文 :


im 试图在 scala 中制作一副牌。我有两个我的信息枚举器:"西装"和"脸"。我有以下处理甲板类的代码:

case class Card (suit: Suit, face: Face) //require("error") nereikia net naudoti cia, nes object naudojam
class Deck(myCards: List[Card] = for(face <- Face.all; suit <- Suit.all) yield Card(suit, face))
{
val cards = if(myCards.size > 0 && myCards.size <= 52) myCards
else throw new Exception("Nepavyko sukurti kortu kalades!")
val shuffledCards = util.Random.shuffle(cards)
val drawCard = (cards.head, cards.tail)
val splitShuffled = if(myCards.size % 2 == 0) shuffledCards.sliding(26, 2).toList
else throw new Exception("Kortu kiekis negali buti nelyginis, nesazininga!")
}

如何循环投掷我的牌组并抽出每张牌?基本上我有一个全新的套牌,然后使用功能拆分洗牌,我将我的套牌分成两个较小的套牌供两个玩家使用。如何比较每张抽出的牌?对我来说,这是函数式编程最令人沮丧的事情。我不明白!如果我的清单是不变的,人们应该如何循环扔这些牌?:D非常感谢您的帮助!!^^

这不是一个真正的答案,但这里有一些关于如何做到这一点的提示:


首先创建一个表示一个Player的数据的类。这包含一个平局堆、一个分数堆和一个计算该玩家分数的score方法。

接下来,创建一个表示游戏当前State的类。这包含两个Player实例,可能还有一些其他数据。它还具有一种方法,可以比较每个玩家的score并指示谁是winner(或平局(。

然后,创建一个玩一轮游戏的函数。它采用当前State并生成一个新的State,其中包含玩一轮的结果。这将取每个抽奖堆的head并比较两张牌。然后,它基于此比较生成两个新的分数堆,以及两个新的抽奖桩,它们只是当前抽奖桩的tailState是使用使用新抽奖分数堆创建的Player的两个实例创建的。

然后编写一个递归函数,该函数采用初始State并生成单轮的结果。如果桩现在为空,则返回新的State,否则它用新State递归调用自己。

在此函数的结果(最终状态(上调用winner将告诉您谁赢得了游戏。


这是对如何完成的简要描述,但关键是任何地方都没有可变状态,只有一组接受不可变值并返回不可变值的纯函数。

这是我第一次解决这个问题,所以它可能并不完美,但它应该给你一些想法。我认为练习FP是一个很好的练习。

我喜欢首先考虑类型,然后考虑我需要的转换(函数(,以便获得解决方案。最后,如果类型对齐,则可以组合小函数。

由于您尚未给出Suite的定义,因此Face我将它们定义如下(Rank使用而不是Face(:

sealed trait Suit
sealed case class Hearts() extends Suit {
override def toString = "♡"
}
sealed case class Diamonds() extends Suit {
override def toString = "♢"
}
sealed case class Clubs() extends Suit {
override def toString = "♧"
}
sealed case class Spades() extends Suit {
override def toString = "♤"
}
sealed class Rank(val value: Int) {
override def toString = s"${value}"
}
sealed case class Ace() extends Rank(14) {
override def toString = "A"
}
sealed case class King() extends Rank(13){
override def toString = "K"
}
sealed case class Queen() extends Rank(12){
override def toString = "Q"
}
sealed case class Jack() extends Rank(11){
override def toString = "J"
}
sealed case class Ten() extends Rank(10)
sealed case class Nine() extends Rank(9)
sealed case class Eight() extends Rank(8)
sealed case class Seven() extends Rank(7)
sealed case class Six() extends Rank(6)
sealed case class Five() extends Rank(5)
sealed case class Four() extends Rank(4)
sealed case class Three() extends Rank(3)
sealed case class Two() extends Rank(2)
case class Card(suit: Suit, rank: Rank) {
override def toString = rank.toString+suit.toString
}

toString方法只是为了使调试输出更简洁。

为了便于阅读,我还创建了两个类型别名:

type Deck = List[Card]
type Hand = List[Card]

生成花色和等级列表的两个函数:

def suits(): List[Suit] = List(Hearts(), Diamonds(), Clubs(), Spades())
def ranks(): List[Rank] = List(Ace(), King(), Queen(), Jack(), Ten(), Nine(), Eight(), Seven(), Six(), Five(), Four(), Three(), Two())

还有一个套牌:

def deck(): Deck = for (
s <- suits();
r <- ranks()
) yield Card(s, r)

现在,进入更有趣的部分。Shuffle 采用Deck并返回一个新的(随机的(Deck

def shuffle(cards: Deck): Deck = util.Random.shuffle(cards)

divide取一个Deck(一个List[Card](并返回两个Hand(一个(List[Card], List[Card])(:

def divide(cards: Deck): (Hand, Hand) = cards.splitAt(cards.length / 2)

对于评分函数,我引入了一个新的类型族来模拟战斗结果:

sealed trait BattleResult
sealed case class Player1Wins(cards: List[Card]) extends BattleResult
sealed case class Player2Wins(cards: List[Card]) extends BattleResult
sealed case class War(cards: List[Card]) extends BattleResult

score功能本身将接受两张牌,但也接受上一场战斗(战争场景(中的卡牌。它将比较卡片并返回结果:

def score(player1Card: Card, player2Card: Card, previousTurnCards: List[Card] = List()): BattleResult = (player1Card.rank.value - player2Card.rank.value) match {
case s if (s == 0) => War(player1Card :: player2Card :: previousTurnCards)
case s if (s > 0) => Player1Wins(player1Card :: player2Card :: previousTurnCards)
case s if (s < 0) => Player2Wins(player2Card :: player1Card :: previousTurnCards)
}

最后,battle函数。这里重要的是处理停止情况(当其中一只手为空时(,并以递归方式调用battle,直到我们完成:

def battle(player1Hand: Hand, player2Hand: Hand, previousTurnCards: List[Card] = List()): (Hand, Hand) = (player1Hand, player2Hand) match {
case (p1, List()) => (p1, List())
case (List(), p2) => (List(), p2)
case (nextCard1 :: remainingCards1, nextCard2 :: remainingCards2) => score(nextCard1, nextCard2, previousTurnCards) match {
case Player1Wins(cards) => (remainingCards1 ::: cards, remainingCards2)
case Player2Wins(cards) => (remainingCards1, remainingCards2 ::: cards)
case War(cards) => battle(remainingCards1, remainingCards2, cards)
}
}

万一Player1Wins我们将卡片添加到他们的堆的末尾。 万一Player2Wins我们对 player2 的堆做同样的事情。 如果War我们再次battle

最后但并非最不重要的一点是,play函数将继续播放,直到有赢家:

def play(hands: (Hand, Hand)): (Hand, Hand) = hands match {
case (h, List()) => (h, List())
case (List(), h) => (List(), h)
case (player1: Hand, player2: Hand) => play(battle(player1, player2))
}

执行:

play(divide(shuffle(deck())))

我希望这有所帮助。

相关内容

最新更新