17

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

到目前为止,我已经能够做到所有这些,除了这个。以下是我尝试过的,但我不知道如何让它工作。

向Card添加一个方法,该方法创建一副完整的纸牌,每个等级和花色组合都有一张纸牌。

// 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()
  • 我不知道我应该为那个方法返回什么,一个数组?
  • 我应该使用 for 循环来创建它吗?或者是否有适当/更简单的方法来使用枚举
  • 为什么我要在Card内部创建此方法,调用threeOfSpades.createFullDeck()似乎不正确。
4

18 回答 18

19

这是另一种方法,这一次只使用到那时你已经学会的技术*

首先,我们使用之前定义的相应RankSuit枚举来定义可能的等级和花色。

接下来,我们让函数遍历每个花色中的每个等级,为每个花色创建一张卡片,最后返回一个卡片数组。

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
    }
}

(* 值得注意的例外是,巡回赛当时没有明确解释如何附加到数组)

于 2014-06-12T14:02:20.930 回答
10

一个健壮的代码答案在生成牌组时不会使用枚举中的实际值(即.Spades),例如,如果稍后将“Joker”添加到 Rank 枚举(枚举中的任何位置),则牌组生成函数应该仍然可以正常工作。

设计问题(返回什么?,deck generation 是否应该是 card 的函数?)与本教程并不真正相关,但如果要进一步构建任何重要的功能,Deck 类可能会更可取(例如,随机播放)。所以现在,只需要从 Card 结构中的函数返回一个数组即可。

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

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
}

调用它:

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

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

  • 添加到枚举时循环执行的次数如何变化
  • 两个枚举计数器都从 1 开始(如果枚举中没有另外指定,则第一个原始值为 1)
  • 未指定的数组索引从 0 开始(例如,deck[3] 实际上是黑桃的 4)
于 2015-01-18T10:06:13.943 回答
3

实验要求一种方法来卡片。所以 II 将该方法声明为静态的,以便它作用于结构而不是它的实例:

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
    }
}

要使用它:

let deck = Card.deck()

希望有帮助。

于 2014-09-22T12:59:07.273 回答
2

通过符合CaseIterable 协议,您将allCases免费获得计算属性:

extension Rank: CaseIterable { }
extension Suit: CaseIterable { }

然后您可以使用maps 一次实现所有目标:

func createDeck() -> [Card] {
    Suit.allCases.flatMap{ s in Rank.allCases.map{ r in Card(rank: r, suit: s) }}
}

flatMap用于将嵌套数组转换为一维(平面)数组。

于 2021-04-24T23:17:29.657 回答
1

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

enum Suit : Int

然后我添加了一个名为 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()循环所有可能的扑克牌并将它们添加到您的牌组中。

于 2014-06-08T20:05:32.897 回答
1

我把所有东西都留在了 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()
于 2018-01-08T14:25:04.880 回答
1

这是 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
    }
}

你可以这样称呼它:

let aceOfHearts = Card(rank: .Ace, suit: .hearts)
let deck = aceOfHearts.createDeck()
于 2016-12-28T04:46:30.193 回答
1

您可以使用 zip 两个一次构建所有案例!

第一的:

符合CaseIterable 协议

extension Rank: CaseIterable { }
extension Suit: CaseIterable { }

因此,您将allCases免费获得计算属性:

适合所有案件

Rank.allCases

第二:

那么您可以使用maps 一次实现所有目标:

func createDeck() -> [Card] {
    zip(Rank.allCases, Suit.allCases).map { Card(rank: $0.0, suit: $0.1) }
}

zip建立需求,map并将所有转换为Cards

于 2021-04-25T12:48:56.950 回答
0

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

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)

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

于 2014-06-13T07:45:41.017 回答
0

首先,我将解决最简单的问题:您将创建完整套牌的代码放在哪里取决于您,但我建议您不要将其放入Card,而是创建一个Deck类并提供一个方便的初始化程序来执行此操作。

也就是说,让我们继续将其添加到Card课程中的计划。不幸的是,没有办法以您希望的方式循环遍历枚举的所有可能值(尽管我很想错了!),但您可以这样做:

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)!
}

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

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

检查零:

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

强制解包:

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

所以回答你关于循环的问题:是的,这就是这样做的方法=P,关于数组也是如此,尽管这是一个设计决定。Deck创建一个类并返回它同样有意义。

