所以我一直在做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()
threeOfSpades.createFullDeck()
似乎不正确。答案 0 :(得分:17)
这是另一种方法,这次只使用你到目前为止学到的技术*
首先,我们使用之前定义的相应Rank
和Suit
枚举来定义可能的排名和套装。
接下来,我们让函数迭代每个套装中的每个等级,为每个套装创建一张卡片,最后返回一组卡片。
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结构中并尝试向枚举中添加值。请注意以下事项:
答案 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
将全部转换为 Card
s
答案 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
}
}