Finishing the game

In this section, we will finally be able to play the game.

Implementing the game logic

After having all the required functions in place, it's now a straightforward task to complete the game. First of all, we add the instance variables to hold the number of the pairs already created, the current score, and the list of selected cards turned up:

private var selectedIndexes = Array<NSIndexPath>()
private var numberOfPairs = 0
private var score = 0

Then, we apply the logic when a card is selected:

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        if selectedIndexes.count == 2 || selectedIndexes .contains(indexPath) {
                return
            }
            selectedIndexes.append(indexPath)

        let cell = collectionView.cellForItemAtIndexPath(indexPath)
        as! CardCell
        cell.upturn()

        if selectedIndexes.count < 2 {
            return
        }

        let card1 = deck[selectedIndexes[0].row]
        let card2 = deck[selectedIndexes[1].row]

        if card1 == card2 {
            numberOfPairs++
            checkIfFinished()
            removeCards()
        } else {
            score++
            turnCardsFaceDown()
        }
}

We first check whether we have touched an already turned-up card or whether we have two cards turned up. If not, we save the index. Then, we check whether we have flipped the first card, and if not, we proceed to check the values of the cards.

The pattern of checking a condition and leaving the current function if the condition is true is called Guard. It helps make the code more readable by avoiding the use of the else clause and the nesting of curly braces.

We got a pair

As shown in the previous part of the source, we implement the missing actions in a private extension:

// MARK: Actions
private extension MemoryViewController {
    func checkIfFinished(){
    }
    func removeCards(){
    }
    func turnCardsFaceDown(){
    }
}

The first one checks whether we have completed all the pairs, and if so, it presents a popup with the score and returns to the main menu:

func checkIfFinished(){
    if numberOfPairs == deck.count/2 {
        showFinalPopUp()
    }
}
func showFinalPopUp() {
    let alert = UIAlertController(title: "Great!", message: "You won with score: \(score)!", preferredStyle: UIAlertControllerStyle.Alert)
    alert.addAction(UIAlertAction(title: "Ok", style: .Default, handler: { action in self.dismissViewControllerAnimated(true, completion: nil)}))

    self.presentViewController(alert, animated: true, completion: nil)
}

Note that in iOS 8, UIAlertController is slightly different from that in the previous version. In our case, a simple dialog box with an OK button is enough.

If the cards are equal, we need to remove them:

func removeCards(){
    execAfter(1.0) {
        self.removeCardsAtPlaces(self.selectedIndexes)
        self.selectedIndexes = []
    }
}

func removeCardsAtPlaces(places: Array<NSIndexPath>){
    for index in selectedIndexes {
        let cardCell = collectionView.cellForItemAtIndexPath(index)
         as! CardCell
         cardCell.remove()
    }
}

The remove() function in CardCell is similar to turnUp() and turnDown(), but instead of making a transition, it just performs an animation before hiding the cell:

func remove() {
    UIView.animateWithDuration(1,
        animations: {
            self.alpha = 0
        },
        completion: { completed in
        self.hidden = true
    })
}

We made the wrong move

Finally, if the cards are different, we need to turn them down:

func turnCardsFaceDown(){
    execAfter(2.0) {
        self.downturnCardsAtPlaces(self.selectedIndexes)
        self.selectedIndexes = []
    }
}

func downturnCardsAtPlaces(places: Array<NSIndexPath>){
    for index in selectedIndexes {
        let cardCell = collectionView.cellForItemAtIndexPath(index)
        as! CardCell
        cardCell.downturn()
    }
}

Et voilà! The game is completed

As you can see in the following screenshot, the game presents a smooth animation and nice images:

Note

The complete source can be downloaded from https://github.com/gscalzo/Swift2ByExample/tree/2_Memory_4_Complete.