Добавьте способ к Карте, который создает полную колоду карт, с одной картой каждой комбинации ранга и костюма

Итак, я делал эксперименты, которые находятся в книге Apple Swift.

Я смог сделать все, кроме этого, до сих пор. Ниже я попытался, но я не могу понять, как заставить его работать.

Добавьте способ к Карте, который создает полную колоду карт, с одной картой каждой комбинации ранга и костюма.

// 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()
  • Я не знаю, что я должен вернуть для этого метода, Array?
  • Должен ли я использовать цикл for для создания этого? или есть правильный/более простой способ сделать это с перечислением
  • Почему я должен создать этот метод внутри карты, вызов threeOfSpades.createFullDeck() кажется неправильным.

Ответ 1

Вот еще один способ сделать это, на этот раз только с использованием техник, которые вы изучили до этого момента *

Сначала мы определяем возможные ранги и масти, используя соответствующие перечисления 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
    }
}

(* с заметным исключением, что в туре не было явного объяснения, как добавлять массивы в этот момент)

Ответ 2

Надежный ответ кода не будет использовать фактические значения (т.е..Spades) из перечислений при создании колоды, например, если "Джокер" добавляется позже к перечислению Ранга (в любом месте перечисления), функция генерации колоды должна работать без изменений.

Вопросы дизайна (что вернуть?, если генерация колоды будет функцией карты?) не имеют отношения к этому учебнику, но вполне вероятно, что класс Deck был бы предпочтительнее, если бы какая-либо серьезная функциональность была (например, перетасовка). Так что теперь возвращение массива из функции в структуре карты - это все, что требуется.

Следующий код (насколько это возможно, только с использованием того, что было описано до этого момента в учебнике) определяет функцию в структуре карты, которая проходит через списки Кодекса и Ранга без необходимости знать какие-либо из значений перечисления и возвращает массив:

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

Скопируйте функцию в структуру Карты и попробуйте добавить значения к перечислениям. Обратите внимание на следующее:

  • Как количество циклов, выполняемых циклами, изменяется при добавлении в перечисления
  • что оба счетчика перечисления начинаются с 1 (если в перечислении не указано иначе, первое исходное значение равно единице)
  • индексы неуказанных массивов начинаются с 0 (например, колода [3] на самом деле является 4 пиками)

Ответ 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()

Надеюсь, что это поможет.

Ответ 4

А для цикла - путь. Я сделал несколько настроек в вашем базовом коде. Во-первых, я добавил тип к вашему перечислению 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

Я оставил все, как в 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

Сначала я рассмотрю самый простой вопрос: где вы помещаете код, который создает полную колоду, зависит от вас, но я бы посоветовал вам не помещать его в Card, а создать класс Deck и инициализатор удобства, чтобы сделать это там.

Тем не менее, продолжайте с планом добавления его в класс 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)!
}

Пройдите через это. Enum присваивает базовое значение каждому случаю, и, написав case Ace = 1, вы настраиваете его, чтобы начать подсчет с 1 (а не 0, по умолчанию). API, предоставляемый Enum для доступа к базовому значению, представляет собой метод toRaw() для каждого случая Enum (сам Enum также предоставляет его в виде Rank.toRaw(Rank.Ace).

Вы можете преобразовать обратно из необработанного значения с помощью метода aptly с именем fromRaw() (так что Rank.fromRaw(1) предоставит нам Ace), но есть оговорка: он возвращает необязательный. Тип возврата Rank?, не Rank. Чтобы получить доступ к значению, нужно либо проверить нуль, либо принудительно развернуть его.

Проверка на ноль:

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
    }

}

Ответ 7

Я прочитал ответы выше, но тогда я не мог использовать метод... если это не метод класса. Поэтому я добавил "статический" перед двумя добавленными мной методами, и вот мое предложение:

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)

Но я согласен, класс "Deck" был бы лучшим вариантом...

Ответ 8

Удивительно, но никто еще не получил удар по функциональной реализации. Здесь:

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

Ответ 9

Попытка избежать знания определения enum... Кажется неуклюжим (я новичок) и все еще нуждается в начальном индексе: 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()

Ответ 10

Я тоже начал изучать Свифта и имел ту же проблему. Я тоже думал, что было довольно странно, что эксперимент заключался в создании метода внутри структуры Card для создания полной колоды карт.

После просмотра этих ответов и ознакомления с официальным курсом Apple "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)")
}

Ответ 11

Здесь все решение для 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()

Ответ 12

Поскольку все приведенные выше примеры необходимы по своей природе, и Swift построен с функциональным программированием, я использовал более функциональный подход к решению проблемы. Вот мой полный набор кода:

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

Suit 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

Как разработчик 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
}

Я согласен с парнем, приведенным выше, в классе будет больше смысла, потому что в этом примере вам сначала нужно инициализировать карту, чтобы вызвать эту функцию...