diff --git a/Memorize/ContentView.swift b/Memorize/ContentView.swift index 1203249..1937e60 100644 --- a/Memorize/ContentView.swift +++ b/Memorize/ContentView.swift @@ -8,56 +8,47 @@ import SwiftUI struct ContentView: View { - var emojis = ["🚌", "🚙", "🚗", "🚕", "🏎", "🚎", "🚓"] - @State var emojiCount = 2 + @ObservedObject var viewModel: EmojiMemoryGame var body: some View { - VStack { - ScrollView { - LazyVGrid(columns: [GridItem(.adaptive(minimum: 65))]) { - ForEach(emojis[0 ..< emojiCount], id: \.self) { - emoji in CardView(content: emoji).aspectRatio(2 / 3, contentMode: .fit) - } + ScrollView { + LazyVGrid(columns: [GridItem(.adaptive(minimum: 65))]) { + ForEach(viewModel.cards) { + card in CardView(card: card).aspectRatio(2 / 3, contentMode: .fit) + .onTapGesture { + viewModel.choose(card) + } } } - .foregroundColor(/*@START_MENU_TOKEN@*/ .red/*@END_MENU_TOKEN@*/) - .padding(.horizontal) - .font(.largeTitle) } + .foregroundColor(/*@START_MENU_TOKEN@*/ .red/*@END_MENU_TOKEN@*/) .padding(.horizontal) } } struct CardView: View { - @State var isFaceUp: Bool = true - var content: String + let card: MemoryGame.Card var body: some View { ZStack { let shape = RoundedRectangle(cornerRadius: 20.0) - if isFaceUp { - shape - .fill() - .foregroundColor(.white) - shape - .strokeBorder(lineWidth: 3) - Text(content) - .font(.largeTitle) + if card.isFaceUp { + shape.fill().foregroundColor(.white) + shape.strokeBorder(lineWidth: 3) + Text(card.content).font(.largeTitle) + } else if card.isMatched { + shape.opacity(0) + } else { + shape.fill() } - else { - shape - .fill() - } - } - .onTapGesture { - isFaceUp = !isFaceUp } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { - ContentView() + let game = EmojiMemoryGame() + ContentView(viewModel: game) .preferredColorScheme(.dark) - ContentView() + ContentView(viewModel: game) .preferredColorScheme(.light) } } diff --git a/Memorize/EmojiMemoryGame.swift b/Memorize/EmojiMemoryGame.swift index 3132c2a..f7283ea 100644 --- a/Memorize/EmojiMemoryGame.swift +++ b/Memorize/EmojiMemoryGame.swift @@ -8,16 +8,22 @@ import SwiftUI // viewmodel -class EmojiMemoryGame { +class EmojiMemoryGame: ObservableObject{ static let emojis = ["🚌", "🚙", "🚗", "🚕", "🏎", "🚎", "🚓"] static func createMemoryGame() -> MemoryGame { MemoryGame(numberOfPairsOfCards: 5) { pairIndex in EmojiMemoryGame.emojis[pairIndex] } } - private var model: MemoryGame = createMemoryGame() + @Published private var model: MemoryGame = createMemoryGame() var cards: [MemoryGame.Card] { return model.cards } + + // MARK: - Intent(s) + + func choose(_ card: MemoryGame.Card) { + model.choose(card) + } } diff --git a/Memorize/MemorizeApp.swift b/Memorize/MemorizeApp.swift index b685264..809b856 100644 --- a/Memorize/MemorizeApp.swift +++ b/Memorize/MemorizeApp.swift @@ -9,9 +9,10 @@ import SwiftUI @main struct MemorizeApp: App { + let game = EmojiMemoryGame() var body: some Scene { WindowGroup { - ContentView() + ContentView(viewModel: game) } } } diff --git a/Memorize/MemoryGame.swift b/Memorize/MemoryGame.swift index ec65cdf..aa2aa68 100644 --- a/Memorize/MemoryGame.swift +++ b/Memorize/MemoryGame.swift @@ -8,24 +8,53 @@ import Foundation // model -struct MemoryGame { +struct MemoryGame where CardContent: Equatable { private(set) var cards: [Card] + private var indexOfTheOneAndOnlyFaceUpCard: Int? - func choose(_ card: Card) {} + mutating func choose(_ card: Card) { + if let chosenIndex = cards.firstIndex(where: { $0.id == card.id }), !cards[chosenIndex].isFaceUp, !cards[chosenIndex].isMatched { + if let potentialMatchIndex = indexOfTheOneAndOnlyFaceUpCard { + if cards[chosenIndex].content == cards[potentialMatchIndex].content { + cards[chosenIndex].isMatched = true + cards[potentialMatchIndex].isMatched = true + } + indexOfTheOneAndOnlyFaceUpCard = nil + } else { + for index in cards.indices { + if cards[index].isFaceUp { + cards[index].isFaceUp.toggle() + } + } + indexOfTheOneAndOnlyFaceUpCard = chosenIndex + } + cards[chosenIndex].isFaceUp.toggle() + } + } + + func index(of card: Card) -> Int? { + for index in 0 ..< cards.count { + if cards[index].id == card.id { + return index + } + } + return nil + } init(numberOfPairsOfCards: Int, createCardContent: (Int) -> CardContent) { cards = [Card]() // for pairIndex in 0 ..< numberOfPairsOfCards { let content: CardContent = createCardContent(pairIndex) - cards.append(Card(content: content)) - cards.append(Card(content: content)) + cards.append(Card(content: content, id: pairIndex * 2)) + cards.append(Card(content: content, id: pairIndex * 2 + 1)) } } - struct Card { + struct Card: Identifiable { var isFaceUp: Bool = false var isMatched: Bool = false var content: CardContent + var id: Int } }