Home > Software design >  How to I change my memory game so that it matches 2 specific cards?
How to I change my memory game so that it matches 2 specific cards?

Time:12-10

Right now, I have my code in a way that makes the cards with the same images are matched. I want to change my code so that 2 specific cards are match - ex: Image("Beagle") and Image("BeagleInformation").


For my code, I have the content view file and 2 other files - FinalMemoryGame and MemoryGame. I think that my problem mainly focuses on the MemoryGame file. I have included all 3 below

CONTENTVIEW

import SwiftUI

struct ContentView: View {
    @State private var progress = 0.0
    @State private var timeRemaining = 30
    @State private var fadeInOut = false
    let timer = Timer.publish(every: 1, on: .main, in: .com
    mon).autoconnect()
    @ObservedObject var viewModel: FinalMemoryGame
    
    
    var body: some View {
        ScrollView {
            HStack{Text("Final Game").font(.system(size:36,design: .rounded))
        .foregroundColor(.purple)
                .bold()
                Image(systemName: "arrow.clockwise").onTapGesture{
                    viewModel.reset()
                    progress = Double(viewModel.matches)
                    timeRemaining = 30
                }
            }

            LazyVGrid(columns:
        [GridItem(
        .adaptive(minimum: 100),
        spacing:10)]){
            ForEach(viewModel.cards) { card in DogCard(
                card: card).aspectRatio(1, contentMode: .fit).frame(width:100, height: 125).onTapGesture{
                    viewModel.choose(card)
                    progress = Double(viewModel.matches)
                }
                
        }
        }

        }.onReceive(timer) { time in
            if timeRemaining > 0 {
                timeRemaining -= 1
            }
            if timeRemaining == 0 && progress < 6{
                viewModel.lose()
            }
        }
        
        if timeRemaining == 0 && progress < 6{
            VStack {
                ProgressView("You lose!", value: progress, total:6)
                    .foregroundColor(.red)
                    .font(.system(size: 20, weight: .bold))
                    .onAppear () {
                        withAnimation(Animation.easeInOut(duration:0.6)
                            .repeatForever(autoreverses:true)){
                                fadeInOut.toggle()
                            }
                    }.opacity(fadeInOut ? 0 : 1)

            }
                
                
        }
        else if progress == 6{
            VStack{
                ProgressView("You win!", value: progress, total:6)
                    .foregroundColor(.green)
                    .font(.system(size: 20, weight: .bold))
                    .onAppear () {
                        withAnimation(Animation.easeInOut(duration:0.6)
                            .repeatForever(autoreverses:true)){
                                fadeInOut.toggle()
                            }
                    }.opacity(fadeInOut ? 0 : 1)
                
            }
                
                
        }
        else{
        ProgressView("Time Remaining: \(timeRemaining)", value: progress, total:6)
        }
    }
}

    struct DogCard: View {
    var card: MemoryGame.Card
    var body: some View {
        ZStack{
            let shape = RoundedRectangle(cornerRadius: 10)
            if card.isFaceUp {
                shape.stroke(lineWidth: 3).foregroundColor(.blue)
                Image(card.content).resizable().scaledToFit().padding()
                
            }
            else {
                shape.fill().foregroundColor(.pink)
                }

        }.animation(.easeInOut(duration: 0.5), value: card.animationAmount)
    }
    }

    struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(viewModel: FinalMemoryGame())
    }
}

FINALMEMORYGAME

import SwiftUI

class FinalMemoryGame: ObservableObject {
    
    @Published private var model: MemoryGame = CreateMemoryGame()
    
    static func CreateMemoryGame() -> MemoryGame {
        return MemoryGame(numberOfPairsOfCards: 6, contentFactory: makeContent)
    }
    
    static func makeContent(index: Int)->String {
        let images = ["Beagle", "BeagleInformation", "Dutch Shepherd", "Havanese", "Leonberger", "Pharaoh Hound"]
        
        return images[index]
    }
    
    var cards: Array<MemoryGame.Card> {
        model.cards
    }
    
    var pairs: Int{
        model.numberOfPairs
    }
    
