App using Swift 5, to create a card memory game. The user can only have two cards filped over at the same time. When a
card is flipped over a timer starts forcing the player to match the cards quickly. Once a card is matched the card disapperars. After, the
game is over the user can press a restart button to play again.
This mobile app was created following the MVVM framework. The Model is responsible for creating the cards, and controlling the logic
involved in matching the cards.
π· Screenshots
π» Code Examples
MemoryGame.swift extract: checks if the cards that the user selected are matching and if they are, the cards are removed from the screen.
Additionally, the file also controls the time limit that the user has.
importFoundationstructMemoryGame<CardContent> where CardContent:Equatable {
private(set) var cards: Array<Card>
privatevar indexOfTheOneAndOnlyFaceUpCard: Int?{
get{
cards.indices.filter { cards[$0].isFaceUp}.only}
set{
for index in cards.indices{
cards[index].isFaceUp= index == newValue
}
}
}
mutatingfuncchoose(card: Card){
iflet chosenIndex = cards.firstIndex(matching: card), !cards[chosenIndex].isFaceUp,!cards[chosenIndex].isMatched{
iflet potentialMatchIndex = indexOfTheOneAndOnlyFaceUpCard{
if cards[chosenIndex].Content== cards[potentialMatchIndex].Content{
cards[chosenIndex].isMatched=true
cards[potentialMatchIndex].isMatched=true
}
self.cards[chosenIndex].isFaceUp=!self.cards[chosenIndex].isFaceUp
}else{
indexOfTheOneAndOnlyFaceUpCard = chosenIndex
}
}
}
init(pairs: Int, cardContentFactory: (Int) -> CardContent) {
cards =Array<Card>()
for pairIndex in0..<pairs {
let content =cardContentFactory(pairIndex)
cards.append(Card(Content: content, id: pairIndex*2))
cards.append(Card(Content: content, id: pairIndex*2+1))
}
cards.shuffle()
}
structCard: Identifiable {
var isFaceUp: Bool=false{
didSet{
if isFaceUp{
startUsingBonusTime()
}
else{
stopUsingBonusTime()
}
}
}
var isMatched: Bool=false{
didSet {
stopUsingBonusTime()
}
}
var Content: CardContent
var id: Intvar bonusTimeLimit : TimeInterval =6privatevar faceUpTime: TimeInterval{
iflet lastFaceUpDate =self.lastFaceUpDate {
return pastFaceUpTime +Date().timeIntervalSince(lastFaceUpDate)
}
else{
return pastFaceUpTime
}
}
var lastFaceUpDate: Date?var pastFaceUpTime : TimeInterval =0var bonusTimeRemaining: TimeInterval{
max (0, bonusTimeLimit-faceUpTime)
}
var bonusRemaining: Double{
(bonusTimeLimit >0&& bonusTimeRemaining >0) ? bonusTimeRemaining/bonusTimeLimit :0
}
var hasEarnedBonus: Bool {
isMatched && bonusTimeRemaining >0
}
var isComsumingBonusTime : Bool{
isFaceUp &&!isMatched && bonusTimeRemaining >0
}
privatemutatingfuncstartUsingBonusTime(){
if isComsumingBonusTime, lastFaceUpDate ==nil{
lastFaceUpDate =Date()
}
}
privatemutatingfuncstopUsingBonusTime(){
pastFaceUpTime = faceUpTime
self.lastFaceUpDate=nil
}
}
}
π License
This project is licensed under the terms of the MIT license.