Reputation: 1051
I am trying to initialize a deck of cards for the game Sets, which has 4 parameters for each card : color, shape, shade and number of shapes on the card.
My Card class looks as below :
enum CardColor : Int {
case red = 1
case purple = 2
case green = 3
}
enum CardShape : Int {
case line = 1
case snake = 2
case diamond = 3
}
enum CardShade : Int {
case empty = 1
case filled = 2
case stripes = 3
}
class Card {
var color : CardColor
var shape : CardShape
var shade : CardShade
var number : Int
var image : String
var isTapped = false
var isMatched = false
init(color : CardColor , shape : CardShape, shade : CardShade , number : Int) {
self.color = color
self.shape = shape
self.shade = shade
self.number = number
self.image = "\(color.rawValue)\(shape.rawValue)\(shade.rawValue)\(number)"
}
}
I can't find a way to initialize a deck and I am currently using an array of Card that I made manually :
cards = [Card(color: .red, shape: .diamond, shade: .filled, number: 1)...
and so on.
The cards looks like this :
Upvotes: 1
Views: 310
Reputation: 63252
I would use a series of flatMaps
to generate the full deck. I would also change a few other things:
Card
a struct. Any card that is a single red empty line is the same as any other card that's a single red empty line. I.e. cards don't have their own identity separate from their value, thus a reference type (a class) wouldn't be useful.isTapped
or isMatched
fields from the Card
struct. It doesn't make sense there. If you give a Set player a card and asked them what the isTapped
value is, they would have no idea. It simply doesn't belong. I would make something like a CardSlot
or CardView
that keeps track of such UI state.image
to imageName
. If it were really an image
, one would expect it to have type UIImage
or NSImage
, not String
.
imageName
to be a computed property. Now, all stored fields (color
, shape
, shade
, parity
) can be filled in by a member wise initializer, which the compiler will automatically synthesize for this struct.Card
, to prevent the needless Card
prefix in all their names.green_line_filled_three.png
than 3123.png
rawValue
s aren't needed to generate the image names, they can be removed. There's rarely ever a need to use Int
raw values anymore. C interop is the only thing I can think of. For generating all enum values, you can use CaseIterable
, instead of mapping init(rawValue: Int)
over a range of Int
s.number: Int
to arity: Card.arity
, to prevent illegal values from ever popping upAnd here's what that would look like:
struct Card {
enum Color: CaseIterable { case red, purple, green }
enum Shape: CaseIterable { case line, snake, diamond }
enum Shade: CaseIterable { case empty, filled, striped }
enum Arity: CaseIterable { case one, two, three }
let color: Color
let shape: Shape
let shade: Shade
let arity: Arity
var imageName: String {
return "\(color)\(shape)\(shade)\(arity)"
}
static func generateFullDeck() -> [Card] {
return Color.allCases.flatMap { color in
return Shape.allCases.flatMap { shape in
return Shade.allCases.flatMap { shade in
return Arity.allCases.map { arity in
return Card(color: color, shape: shape, shade: shade, arity: arity)
}
}
}
}
/*
// Alternate implementation which prevents the "pyramid of doom" nesting,
// But it's considerably more complex
return Color.allCases.lazy.flatMap { color in
Shape.allCases.map { shape in (color, shape)}
}.flatMap { (color, shape) in
Shade.allCases.map { shade in (color, shape, shade) }
}.flatMap { (color, shape, shade) in
Arity.allCases.map { arity in
}
})
*/
}
}
Card.generateFullDeck().forEach { print($0) }
Upvotes: 1
Reputation: 154583
For loops would work well here. Use 4 nested loops to loop through the attributes and create a new card inside of the inner loop:
Add CaseIterable
to your enums to make it easy to access all of the cases:
enum CardColor : Int, CaseIterable {
case red = 1
case purple = 2
case green = 3
}
Then:
// Array to hold the cards
var cards = [Card]()
for color in CardColor.allCases {
for shape in CardShape.allCases {
for shade in CardShade.allCases {
for number in 1...3 {
// Create a new card and append it to the array
cards.append(Card(color: color, shape: shape, shade: shade, number: number))
}
}
}
}
Upvotes: 2