    func choose(_ card: MemoryGame.Card){
        model.chooseCard(card)
    }
    
    func reset()
    {
        model.reset()
    }
    
    func lose(){
        model.lose()
     }
    
    var matches: Int{
        model.matches
     }

    }

MEMORYGAME

import Foundation
import SwiftUI

struct MemoryGame {
    private(set) var cards: Array<Card>
    private(set) var numberOfPairs: Int
    private(set) var upCards: Array<Int>
    private(set) var matches: Int
    private(set) var lost: Bool
    
    struct Card: Identifiable {
        var content: String
        var isFaceUp: Bool = false
        var isMatched: Bool = false
        var id: Int
        var animationAmount = 0.0
    }
    
    mutating func chooseCard(_ card: Card) {
        if lost{
            return
        }
        for index in cards.indices {
            if cards[index].id == card.id{
                cards[index].animationAmount  = 180
                if cards[index].isFaceUp{
                    return
                }
                //If 2  cards are picked, they get faced down
                else if upCards[0] != -1 && upCards[1] != -1{
                    cards[upCards[0]].isFaceUp.toggle()
                    cards[upCards[1]].isFaceUp.toggle()
                    cards[index].isFaceUp.toggle()
                    upCards[0] = index
                    upCards[1] = -1
                }
                else if upCards[0] != -1{
                    cards[index].isFaceUp.toggle()
                    if cards[index].content == cards[upCards[0]].content{
                        cards[index].isMatched.toggle()
                        cards[upCards[0]].isMatched.toggle()
                        matches  = 1
                        upCards[0] = -1
                    }
                    else{
                        upCards[1] = index
                    }
                }
                else{
                    cards[index].isFaceUp.toggle()
                    upCards[0] = index
                }
                
                
            }
        }
    }

    
    mutating func reset() {
        lost = false
        cards.shuffle()
        matches = 0
        upCards = [-1,-1]
        for index in cards.indices{
            chooseCard(cards[index])
            upCards = [-1,-1]
            cards[index].isFaceUp = false
            cards[index].isMatched = false
            
        }
        
    }
    
    mutating func lose(){
        lost = true
    }
    
