ContentView.swift
import Foundation
struct MemoryGame<CardContent> where CardContent: Equatable {
private(set) var cards: Array<Card>
//唯一朝上的卡的index,Int? = Optional.none,只有一张朝上则匹配
private var indexOfTheOneAndOnlyFaceUpCard: Int?
mutating func choose(_ card: Card) {
if let chosenIndex = cards.firstIndex(where: { $0.id == card.id }),
//判断如果已经朝上,则不能翻下去,朝上的卡不能选
!cards[chosenIndex].isFaceUp,
//不能是已经匹配的
!cards[chosenIndex].isMatched
{
//唯一朝上卡的index的内容 是 潜在匹配的index的内容,这两张卡都匹配
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 0..<cards.count { 等于 for index in cards.indices {
for index in cards.indices {
cards[index].isFaceUp = false
}
//唯一朝上的卡是我刚选的卡
indexOfTheOneAndOnlyFaceUpCard = chosenIndex
}
//选中的卡翻面
cards[chosenIndex].isFaceUp.toggle()
}
}
init(numberOfPairOfCards: Int, createCardContent: (Int) -> CardContent) {
cards = Array<Card>()
for pairIndex in 0..<numberOfPairOfCards {
let content = createCardContent(pairIndex)
cards.append(Card(content: content, id: pairIndex*2))
cards.append(Card(content: content, id: pairIndex*2+1))
}
}
struct Card:Identifiable {
var isFaceUp: Bool = false
var isMatched: Bool = false
var content: CardContent
var id: Int
}
}
ContentView.swift-------------------------
import SwiftUI
struct ContentView: View {
@ObservedObject var viewModel: EmojiMemoryGame
var body: some View {
VStack {
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(.red)
}
.padding(.horizontal)
}
}
struct CardView: View {
var card: MemoryGame<String>.Card
var body: some View {
ZStack {
let shape = RoundedRectangle(cornerRadius: 20)
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()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let game = EmojiMemoryGame()
ContentView(viewModel: game)
.preferredColorScheme(/*@START_MENU_TOKEN@*/.dark/*@END_MENU_TOKEN@*/)
ContentView(viewModel: game)
.preferredColorScheme(.light)
}
}