I'm trying to create a card game with Swift. My model is a struct called SetGame that holds an array of cards of type struct Card where one variable in Card is another struct called content which is of type CardContent that I set to a struct called SetCard in the view model. It has the following variables: color, shading, numberOfShapes, and shape.
I can't seem to figure out how to access the cardContent variables such as shape and color inside my model.
When I type print(card1.content.shape) I get an error saying that "Value of type 'CardContent' has no member 'shape'"
When I print (card1) I get "Card(isSelected: true, isMatched: false, content: Set.SetCard(color: purple, numberOfShapes: 1, shape: "Diamond", shading: 0.1), id: 54)"
When I print(card1.content) I get the values I'm looking for "SetCard(color: purple, numberOfShapes: 1, shape: "Diamond", shading: 0.1)"
How do I access these values?
struct SetGame<CardContent> where CardContent: Equatable {
private(set) var cards: Array<Card>
private(set) var dealtCards: Array<Card>
private(set) var score = 0
private(set) var selectedCards = [Int]()
init(numberOfPairOfCards: Int, creatrCardContent: (Int) -> CardContent) {
cards = []
dealtCards = [Card]()
for pairIndex in 0..<numberOfPairOfCards {
let content: CardContent = creatrCardContent(pairIndex)
cards.append(Card(content: content, id: pairIndex))
}
cards.shuffle()
for _ in 0..<12{
if let dealtCard = cards.popLast(){
self.dealtCards.append(dealtCard)
}
}
}
mutating func choose(_ card: Card){
if let chosenIndex = dealtCards.firstIndex(where: {$0.id == card.id}) {
if !dealtCards[chosenIndex].isSelected {
selectedCards.append(dealtCards[chosenIndex].id)
} else {
selectedCards.removeLast()
}
dealtCards[chosenIndex].isSelected = !dealtCards[chosenIndex].isSelected
print(selectedCards)
}
if selectedCards.count == 3 {
print("Let's see if they match")
print(doesMatch(cards: selectedCards))
}
}
func doesMatch(cards: [Int]) -> Bool {
// Get card content from id in cards array
if let card1 = dealtCards.first(where: { $0.id == cards[0]}) {
print(card1)
print(card1.content)
print(card1.content.shape)
}
return false
}
struct Card: Identifiable {
var isSelected = false
var isMatched = false
let content: CardContent
let id : Int
}
}
struct SetCard : Equatable {
let color : Color
let numberOfShapes: Int
let shape : String
let shading : Double
}
class SetGameViewModel: ObservableObject {
typealias Card = SetGame<SetCard>.Card
@Published private var model: SetGame<SetCard>
init() {
self.model = SetGameViewModel.createGame()
}
var cards: Array<Card> {
return model.cards
}
var dealtCards: Array<Card> {
return model.dealtCards
}
static func createGame() -> SetGame<SetCard> {
var cardDeck : [SetCard] = []
let shapes = ["Diamond", "Squiggle", "Oval"]
let colors = [Color.red, Color.green, Color.purple]
let counts = [1,2,3]
let shades = [0.1, 0.5, 1]
for color in colors {
for shape in shapes {
for count in counts {
for shade in shades {
let card = SetCard.init(color: color, numberOfShapes: count, shape: shape, shading: shade)
cardDeck.append(card)
}
}
}
}
return SetGame<SetCard>(numberOfPairOfCards: cardDeck.count) {pairIndex in
cardDeck[pairIndex]
}
}
// Mark:= Intents(s)
func choose(_ card: Card){
model.choose(card)
}
}
You made content
generic, so it's type is actually Equatable
. This means you need to cast the content
to its actual type SetCard
, and now you can access its properties:
if let card1 = dealtCards.first(where: { $0.id == cards[0]}) {
print(card1)
print(card1.content)
let content = card1.content as! SetCard
print(content.shape)
}