Try this:
import SwiftUI
struct Card: Identifiable{
var id = UUID()
var content: String
var isFacedUp: Bool = false
var isMatched = false
}
class ViewModel: ObservableObject{
@Published var cards: [Card] = [
Card(content: "😀"),
Card(content: "😀"),
Card(content: "😘"),
Card(content: "🥶"),
Card(content: "😡"),
Card(content: "🥶"),
Card(content: "😘"),
Card(content: "😡")
]
func tapped(_ card: Card){
if let chosenIndex = cards.firstIndex(where: { $0.id == card.id}), !cards[chosenIndex].isFacedUp, !cards[chosenIndex].isMatched{
if let potenialMatcehIndex = cards.indices.filter({ cards[$0].isFacedUp}).oneAndOnly{
print("ONE")
if cards[chosenIndex].content == cards[potenialMatcehIndex].content{
print("TWO")
cards[potenialMatcehIndex].isMatched = true
cards[chosenIndex].isMatched = true
}
cards[chosenIndex].isFacedUp = true
} else{
print("THREE")
cards.indices.forEach({cards[$0].isFacedUp = ($0 == chosenIndex)})
}
}
}
}
struct ContentView: View {
let columns = [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]
@StateObject var viewModel = ViewModel()
var body: some View {
LazyVGrid(columns: columns) {
ForEach(viewModel.cards) { card in
RoundedRectangle(cornerRadius: 20)
.frame(width: 70, height: 70)
.foregroundColor(card.isFacedUp || card.isMatched ? Color(.systemIndigo) : .purple)
.padding()
.overlay(Text(card.content).font(.system(size: 30)).rotation3DEffect(Angle(degrees: card.isFacedUp || card.isMatched ? 180 : 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0))).opacity(card.isFacedUp || card.isMatched ? 1 : 0))
.rotation3DEffect(card.isFacedUp || card.isMatched ? Angle(degrees: 180): Angle(degrees: 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0)))
.animation(.default, value: card.isFacedUp)
.onTapGesture { viewModel.tapped(card) }
}
}
}
}
extension Array{
var oneAndOnly: Element?{
if self.count == 1{
return self.first
} else{
return nil
}
}
}