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

时间:2014-06-08 18:56:01

标签: swift swift-playground

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

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

  

添加一个方法到,创建一副完整的卡片组,每张卡片都有等级和套装。

// 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循环来创建吗?或者使用enum
  • 是否有适当/更简单的方法
  • 为什么我会在 Card 中创建此方法,调用threeOfSpades.createFullDeck()似乎不正确。

18 个答案:

答案 0 :(得分:17)

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

首先,我们使用之前定义的相应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
    }
}

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

答案 1 :(得分:8)

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

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

以下代码(尽可能仅使用本教程中到目前为止所描述的内容)定义了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
}

用以下方式调用:

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

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

  • 添加到枚举
  • 时循环执行次数的变化情况
  • 两个枚举计数器从1开始(如果在枚举中没有另外指定,则第一个原始值为1)
  • 未指定的数组索引从0开始(例如,deck [3]实际上是3个黑桃)

答案 2 :(得分:3)

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

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()

希望有所帮助。

答案 3 :(得分:1)

通过遵守vtable协议,您将免费获得CaseIterable计算属性:

allCases

然后您可以使用 extension Rank: CaseIterable { } extension Suit: CaseIterable { } 一次性完成所有操作:

map

func createDeck() -> [Card] { Suit.allCases.flatMap{ s in Rank.allCases.map{ r in Card(rank: r, suit: s) }} } 用于将嵌套数组转换为一维(平面)数组。

答案 4 :(得分: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()遍历所有可能的扑克牌并将其添加到你的套牌中。

答案 5 :(得分: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()

答案 6 :(得分:0)

这是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()

答案 7 :(得分: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 解决方案。但这只是另一种似乎有效的变体,不胜感激同行评审。

答案 8 :(得分:0)

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

首先:

符合CaseIterable 协议

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

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

<块引用>

Suit.allCases

Rank.allCases

第二:

然后您可以使用 map 一次性完成所有操作:

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

zip 将构建需求,map 将全部转换为 Cards

答案 9 :(得分: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 关键字。

答案 10 :(得分: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)
}

结果将显示纸牌的所有值。

答案 11 :(得分: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才能调用此函数...

答案 12 :(得分:0)

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

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

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(添加类似类型的数组)

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())

答案 13 :(得分:0)

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

看完这些答案,并阅读官方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)")
}

答案 14 :(得分:0)

试图避免知道枚举定义......看起来很笨拙(我是初学者),仍然需要起始索引: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()

答案 15 :(得分: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()
  }
}

答案 16 :(得分:0)

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

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)

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

答案 17 :(得分:0)

首先,我将解决最简单的问题:在哪里放置创建完整套牌的代码取决于您,但我建议您将其放入Card,而是创建一个Deck类并在那里提供convenience initializer

那就是说,让我们继续把它添加到Card课程的计划。不幸的是,没有办法以你希望的方式循环遍历Enum的所有可能值(虽然我喜欢这个错误!),但你可以这样做:< / p>

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

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

您可以使用恰当命名的fromRaw()方法从原始值转换回来(因此Rank.fromRaw(1)会给我们Ace),但有一个警告:它返回一个可选项。返回类型为Rank? Rank。要访问either check for nil, or force unwrap it所需的值。

检查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类并返回它同样有意义。

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

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
    }

}