4

我正在尝试学习 scala,并决定创建一个扑克应用程序来了解一些类对象。我的套牌工作正常,但我已经到了需要抓 5 张牌的地步。到目前为止,我有:

import util.Random

case class Card(value: Int, color: String)

class Deck {
  private var deck = newDeck 

  def draw(amount: Int): List[Card] = {
    val ret = deck.take(amount)
    deck = deck.drop(amount)
    ret
  }

  def newDeck: List[Card] = {
    Random.shuffle((1 to 13).map(x => 
      List(Card(x, "D"), Card(x, "C"), Card(x, "H"), Card(x, "S"))).toList.flatten)
  }

  override def toString: String =  "Deck has " + deck.length + " cards left."
}

这个抽奖功能似乎不太正确,有两个步骤 - 但我不确定我还能(或应该)拿走多少张牌,并使列表处于没有这些牌的状态?

(顺便说一句,如果有人对牌组创建/洗牌有更好的功能,我会全神贯注,这似乎也有点老套......但我的主要问题是列表状态)

4

4 回答 4

2

已经为您编写了解决此问题的最纯粹的功能方法!它splitAt的模型绘制为获取一定数量的卡片并随之返回卡组的新状态。

来自 collections api的Queue.dequeue使用了这种技术:

def dequeue: (A, Queue[A])
//Returns a tuple with the first element in the queue,
//and a new queue with this element removed. 

那么draw就是这样:

def draw[A](amount: Int): (A, Queue[A]) = deck.splitAt(amount)
于 2013-09-30T02:51:32.877 回答
2

在我看来,你应该重写代码:

(a)具有完全不可变的结构,即没有 var没有可变集合

或者

(b)替换var deck: List[Card]为一些可变集合,例如ListBuffer.

这是(a)解决方案:

import util.Random

case class Card(value: Int, color: String)

class Deck(private val cards: Seq[Card]) {
  def draw(amount: Int): (Deck, Seq[Card]) = {
    val (ret, rem) = cards.splitAt(amount)
    (new Deck(rem), ret)
  }

  override def toString: String = "Deck has " + cards.size + " cards left."
}

object Deck {
  def apply(cards: Seq[Card] = Nil): Deck = cards match {
    case Nil =>
        val ncds = for(v <- 1 to 13; c <- Seq("D", "C", "H", "S")) yield Card(v, c)
        new Deck(Random.shuffle(ncds))
    case _ => new Deck(cards)
  }
} 

用例:

scala> :paste
// Entering paste mode (ctrl-D to finish)
//paste code here

// Exiting paste mode, now interpreting.

import util.Random
defined class Card
defined class Deck
defined object Deck

scala> val d1 = Deck()
d1: Deck = Deck has 52 cards left.

scala> val (d2, cards) = d1.draw(4)
d2: Deck = Deck has 48 cards left.
cards: Seq[Card] = Vector(Card(3,H), Card(2,S), Card(11,H), Card(8,C))
于 2013-09-30T04:07:38.423 回答
2

撇开你是否想让甲板成为“var”不谈,你可以同时做到这一点takedrop使用splitAt

def draw(amount: Int): List[Card] = {
  val (ret, remainder) = deck.splitAt(amount)
  deck = remainder
  ret
}
于 2013-09-29T13:30:51.827 回答
1

只是一个小提示:您可以避免使用.flattenif.flatMap代替方法.mapnewDeck我不知道你为什么认为这种方法“hacky”,对我来说它看起来非常合理。这是使用 for 语法的变体:

def newDeck: List[Card] = {
  val sorted = for {
    value <- 1 to 13
    color <- Seq("D", "C", "H", "S")
  } yield Card(value, color)

  Random.shuffle(sorted).toList
}
于 2013-09-29T14:37:14.927 回答