Добавьте способ к Карте, который создает полную колоду карт, с одной картой каждой комбинации ранга и костюма
Итак, я делал эксперименты, которые находятся в книге 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
}
Я согласен с парнем, приведенным выше, в классе будет больше смысла, потому что в этом примере вам сначала нужно инициализировать карту, чтобы вызвать эту функцию...