添加一种方法,卡创建一整套卡片,每个组合的等级和套装卡

时间:2023-01-23 19:16:49

So I have been doing the experiments that are in the Apple Swift Book.

所以我一直在做Apple Swift Book中的实验。

I have been able to do all of them, except for this one so far. Below is what I have tried, but I can't figure out how to get it working.

到目前为止,我已经能够完成所有这些了。以下是我的尝试,但我无法弄清楚如何让它工作。

Add a method to Card that creates a full deck of cards, with one card of each combination of rank and suit.

添加一种方法,卡创建一整套卡片,每个组合的等级和套装卡。

// Playground - noun: a place where people can play

enum Rank: Int {
    case Ace = 1
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack, Queen, King

    func simpleDescription() -> String {
        switch self {
            case .Ace:
                return "ace"
            case .Jack:
                return "jack"
            case .Queen:
                return "queen"
            case .King:
                return "king"
            default:
                return String(self.toRaw())
        }
    }
}

enum Suit {
    case Spades, Hearts, Diamonds, Clubs

    func simpleDescription() -> String {
        switch self {
            case .Spades:
                return "spades"
            case .Hearts:
                return "hearts"
            case .Diamonds:
                return "diamonds"
            case .Clubs:
                return "clubs"
        }
    }
}

struct Card {
    var rank: Rank
    var suit: Suit

    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }

    func createFullDeck() -> Array{
        var FullDeck: Array

        FullDeck = Card(rank: .Ace, suit: .Spades)
        FullDeck = Card(rank: .Two, suit: .Spades)

        return FullDeck
    }
}

let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()

threeOfSpades.createFullDeck()
  • I don't know what I am supposed to return for that method, an Array?
  • 我不知道我应该为该方法返回什么,一个数组?
  • Should I use a for loop to create this? or is there a proper/easier way to do this with enum
  • 我应该使用for循环来创建它吗?或者是否有一个适当/更简单的方法来使用枚举
  • Why would I create this method inside of Card, calling threeOfSpades.createFullDeck() seems incorrect.
  • 为什么我会在Card中创建这个方法,调用threeOfSpades.createFullDeck()似乎不正确。

12 个解决方案

#1


17  

Here's another way of doing it, this time only using techniques you would have learned up to that point*

这是另一种方法,这次只使用你到目前为止学到的技术*

First we define the possible ranks and suits, using the respective Rank and Suit enums defined previously.

首先,我们使用先前定义的相应Rank和Suit枚举来定义可能的等级和套装。

Next we have the function iterate over each rank within each suit, creating a card for each, and finally returning an array of the cards.

接下来,我们让函数迭代每个套装中的每个等级,为每个套装创建一张卡片,最后返回一组卡片。

struct Card {
    var rank: Rank
    var suit: Suit
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }

    func createDeck() -> Card[] {
        let ranks = [Rank.Ace, Rank.Two, Rank.Three, Rank.Four, Rank.Five, Rank.Six, Rank.Seven, Rank.Eight, Rank.Nine, Rank.Ten, Rank.Jack, Rank.Queen, Rank.King]
        let suits = [Suit.Spades, Suit.Hearts, Suit.Diamonds, Suit.Clubs]
        var deck = Card[]()
        for suit in suits {
            for rank in ranks {
                deck.append(Card(rank: rank, suit: suit))
            }
        }
        return deck
    }
}

