Need a help with my app

Hi guys
I'm trying to build a game (cards game precisely) and I need that when the user finds the same cards the game has to stop... I watched different videos on internet and tried a lot of lines of code but I can't do this. So please, can anyone help me?
Thank you.

I leave you my code:

import SwiftUI
import PlaygroundSupport

let columns = [GridItem(.flexible()),
               GridItem(.flexible()),
               GridItem(.flexible()),
               GridItem(.flexible())]

struct ContentView: View {
    @State var flipped1 = false 
    @State var flipped2 = false 
    @State var flipped3 = false 
    @State var flipped5 = false 
    @State var flipped6 = false 
    @State var flipped7 = false 
    @State var flipped8 = false 
    @State var flipped9 = false 
    

    var body: some View {
        LazyVGrid(columns: columns) {
            Group {
                RoundedRectangle(cornerRadius: 20)
                    .frame(width: 140, height: 170)
                    .foregroundColor(flipped1 ? Color(.systemIndigo) : .purple)
                    .padding()
                    .overlay(Text("😀").font(.system(size: 80)).rotation3DEffect(Angle(degrees: flipped1 ? 180 : 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0))).opacity(flipped1 ? 1 : 0))

                    .rotation3DEffect(flipped1 ? Angle(degrees: 180): Angle(degrees: 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0)))
                    .animation(.default, value: flipped1)
                    .onTapGesture {
                        flipped1.toggle()
                    }

                RoundedRectangle(cornerRadius: 20)
                    .frame(width: 140, height: 170)
                    .foregroundColor(flipped2 ? Color(.systemIndigo) : .purple)
                    .padding()
                    .overlay(Text("😜").font(.system(size: 80)).rotation3DEffect(Angle(degrees: flipped2 ? 180 : 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0))).opacity(flipped2 ? 1 : 0))

                    .rotation3DEffect(flipped2 ? Angle(degrees: 180): Angle(degrees: 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0)))

                    .animation(.default) 

                    .onTapGesture {

                        flipped2.toggle()

                    }

                

                RoundedRectangle(cornerRadius: 20)

                    .frame(width: 140, height: 170)

                    .foregroundColor(self.flipped3 ? Color(.systemIndigo) : .purple)

                    .padding()

                    .overlay(Text("😘").font(.system(size: 80)).rotation3DEffect(Angle(degrees: flipped3 ? 180 : 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0))).opacity(flipped3 ? 1 : 0))

                    .rotation3DEffect(self.flipped3 ? Angle(degrees: 180): Angle(degrees: 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0)))

                    .animation(.default) 

                    .onTapGesture {

                        self.flipped3.toggle()

                    }

                

                RoundedRectangle(cornerRadius: 20)

                    .frame(width: 140, height: 170)

                    .foregroundColor(self.flipped5 ?  Color(.systemIndigo) : .purple)

                    .padding()

                    .overlay(Text("🥶").font(.system(size: 80)).rotation3DEffect(Angle(degrees: flipped5 ? 180 : 0), axis: (x: CGFloat(0), y:CGFloat(10), z: CGFloat(0))).opacity(flipped5 ? 1 : 0))

                    .rotation3DEffect(self.flipped5 ? Angle(degrees: 180): Angle(degrees: 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0)))

                    .animation(.default) 

                    .onTapGesture {

                        self.flipped5.toggle()

                    }

                RoundedRectangle(cornerRadius: 20)

                    .frame(width: 140, height: 170)

                    .foregroundColor(self.flipped6 ? Color(.systemIndigo) : .purple)

                    .padding()

                    .overlay(Text("😡").font(.system(size: 80)).rotation3DEffect(Angle(degrees: flipped6 ? 180 : 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0))).opacity(flipped6 ? 1 : 0))

                    .rotation3DEffect(self.flipped6 ? Angle(degrees: 180): Angle(degrees: 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0)))

                    .animation(.default) 

                    .onTapGesture {

                        self.flipped6.toggle()

                    }

                

                Group {

                    RoundedRectangle(cornerRadius: 20)

                        .frame(width: 140, height: 170)

                        .foregroundColor(self.flipped7 ? Color(.systemIndigo) : .purple)

                        .padding()

                        .overlay(Text("🥶").font(.system(size: 80)).rotation3DEffect(Angle(degrees: flipped7 ? 180 : 0), axis: (x: CGFloat(0), y:CGFloat(10), z: CGFloat(0))).opacity(flipped7 ? 1 : 0))

                        .rotation3DEffect(self.flipped7 ? Angle(degrees: 180): Angle(degrees: 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0)))

                        .animation(.default) 

                        .onTapGesture {

                            self.flipped7.toggle()

                        }

                    RoundedRectangle(cornerRadius: 20)

                        .frame(width: 140, height: 170)

                        .foregroundColor(self.flipped8 ? Color(.systemIndigo) : .purple)

                        .padding()

                        .overlay(Text("😘").font(.system(size: 80)).rotation3DEffect(Angle(degrees: flipped8 ? 180 : 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0))).opacity(flipped8 ? 1 : 0))

                        .rotation3DEffect(self.flipped8 ? Angle(degrees: 180): Angle(degrees: 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0)))

                        .animation(.default) 

                        .onTapGesture {

                            self.flipped8.toggle()

                        }

                    RoundedRectangle(cornerRadius: 20)

                        .frame(width: 140, height: 170)

                        .foregroundColor(self.flipped9 ? Color(.systemIndigo) : .purple)

                        .padding()

                        .overlay(Text("😡").font(.system(size: 80)).rotation3DEffect(Angle(degrees: flipped9 ? 180 : 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0))).opacity(flipped9 ? 1 : 0))

                        .rotation3DEffect(self.flipped9 ? Angle(degrees: 180): Angle(degrees: 0), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0)))

                        .animation(.default) 

                        .onTapGesture {

                            self.flipped9.toggle()

                        }

                    

                }

            }

        }

    }

}











PlaygroundPage.current.setLiveView(ContentView())






Answered by Jad-T in 700435022

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

Accepted Answer

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

Thanks very much, it's exactly what I want!

Can you explain me what you did in the tapped() function? Because it's a little bit confusing to understand.

Need a help with my app
 
 
Q