    init(numberOfPairsOfCards: Int, contentFactory: (Int)->String){
        cards = []
        numberOfPairs = numberOfPairsOfCards
        upCards = [-1,-1]
        matches = 0
        lost = false
        
        for index in 0..<numberOfPairsOfCards {
            let content = contentFactory(index)
            cards.append(Card(content: content, id: index * 2))
            cards.append(Card(content: content, id: index * 2   1))
        }
        
        cards.shuffle()
    }
    //THIS IS WHERE I PUT IT
    func cardsMatch(card1: Card, card2: Card) -> Bool {
        switch (card1.content, card2.content) {
        case ("Beagle", "BeagleInformation"), ("BeagleInformation", "Beagle"):
            return true
        case let (a, b):
            return a == b
        }
        
    }
    else if upCards[0] != -1 { //ERROR
        cards[index].isFaceUp.toggle()
        if cardsMatch(card1: cards[index], card2: cards[upCards[0]]) {
            cards[index].isMatched.toggle()
            cards[upCards[0]].isMatched.toggle()
            matches  = 1
            upCards[0] = -1
        }
        else{
            upCards[1] = index
        }
    }

As you can see, I tried adding

if Image("Beagle") == Image("BeagleInformation") {
                    cards[index].isMatched.toggle()
                    cards[upCards[0]].isMatched.toggle()
                    matches  = 1
                    upCards[0] = -1

at the end of my MemoryGame file but I do not think that that's correct

CodePudding user response:

This code:

if Image("Beagle") == Image("BeagleInformation") {
    cards[index].isMatched.toggle()
    cards[upCards[0]].isMatched.toggle()
    matches  = 1
    upCards[0] = -1

is incorrect because:

  1. It contains SwiftUI image code which does not belong in your memory game model code.
  2. It isn't looking at the current 2 up cards to decide if they match.

Your current algorithm for deciding if 2 cards match is to compare their .content values which are Strings. I would suggest making a separate cardsMatch() function that takes 2 Cards and returns a Bool:

func cardsMatch(card1: Card, card2: Card) -> Bool {
    switch (card1.content, card2.content) {
    case ("Beagle", "BeagleInformation"), ("BeagleInformation", "Beagle"):
        return true
    case let (a, b):
        return a == b
    }
}

This function declares a match if the two cards are "Beagle" and "BeagleInformation" in either order, or if the two cards are the same. You can customize this function to whatever you want a match to be.

Call this function when you have 2 up cards to compare:

Replace:

if cards[index].content == cards[upCards[0]].content{

with:

if cardsMatch(card1: cards[index], card2: cards[upCards[0]]) {

Changes for Swift Playgrounds on iPad

I ran this on Swift Playgrounds on iPad with these mods:

I use these image names:

let images = ["clock", "car", "house", "tree", "airplane", "globe"]

And modified DogCard to use an Image(systemName:) in an overlay.

struct DogCard: View {
    var card: MemoryGame.Card
    var body: some View {
        ZStack{
            let shape = RoundedRectangle(cornerRadius: 10)
            if card.isFaceUp {
                shape.stroke(lineWidth: 3).foregroundColor(.blue).overlay {
                    Image(systemName: card.content).resizable().scaledToFit().padding()
                        .foregroundColor(.red)
                }
                
            }
            else {
                shape.fill().foregroundColor(.pink)
            }
            
        }.animation(.easeInOut(duration: 0.5), value: card.animationAmount)
    }
}

Here it is running on the iPad:

game running in Swift Playgrounds


Here is my MemoryGame:

struct MemoryGame {
    private(set) var cards: [Card]
    private(set) var numberOfPairs: Int
    private(set) var upCards: [Int]
    private(set) var matches: Int
    private(set) var lost: Bool
    
    struct Card: Identifiable {
        var content: String
        var isFaceUp: Bool = false
        var isMatched: Bool = false
        var id: Int
        var animationAmount = 0.0
    }
    
    func cardsMatch(card1: Card, card2: Card) -> Bool {
        switch (card1.content, card2.content) {
        case ("globe", "airplane"), ("airplane", "globe"):
            return true
        case let (a, b):
            return a == b
        }
    }
    
    mutating func chooseCard(_ card: Card) {
        if lost {
            return
        }
        for index in cards.indices {
            if cards[index].id == card.id {
                cards[index].animationAmount  = 180
                if cards[index].isFaceUp {
                    return
                }
                //If 2  cards are picked, they get faced down
                else if upCards[0] != -1 && upCards[1] != -1 {
                    cards[upCards[0]].isFaceUp.toggle()
                    cards[upCards[1]].isFaceUp.toggle()
                    cards[index].isFaceUp.toggle()
                    upCards[0] = index
                    upCards[1] = -1
                }
                else if upCards[0] != -1 {
                    cards[index].isFaceUp.toggle()
                    if cardsMatch(card1: cards[index], card2: cards[upCards[0]]) {
                        cards[index].isMatched.toggle()
                        cards[upCards[0]].isMatched.toggle()
                        matches  = 1
                        upCards[0] = -1
                    }
                    else{
                        upCards[1] = index
                    }
                }
                else{
                    cards[index].isFaceUp.toggle()
                    upCards[0] = index
                }
                
            }
        }
    }
    
    mutating func reset() {
        lost = false
        cards.shuffle()
        matches = 0
        upCards = [-1, -1]
        
        for index in cards.indices {
            chooseCard(cards[index])
            upCards = [-1, -1]
            cards[index].isFaceUp = false
            cards[index].isMatched = false
            
        }
        
    }
    
    mutating func lose() {
        lost = true
    }
    
    init(numberOfPairsOfCards: Int, contentFactory: (Int) -> String){
        cards = []
        numberOfPairs = numberOfPairsOfCards
        upCards = [-1, -1]
        matches = 0
        lost = false
        
        for index in 0..<numberOfPairsOfCards {
            let content = contentFactory(index)
            cards.append(Card(content: content, id: index * 2))
            cards.append(Card(content: content, id: index * 2   1))
        }
        
        cards.shuffle()
    }
}
  • Related