(* with the notable exception that the tour hadn't explicitly explained how to append to arrays at that point)

(*有一个值得注意的例外,即巡演没有明确解释当时如何附加到数组)

#2


8  

A robust code answer will not to the use actual values (i.e., .Spades) from the enumerations when generating the deck, e.g., if a "Joker" is added later to the Rank enumeration (anywhere in the enumeration), the deck generation function should still work without change.

一个健壮的代码答案将不会在生成套牌时使用枚举中的实际值(即.Spades),例如,如果稍后将“Joker”添加到Rank枚举(枚举中的任何位置),则甲板生成函数应该仍然没有改变。

The design questions (what to return?, should the deck generation be a function of card?) are not really relevant to this tutorial, but it is likely that a Deck class would be preferable if any serious functionality is going to be built out further (e.g., shuffle). So for now, returning an Array from a function in the Card structure is all that is required.

设计问题(要返回什么?,甲板生成应该是卡的功能吗?)与本教程并不真正相关,但如果要进一步构建任何严格的功能,可能会更喜欢Deck类(例如,洗牌)。所以现在,只需要从Card结构中的函数返回一个数组。

The following code (as far as possible only using what has been described up to this point in the tutorial) defines a function in the Card Structure that loops through the Suit and Rank enumerations without needing to know any of the enumeration values and returns an Array:

下面的代码(尽可能只使用本教程中到目前为止所描述的内容)定义了Card结构中的一个函数,该函数遍历Suit和Rank枚举,无需知道任何枚举值并返回一个数组:

static func deck() -> [Card] {
    var deck = [Card]()
    var suitCount = 1
    while let suit = Suit(rawValue: suitCount) {
        var rankCount = 1
        while let rank = Rank(rawValue: rankCount) {
            deck.append(Card(rank: rank, suit: suit))
            rankCount += 1
        }
        suitCount += 1
    }
    return deck
}

Invoke this with:

用以下方式调用:

let deck = Card.deck()
var card3 = deck[3].simpleDescription()

Copy the function into the Card structure and try adding values to enums. Note the following:

将该函数复制到Card结构中,然后尝试将值添加到枚举中。请注意以下事项:

  • how the number of times the loops are executed changes when adding to the enums
  • 添加到枚举时,循环执行的次数如何变化
  • that both enum counters start at 1 (if not otherwise specified in the enumeration the first raw value is one)
  • 两个枚举计数器从1开始(如果在枚举中没有另外指定,则第一个原始值为1)
  • unspecified array indexes start at 0 (e.g., deck[3] is actually the 4 of Spades)
  • 未指定的数组索引从0开始(例如,deck [3]实际上是3个黑桃)

#3


3  

The experiment asks for a method to Card. So I I declared the method as being static so that it acts on the struct and not an instance of it:

实验要求卡的方法。所以我将该方法声明为静态,以便它作用于struct而不是它的实例:

struct Card {
    var rank: Rank
    var suit: Suit

    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }

    static func deck() -> [Card] {
        var deck: [Card] = []
        for suit in [Suit.Spades, Suit.Hearts, Suit.Diamonds, Suit.Clubs] {
            for rank in 0...13 {
                if let unwrappedRank = Rank.fromRaw(rank) {
                    deck.append(Card(rank: unwrappedRank, suit: suit))
                }
            }
        }
        return deck
    }
}

To make use of it:

要使用它:

let deck = Card.deck()

Hope that helps.

希望有所帮助。

#4


1  

A for loop is the way to go. I made a few adjustments in your base code. First, I added a type to your Suit enum.

一个for循环是要走的路。我在你的基本代码中做了一些调整。首先,我在你的Suit枚举中添加了一个类型。

enum Suit : Int

Then I added a class called Deck which is responsible for a deck of cards.

然后我添加了一个名为Deck的类,它负责一副牌。

class Deck {
    var cards:Card[]

    init() {
        self.cards = Array<Card>()
    }

    func createDeck() {
        for suit in 0...Suit.Clubs.toRaw() {
            for rank in 1...Rank.King.toRaw() {
                self.cards += Card(rank: Rank.fromRaw(rank)!, suit: Suit.fromRaw(suit)!)
            }
        }
    }
}

func createDeck() loops through all possible playing cards and adds them to your deck.

func createDeck()循环遍历所有可能的扑克牌并将它们添加到你的牌组中。

#5


0  

First I'll tackle the easiest question: Where you put the code that creates the full deck is up to you, but I would advise you not to put it in Card, but rather create a Deck class and provide a convenience initializer to do it there.

首先,我将解决最简单的问题:你在哪里放置创建完整套牌的代码取决于你,但我建议你不要把它放在Card中,而是创建一个Deck类并提供一个方便的初始化程序来完成它那里。

