Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add a method to Card that creates a full deck of cards, with one card of each combination of rank and suit

So I have been doing the experiments that are in the Apple Swift Book.

I have been able to do all of them, except for this one so far. Below is what I have tried, but I can't figure out how to get it working.

Add a method to Card that creates a full deck of cards, with one card of each combination of rank and suit.

// 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()
  • I don't know what I am supposed to return for that method, an Array?
  • Should I use a for loop to create this? or is there a proper/easier way to do this with enum
  • Why would I create this method inside of Card, calling threeOfSpades.createFullDeck() seems incorrect.
like image 371
Arian Faurtosh Avatar asked Jun 08 '14 18:06

Arian Faurtosh


3 Answers

Here's another way of doing it, this time only using techniques you would have learned up to that point*

First we define the possible ranks and suits, using the respective Rank and Suit enums defined previously.

Next we have the function iterate over each rank within each suit, creating a card for each, and finally returning an array of the cards.

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

(* with the notable exception that the tour hadn't explicitly explained how to append to arrays at that point)

like image 98
Jack James Avatar answered Oct 30 '22 20:10

Jack James


A robust code answer will not to the use actual values (i.e., .Spades) from the enumerations when generating the deck, e.g., if a "Joker" is added later to the Rank enumeration (anywhere in the enumeration), the deck generation function should still work without change.

The design questions (what to return?, should the deck generation be a function of card?) are not really relevant to this tutorial, but it is likely that a Deck class would be preferable if any serious functionality is going to be built out further (e.g., shuffle). So for now, returning an Array from a function in the Card structure is all that is required.

The following code (as far as possible only using what has been described up to this point in the tutorial) defines a function in the Card Structure that loops through the Suit and Rank enumerations without needing to know any of the enumeration values and returns an 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
}

Invoke this with:

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

Copy the function into the Card structure and try adding values to enums. Note the following:

  • how the number of times the loops are executed changes when adding to the enums
  • that both enum counters start at 1 (if not otherwise specified in the enumeration the first raw value is one)
  • unspecified array indexes start at 0 (e.g., deck[3] is actually the 4 of Spades)
like image 37
Alan O'Regan Avatar answered Oct 30 '22 18:10

Alan O'Regan


The experiment asks for a method to Card. So I I declared the method as being static so that it acts on the struct and not an instance of it:

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

To make use of it:

let deck = Card.deck()

Hope that helps.

like image 32
zeitgeist7 Avatar answered Oct 30 '22 19:10

zeitgeist7