让我们使用扩展来添加方法。扩展允许您向现有类型添加功能。您可以在类、枚举甚至原始类型上创建扩展。几乎任何东西。

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
    }

}
于 2014-06-08T20:14:39.073 回答
0

令人惊讶的是,还没有人尝试过功能实现。开始:

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()
  }
}
于 2014-07-03T14:09:16.230 回答
0

试图避免了解枚举定义...看起来很笨拙(我是初学者),并且仍然需要起始索引:0 表示 Suit,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()
于 2014-11-21T19:50:22.807 回答
0
struct Card {
 let suit: Suit
 let rank: Rank

static func simpleDescription(suit: Suit, rank: Rank) -> String {
    let card = Card(suit: suit, rank: rank)
    return "The \(card.rank.simpleDescription) of \(card.suit.simpleDescription)"
}

static func createFullDeck() -> [Card]{
    var fullDeck = [Card]()
    let ranks = Range(2...14)
    let suits = Range(0...3)

    ranks.map { (rank) in
        suits.map { (suit) in
            let card = Card(suit: Suit(rawValue: suit)!, rank: Rank(rawValue: rank)!)
            fullDeck.append(card)
        }
    }
    return fullDeck
 }
}

用例

print(Card.simpleDescription(suit: .club, rank: .ace))

结果 = 俱乐部的王牌

Card.createFullDeck().map { (card) in
print(card.suit, card.rank)
}

结果打印卡片组的所有值。

于 2020-08-16T18:06:06.223 回答
0

作为一名 iOS 开发人员,我尝试每年阅读一次这本书/教程。今年,我想我会作为一个新手开发人员来处理它,看看我能根据教程给出的信息做些什么。正如https://stackoverflow.com/users/262455/jack-james指出的那样,他们可能还没有教过 .append。考虑到这一点,这是我的答案

func fullDeck() -> [String] {
    var deckOfCards = [String]()
    let suits = [Suit.clubs, Suit.diamonds, Suit.hearts, Suit.spades]
    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]
    for suit in suits {
        for rank in ranks {
            let card = Card(rank: rank, suit: suit)
            deckOfCards.append(card.simpleDescription())
        }
    }
    print(deckOfCards)
    return deckOfCards
}

我同意上面那个人的观点,一个类会更有意义,因为在这个例子中,你需要先初始化一个 Card 才能调用这个函数......

于 2018-11-26T21:24:00.597 回答
0

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

在查看了这些答案并阅读了 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)")
}
于 2015-10-15T15:25:34.867 回答
0

Array 的map方法允许在每个数组元素上调用闭包。使用有效的 Swift 语法,我们可以用一个调用来替换显式for循环:map

func createDeck() -> [Card] {
        [Suit.spades, Suit.hearts, Suit.diamonds, Suit.clubs].flatMap { suit in
            Array(1...13).map { Card(rank: Rank(rawValue: $0)!, suit: suit) }
        }
    }

flatMap用于将嵌套数组转换为一维(平面)数组。

$0是一种通过编号访问闭包参数的速记 Swift 语法。这允许跳过in内部闭包中的参数名称和关键字。

于 2021-04-24T21:51:42.487 回答
0
static func deck() -> [Card] {
    var deck = [Card]()
    for rankRawValue in Rank.ace.rawValue...Rank.king.rawValue {
        deck.append(Card(rank: Rank(rawValue: rankRawValue)!, suit: Suit.spades))
        deck.append(Card(rank: Rank(rawValue: rankRawValue)!, suit: Suit.hearts))
        deck.append(Card(rank: Rank(rawValue: rankRawValue)!, suit: Suit.diamonds))
        deck.append(Card(rank: Rank(rawValue: rankRawValue)!, suit: Suit.clubs))
    }
    return deck
}

已经提供了不止一个很好的答案,我喜欢 CaseIterable 解决方案。但这只是另一种似乎可行的变体,将不胜感激同行评审。

于 2021-05-04T11:54:48.480 回答
0

由于上述所有示例本质上都是命令式的,并且 Swift 构建时考虑到了函数式编程,因此我采用了一种更实用的方法来解决问题。这是我的全套代码:

我的 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)
        }
    }
}

适合枚举(添加了类似类型的数组)

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
        }
    }

}

...最后是卡片:

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())
于 2017-04-07T23:18:25.410 回答