That said, let's continue with the plan of adding it to the Card class. Unfortunately there is no way to just loop over all possible values of an Enum in the way you'd hope (though I'd love to be wrong about this!), but you can do this:

也就是说,让我们继续将其添加到Card类的计划。不幸的是,没有办法以你希望的方式循环遍历Enum的所有可能值(尽管我喜欢这个错误!),但你可以这样做:

let first_card = Rank.Ace.toRaw() // == 1
let last_card = Rank.King.toRaw() // == 13

for raw_rank in first_card...last_card {
    let rank = Rank.fromRaw(raw_rank)!
}

Let's walk through this. An Enum assigns an underlying value to each case, and by writing case Ace = 1 you're setting it up to start counting from 1 (rather than 0, the default). The API provided by an Enum for accessing the underlying value is a toRaw() method on each Enum case (The Enum itself also provides it in the form of Rank.toRaw(Rank.Ace).

让我们来看看这个。 Enum为每个案例分配一个基础值,并通过编写案例Ace = 1,您将其设置为从1开始计数(而不是0,默认值)。 Enum提供的用于访问基础值的API是每个Enum案例上的toRaw()方法(Enum本身也以Rank.toRaw(Rank.Ace)的形式提供它。

You can convert back from the raw value using the aptly named fromRaw() method (so Rank.fromRaw(1) would give us Ace) but there is a caveat: It returns an optional. The return type is Rank?, not Rank. In order to access the value you need to either check for nil, or force unwrap it.

你可以使用恰当命名的fromRaw()方法从原始值转换回来(所以Rank.fromRaw(1)会给我们Ace)但是有一个警告:它返回一个可选的。返回类型是Rank ?,而不是Rank。要访问该值,您需要检查nil,或强制打开它。

Checking for nil:

检查零:

if let rank = Rank.fromRaw(1) {
    // Do stuff with rank, which is now a plain old Rank
}
else {
    // handle nil
}

Force unwrap:

强制打开:

var rank: Rank = Rank.fromRaw(1)!

So to answer your question about the loops: Yes, that's the way to do it =P, and yes again about the array, though that's a design decision. It makes just as much sense to create a Deck class and return that instead.

所以回答你关于循环的问题:是的,这是做到这一点的方式= P,对于数组再次是,尽管这是一个设计决策。创建一个Deck类并返回它同样有意义。

Let's add the method using an extension. Extensions let you add functionality to an existing type. You can create an extension on a class, enum, or even a primitive type. pretty much anything.

让我们使用扩展名添加方法。通过扩展,您可以向现有类型添加功能。您可以在类,枚举或甚至基本类型上创建扩展。几乎任何东西。

extension Card {

    func createFullDeck() -> Card[] {
        var deck: Array<Card> = []
        for raw_rank in Rank.Ace.toRaw()...Rank.King.toRaw() {
            deck += [
                Card(rank:Rank.fromRaw(raw_rank)!, suit:.Spades),
                Card(rank:Rank.fromRaw(raw_rank)!, suit:.Hearts),
                Card(rank:Rank.fromRaw(raw_rank)!, suit:.Diamonds),
                Card(rank:Rank.fromRaw(raw_rank)!, suit:.Clubs),
            ]
        }
        return deck
    }

}

#6


0  

I read the answers above, but then I couldn't use the method ... unless it is a class method. So I added "static" before the 2 methods I added, and here is my proposal:

我阅读了上面的答案,但后来我无法使用该方法......除非它是一个类方法。所以我在添加的两个方法之前添加了“静态”,这是我的建议:

struct Card {
  var rank: Rank
  var suit: Suit

  func simpleDescription() -> String {
    return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
  }

  static func createDeck() -> Card[] {
    var deck = Card[]()
    for suit in [Suit.Spades, Suit.Clubs, Suit.Hearts, Suit.Diamonds] {
        for rankRawValue in 1...13 {
            let rank = Rank.fromRaw(rankRawValue)
            let card = Card(rank: rank!, suit: suit)
            deck += card
        }
    }
    return deck
  }

  static func printDeck(deck:Card[]) {
    for card in deck {
        println(card.simpleDescription())
    }
  }
}

let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()

let deck = Card.createDeck()
Card.printDeck(deck)

But I agree, a "Deck" class would be a better option ...

但我同意,“甲板”课程将是一个更好的选择......

#7


0  

Surprisingly, no one has yet had a stab at a functional implementation. Here goes:

令人惊讶的是,还没有人对功能实现有所了解。开始:

extension Array {
  func flatten<T>() -> T[] {
    let xs = (self as Any) as Array<Array<T>>
    return xs.reduce(T[]()) { (x, acc) in x + acc }
  }
}

extension Card {
  static func fullDeck() -> Card[] {
    let rawRanks = Array(Rank.Ace.toRaw()...Rank.King.toRaw())
    let suits: Suit[] = [.Spades, .Hearts, .Diamonds, .Clubs]
    return (rawRanks.map {
      rawRank in suits.map {
        suit in Card(rank: Rank.fromRaw(rawRank)!, suit: suit)
        }
      }).flatten()
  }
}

#8


0  

Trying to avoid knowledge of the enum definition... It seems clumsy (I'm a beginner), and still needs the starting index: 0 for Suit, 1 for Rank.

试图避免知道枚举定义...它看起来很笨拙(我是初学者),仍然需要起始索引:0表示套装,1表示Rank。

struct Card {
    var rank: Rank
    var suit: Suit
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
    static func deck() -> [Card] {
        var deck = [Card]()
        var suitCount = 0
        while (Suit(rawValue: suitCount) != nil) {
            var rankCount = 1
            while (Rank(rawValue: rankCount) != nil) {
                deck.append(Card(rank: Rank(rawValue: rankCount)!, suit: Suit(rawValue: suitCount)!))
                rankCount++
            }
            suitCount++
        }
        return deck
    }
}
let deck = Card.deck()

#9


0  

I just started learning Swift also, and had this same problem. I too thought it was rather odd that the experiment was to create a method inside the Card structure to create a full deck of cards.

我刚刚开始学习Swift,并遇到了同样的问题。我也认为实验是在Card结构中创建一个方法以创建一副完整的卡片,这是相当奇怪的。

After looking at these answers, and reading the official Apple "The Swift Programming Language (Swift 2.1)" tour, I solved it like this:

看完这些答案,并阅读官方Apple“The Swift Programming Language(Swift 2.1)”之旅后,我解决了这个问题:

struct Card {
    var rank: Rank
    var suit: Suit

    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }

    func createDeck() -> [Card] {
        let suits = [Suit.Spades, Suit.Hearts, Suit.Clubs, Suit.Diamonds]
        var deck = [Card]()

        for theSuit in suits {
            for theRank in Rank.Ace.rawValue...Rank.King.rawValue {
                deck.append(Card(rank: Rank(rawValue: theRank)!, suit: theSuit))
            }
        }

        return deck
    }
}

let aceOfHearts = Card(rank: .Ace, suit: .Hearts)
let deck = aceOfHearts.createDeck()

for card in deck {
    print("\(card.rank) of \(card.suit)")
}

#10


0  

Here's the whole solution for Swift 3:

这是Swift 3的完整解决方案:

struct Card {

    var rank: Rank
    var suit: Suit

    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
    func createDeck() -> [Card] {
        let suits = [Suit.spades, Suit.hearts, Suit.clubs, Suit.diamonds]
        var deck = [Card]()

        for theSuit in suits {
            for theRank in Rank.Ace.rawValue...Rank.King.rawValue {
                deck.append(Card(rank: Rank(rawValue: theRank)!, suit: theSuit))
            }
        }
        return deck
    }
}

You can call it like this:

你可以这样称呼它:

let aceOfHearts = Card(rank: .Ace, suit: .hearts)
let deck = aceOfHearts.createDeck()

#11


0  

Since all the examples above are imperative in nature and Swift is built with functional programming in mind, I took a more functional approach to solving the problem. Here's my full set of code:

由于上面的所有示例都是本质上必不可少的,并且Swift是在考虑函数式编程的情况下构建的,因此我采用了更加实用的方法来解决问题。这是我的全套代码:

My Rank enum (have to define an array with all the values because it's not possible to iterate over all the values of an enum for some reason)

我的Rank枚举(必须定义一个包含所有值的数组,因为由于某种原因无法迭代枚举的所有值)

enum Rank: Int, CustomStringConvertible {

    case ace = 1
    case two, three, four, five, six, seven, eight, nine, ten
    case jack, queen, king

    static let allRanks = [ace, two, three, four, five, six, seven, eight, nine, ten, jack, queen, king]

    var description: String {
        switch self {
        case .ace:
            return "ace"
        case .jack:
            return "jack"
        case .queen:
            return "queen"
        case .king:
            return "king"
        default:
            return String(self.rawValue)
        }
    }
}

Suit enum (added similar type of array)

适合enum(添加类似类型的数组)

enum Suit: String, CustomStringConvertible  {

    case spades = "♠︎"
    case hearts = "♥︎"
    case diamonds = "♦︎"
    case clubs = "♣︎"

    static let allSuits = [spades, hearts, diamonds, clubs]

    var description: String {
        switch self {
        default:
            return rawValue
        }
    }

}

...and finally the card:

......最后卡片:

struct Card: CustomStringConvertible {
    var rank: Rank
    var suit: Suit

    var description: String {
        return "\(rank)\(suit)"
    }

    static func createDeckOfCards() -> [Card] {
        return Suit.allSuits.reduce([]) {
            deck, suit in deck + Rank.allRanks.reduce([]) {
                cardsInSuit, rank in cardsInSuit + [Card(rank: rank, suit: suit)]
            }
        }
    }
}

print(Card.createDeckOfCards())

#12


0  

I left everything like in Swift Tour, Suit is String and Rank is Int.

我把一切都留在Swift Tour中,Suit是String,Rank是Int。

struct Card {
    var rank: Rank
    var suit: Suit

    func simpleDescription () -> String{
        return "The \(rank.simpleDescription()) of \suit.simpleDescription())"
}

    func createDeck() -> [Card] {
        var n = 1
        var deck = [Card]()
        let suits = [Suit.spades, Suit.hearts, Suit.diamonds, Suit.clubs]
        while let rank = Rank(rawValue: n) {
            for suit in suits {
                deck.append(Card(rank: rank, suit: suit))
            }
            n += 1
        }
        return deck
    }
}   
let card = Card (rank: Rank.ace, suit: Suit.spades)
let deck = card.createDeck()

#1


17  

Here's another way of doing it, this time only using techniques you would have learned up to that point*

这是另一种方法,这次只使用你到目前为止学到的技术*

First we define the possible ranks and suits, using the respective Rank and Suit enums defined previously.

首先,我们使用先前定义的相应Rank和Suit枚举来定义可能的等级和套装。

Next we have the function iterate over each rank within each suit, creating a card for each, and finally returning an array of the cards.

接下来,我们让函数迭代每个套装中的每个等级,为每个套装创建一张卡片,最后返回一组卡片。

struct Card {
    var rank: Rank
    var suit: Suit
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }

    func createDeck() -> Card[] {
        let ranks = [Rank.Ace, Rank.Two, Rank.Three, Rank.Four, Rank.Five, Rank.Six, Rank.Seven, Rank.Eight, Rank.Nine, Rank.Ten, Rank.Jack, Rank.Queen, Rank.King]
        let suits = [Suit.Spades, Suit.Hearts, Suit.Diamonds, Suit.Clubs]
        var deck = Card[]()
        for suit in suits {
            for rank in ranks {
                deck.append(Card(rank: rank, suit: suit))
            }
        }
        return deck
    }
}

(* with the notable exception that the tour hadn't explicitly explained how to append to arrays at that point)

(*有一个值得注意的例外,即巡演没有明确解释当时如何附加到数组)

#2


8  

A robust code answer will not to the use actual values (i.e., .Spades) from the enumerations when generating the deck, e.g., if a "Joker" is added later to the Rank enumeration (anywhere in the enumeration), the deck generation function should still work without change.

一个健壮的代码答案将不会在生成套牌时使用枚举中的实际值(即.Spades),例如,如果稍后将“Joker”添加到Rank枚举(枚举中的任何位置),则甲板生成函数应该仍然没有改变。

The design questions (what to return?, should the deck generation be a function of card?) are not really relevant to this tutorial, but it is likely that a Deck class would be preferable if any serious functionality is going to be built out further (e.g., shuffle). So for now, returning an Array from a function in the Card structure is all that is required.

设计问题(要返回什么?,甲板生成应该是卡的功能吗?)与本教程并不真正相关,但如果要进一步构建任何严格的功能,可能会更喜欢Deck类(例如,洗牌)。所以现在,只需要从Card结构中的函数返回一个数组。

The following code (as far as possible only using what has been described up to this point in the tutorial) defines a function in the Card Structure that loops through the Suit and Rank enumerations without needing to know any of the enumeration values and returns an Array:

下面的代码(尽可能只使用本教程中到目前为止所描述的内容)定义了Card结构中的一个函数,该函数遍历Suit和Rank枚举,无需知道任何枚举值并返回一个数组:

static func deck() -> [Card] {
    var deck = [Card]()
    var suitCount = 1
    while let suit = Suit(rawValue: suitCount) {
        var rankCount = 1
        while let rank = Rank(rawValue: rankCount) {
            deck.append(Card(rank: rank, suit: suit))
            rankCount += 1
        }
        suitCount += 1
    }
    return deck
}

Invoke this with:

用以下方式调用:

let deck = Card.deck()
var card3 = deck[3].simpleDescription()

Copy the function into the Card structure and try adding values to enums. Note the following:

将该函数复制到Card结构中,然后尝试将值添加到枚举中。请注意以下事项:

  • how the number of times the loops are executed changes when adding to the enums
  • 添加到枚举时,循环执行的次数如何变化
  • that both enum counters start at 1 (if not otherwise specified in the enumeration the first raw value is one)
  • 两个枚举计数器从1开始(如果在枚举中没有另外指定,则第一个原始值为1)
  • unspecified array indexes start at 0 (e.g., deck[3] is actually the 4 of Spades)
  • 未指定的数组索引从0开始(例如,deck [3]实际上是3个黑桃)

#3


3  

The experiment asks for a method to Card. So I I declared the method as being static so that it acts on the struct and not an instance of it:

实验要求卡的方法。所以我将该方法声明为静态,以便它作用于struct而不是它的实例:

struct Card {
    var rank: Rank
    var suit: Suit

    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }

    static func deck() -> [Card] {
        var deck: [Card] = []
        for suit in [Suit.Spades, Suit.Hearts, Suit.Diamonds, Suit.Clubs] {
            for rank in 0...13 {
                if let unwrappedRank = Rank.fromRaw(rank) {
                    deck.append(Card(rank: unwrappedRank, suit: suit))
                }
            }
        }
        return deck
    }
}

To make use of it:

要使用它:

let deck = Card.deck()

Hope that helps.

希望有所帮助。

#4


1  

A for loop is the way to go. I made a few adjustments in your base code. First, I added a type to your Suit enum.

一个for循环是要走的路。我在你的基本代码中做了一些调整。首先,我在你的Suit枚举中添加了一个类型。

enum Suit : Int

Then I added a class called Deck which is responsible for a deck of cards.

然后我添加了一个名为Deck的类,它负责一副牌。

class Deck {
    var cards:Card[]

    init() {
        self.cards = Array<Card>()
    }

    func createDeck() {
        for suit in 0...Suit.Clubs.toRaw() {
            for rank in 1...Rank.King.toRaw() {
                self.cards += Card(rank: Rank.fromRaw(rank)!, suit: Suit.fromRaw(suit)!)
            }
        }
    }
}

func createDeck() loops through all possible playing cards and adds them to your deck.

func createDeck()循环遍历所有可能的扑克牌并将它们添加到你的牌组中。

#5


0  

First I'll tackle the easiest question: Where you put the code that creates the full deck is up to you, but I would advise you not to put it in Card, but rather create a Deck class and provide a convenience initializer to do it there.

首先,我将解决最简单的问题:你在哪里放置创建完整套牌的代码取决于你,但我建议你不要把它放在Card中,而是创建一个Deck类并提供一个方便的初始化程序来完成它那里。

That said, let's continue with the plan of adding it to the Card class. Unfortunately there is no way to just loop over all possible values of an Enum in the way you'd hope (though I'd love to be wrong about this!), but you can do this:

也就是说,让我们继续将其添加到Card类的计划。不幸的是,没有办法以你希望的方式循环遍历Enum的所有可能值(尽管我喜欢这个错误!),但你可以这样做:

let first_card = Rank.Ace.toRaw() // == 1
let last_card = Rank.King.toRaw() // == 13

for raw_rank in first_card...last_card {
    let rank = Rank.fromRaw(raw_rank)!
}

Let's walk through this. An Enum assigns an underlying value to each case, and by writing case Ace = 1 you're setting it up to start counting from 1 (rather than 0, the default). The API provided by an Enum for accessing the underlying value is a toRaw() method on each Enum case (The Enum itself also provides it in the form of Rank.toRaw(Rank.Ace).

让我们来看看这个。 Enum为每个案例分配一个基础值,并通过编写案例Ace = 1,您将其设置为从1开始计数(而不是0,默认值)。 Enum提供的用于访问基础值的API是每个Enum案例上的toRaw()方法(Enum本身也以Rank.toRaw(Rank.Ace)的形式提供它。

You can convert back from the raw value using the aptly named fromRaw() method (so Rank.fromRaw(1) would give us Ace) but there is a caveat: It returns an optional. The return type is Rank?, not Rank. In order to access the value you need to either check for nil, or force unwrap it.

你可以使用恰当命名的fromRaw()方法从原始值转换回来(所以Rank.fromRaw(1)会给我们Ace)但是有一个警告:它返回一个可选的。返回类型是Rank ?,而不是Rank。要访问该值,您需要检查nil,或强制打开它。

Checking for nil:

检查零:

if let rank = Rank.fromRaw(1) {
    // Do stuff with rank, which is now a plain old Rank
}
else {
    // handle nil
}

Force unwrap:

强制打开:

var rank: Rank = Rank.fromRaw(1)!

So to answer your question about the loops: Yes, that's the way to do it =P, and yes again about the array, though that's a design decision. It makes just as much sense to create a Deck class and return that instead.

所以回答你关于循环的问题:是的,这是做到这一点的方式= P,对于数组再次是,尽管这是一个设计决策。创建一个Deck类并返回它同样有意义。

Let's add the method using an extension. Extensions let you add functionality to an existing type. You can create an extension on a class, enum, or even a primitive type. pretty much anything.

让我们使用扩展名添加方法。通过扩展,您可以向现有类型添加功能。您可以在类,枚举或甚至基本类型上创建扩展。几乎任何东西。

extension Card {

    func createFullDeck() -> Card[] {
        var deck: Array<Card> = []
        for raw_rank in Rank.Ace.toRaw()...Rank.King.toRaw() {
            deck += [
                Card(rank:Rank.fromRaw(raw_rank)!, suit:.Spades),
                Card(rank:Rank.fromRaw(raw_rank)!, suit:.Hearts),
                Card(rank:Rank.fromRaw(raw_rank)!, suit:.Diamonds),
                Card(rank:Rank.fromRaw(raw_rank)!, suit:.Clubs),
            ]
        }
        return deck
    }

}

#6


0  

I read the answers above, but then I couldn't use the method ... unless it is a class method. So I added "static" before the 2 methods I added, and here is my proposal:

我阅读了上面的答案,但后来我无法使用该方法......除非它是一个类方法。所以我在添加的两个方法之前添加了“静态”,这是我的建议:

struct Card {
  var rank: Rank
  var suit: Suit

  func simpleDescription() -> String {
    return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
  }

  static func createDeck() -> Card[] {
    var deck = Card[]()
    for suit in [Suit.Spades, Suit.Clubs, Suit.Hearts, Suit.Diamonds] {
        for rankRawValue in 1...13 {
            let rank = Rank.fromRaw(rankRawValue)
            let card = Card(rank: rank!, suit: suit)
            deck += card
        }
    }
    return deck
  }

  static func printDeck(deck:Card[]) {
    for card in deck {
        println(card.simpleDescription())
    }
  }
}

let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()

let deck = Card.createDeck()
Card.printDeck(deck)

But I agree, a "Deck" class would be a better option ...

但我同意,“甲板”课程将是一个更好的选择......

#7


0  

Surprisingly, no one has yet had a stab at a functional implementation. Here goes:

令人惊讶的是,还没有人对功能实现有所了解。开始:

extension Array {
  func flatten<T>() -> T[] {
    let xs = (self as Any) as Array<Array<T>>
    return xs.reduce(T[]()) { (x, acc) in x + acc }
  }
}

extension Card {
  static func fullDeck() -> Card[] {
    let rawRanks = Array(Rank.Ace.toRaw()...Rank.King.toRaw())
    let suits: Suit[] = [.Spades, .Hearts, .Diamonds, .Clubs]
    return (rawRanks.map {
      rawRank in suits.map {
        suit in Card(rank: Rank.fromRaw(rawRank)!, suit: suit)
        }
      }).flatten()
  }
}

#8


0  

Trying to avoid knowledge of the enum definition... It seems clumsy (I'm a beginner), and still needs the starting index: 0 for Suit, 1 for Rank.

试图避免知道枚举定义...它看起来很笨拙(我是初学者),仍然需要起始索引:0表示套装,1表示Rank。

struct Card {
    var rank: Rank
    var suit: Suit
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
    static func deck() -> [Card] {
        var deck = [Card]()
        var suitCount = 0
        while (Suit(rawValue: suitCount) != nil) {
            var rankCount = 1
            while (Rank(rawValue: rankCount) != nil) {
                deck.append(Card(rank: Rank(rawValue: rankCount)!, suit: Suit(rawValue: suitCount)!))
                rankCount++
            }
            suitCount++
        }
        return deck
    }
}
let deck = Card.deck()

#9


0  

I just started learning Swift also, and had this same problem. I too thought it was rather odd that the experiment was to create a method inside the Card structure to create a full deck of cards.

我刚刚开始学习Swift,并遇到了同样的问题。我也认为实验是在Card结构中创建一个方法以创建一副完整的卡片,这是相当奇怪的。

After looking at these answers, and reading the official Apple "The Swift Programming Language (Swift 2.1)" tour, I solved it like this:

看完这些答案,并阅读官方Apple“The Swift Programming Language(Swift 2.1)”之旅后,我解决了这个问题:

struct Card {
    var rank: Rank
    var suit: Suit

    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }

    func createDeck() -> [Card] {
        let suits = [Suit.Spades, Suit.Hearts, Suit.Clubs, Suit.Diamonds]
        var deck = [Card]()

        for theSuit in suits {
            for theRank in Rank.Ace.rawValue...Rank.King.rawValue {
                deck.append(Card(rank: Rank(rawValue: theRank)!, suit: theSuit))
            }
        }

        return deck
    }
}

let aceOfHearts = Card(rank: .Ace, suit: .Hearts)
let deck = aceOfHearts.createDeck()

for card in deck {
    print("\(card.rank) of \(card.suit)")
}

#10


0  

Here's the whole solution for Swift 3:

这是Swift 3的完整解决方案:

struct Card {

    var rank: Rank
    var suit: Suit

    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
    func createDeck() -> [Card] {
        let suits = [Suit.spades, Suit.hearts, Suit.clubs, Suit.diamonds]
        var deck = [Card]()

        for theSuit in suits {
            for theRank in Rank.Ace.rawValue...Rank.King.rawValue {
                deck.append(Card(rank: Rank(rawValue: theRank)!, suit: theSuit))
            }
        }
        return deck
    }
}

You can call it like this:

你可以这样称呼它:

let aceOfHearts = Card(rank: .Ace, suit: .hearts)
let deck = aceOfHearts.createDeck()

#11


0  

Since all the examples above are imperative in nature and Swift is built with functional programming in mind, I took a more functional approach to solving the problem. Here's my full set of code:

由于上面的所有示例都是本质上必不可少的,并且Swift是在考虑函数式编程的情况下构建的,因此我采用了更加实用的方法来解决问题。这是我的全套代码:

My Rank enum (have to define an array with all the values because it's not possible to iterate over all the values of an enum for some reason)

我的Rank枚举(必须定义一个包含所有值的数组,因为由于某种原因无法迭代枚举的所有值)

enum Rank: Int, CustomStringConvertible {

    case ace = 1
    case two, three, four, five, six, seven, eight, nine, ten
    case jack, queen, king

    static let allRanks = [ace, two, three, four, five, six, seven, eight, nine, ten, jack, queen, king]

    var description: String {
        switch self {
        case .ace:
            return "ace"
        case .jack:
            return "jack"
        case .queen:
            return "queen"
        case .king:
            return "king"
        default:
            return String(self.rawValue)
        }
    }
}

Suit enum (added similar type of array)

适合enum(添加类似类型的数组)

enum Suit: String, CustomStringConvertible  {

    case spades = "♠︎"
    case hearts = "♥︎"
    case diamonds = "♦︎"
    case clubs = "♣︎"

    static let allSuits = [spades, hearts, diamonds, clubs]

    var description: String {
        switch self {
        default:
            return rawValue
        }
    }

}

...and finally the card:

......最后卡片:

struct Card: CustomStringConvertible {
    var rank: Rank
    var suit: Suit

    var description: String {
        return "\(rank)\(suit)"
    }

    static func createDeckOfCards() -> [Card] {
        return Suit.allSuits.reduce([]) {
            deck, suit in deck + Rank.allRanks.reduce([]) {
                cardsInSuit, rank in cardsInSuit + [Card(rank: rank, suit: suit)]
            }
        }
    }
}

print(Card.createDeckOfCards())

#12


0  

I left everything like in Swift Tour, Suit is String and Rank is Int.

我把一切都留在Swift Tour中,Suit是String,Rank是Int。

struct Card {
    var rank: Rank
    var suit: Suit

    func simpleDescription () -> String{
        return "The \(rank.simpleDescription()) of \suit.simpleDescription())"
}

    func createDeck() -> [Card] {
        var n = 1
        var deck = [Card]()
        let suits = [Suit.spades, Suit.hearts, Suit.diamonds, Suit.clubs]
        while let rank = Rank(rawValue: n) {
            for suit in suits {
                deck.append(Card(rank: rank, suit: suit))
            }
            n += 1
        }
        return deck
    }
}   
let card = Card (rank: Rank.ace, suit: Suit.spades)
let deck = card.createDeck()