NEW! Master Swift design patterns with my latest book! >>

< Previous: Loading a level: addTarget and shuffling arrays   Next: Property observers: didSet >

It's play time: index(of:) and joined()

We need to add three more methods to our view controller in order to finish this game: one to handle letter buttons being tapped, another to handle the current word being cleared, and a third to handle the current word being submitted. The first two are easiest, so let's get those done so we can get onto the serious stuff.

First, we already used the addTarget() method in viewDidLoad() to make all our letter buttons call the method letterTapped(), but right now it’s empty. Please fill it in like this:

@objc func letterTapped(btn: UIButton) {
    currentAnswer.text = currentAnswer.text! + btn.titleLabel!.text!
    activatedButtons.append(btn)
    btn.isHidden = true
}

That does three things: gets the text from the title label of the button that was tapped and appends it to the current text of the answer text field, then appends the button to the activatedButtons array, and finally hides the button. We need to force unwrap both the title label and its text, because both might not exist – and yet we know they do.

The activatedButtons array is being used to hold all buttons that the player has tapped before submitting their answer. This is important because we're hiding each button as it is tapped, so when the user taps "Clear" we need to know which buttons are currently in use so we can re-show them. You already created an empty @IBAction method for clear being tapped, so fill it in like this:

@IBAction func clearTapped(_ sender: Any) {
    currentAnswer.text = ""

    for btn in activatedButtons {
        btn.isHidden = false
    }

    activatedButtons.removeAll()
}

As you can see, this method removes the text from the current answer text field, unhides all the activated buttons, then removes all the items from the activatedButtons array.

That just leaves one final method, and you already created its stub: the submitTapped() method for when the player taps the submit button.

This method will use another new function called index(of:), which searches through an array for an item and, if it finds it, tells you its position. The return value is optional so that in situations where nothing is found you won't get a value back, so we need to unwrap its return value carefully.

If the user gets an answer correct, we're going to change the answers label so that rather than saying "7 LETTERS" it says "HAUNTED", so they know which ones they have solved already. The way we're going to do this is delightfully simple: index(of:) will tell us which solution matched their word, then we can use that position to find the matching clue text. All we need to do is split the answer label text up by \n, replace the line at the solution position with the solution itself, then re-join the answers label back together.

You've already learned how to use components(separatedBy:) to split text into an array, and now it's time to meet its counterpart: joined(separator:). This makes an array into a single string, with each array element separated by the string specified in its parameter.

Once that's done, we clear the current answer text field and add one to the score. If the score is evenly divisible by 7, we know they have found all seven words so we're going to show a UIAlertController that will prompt the user to go to the next level.

The "evenly divisible" task is easy to do in Swift (and indeed any sensible programming language) thanks to a dedicated modulo operator: %. Modulo is division with remainder, so 10 % 3 means "tell me what number remains when you divide 10 evenly into 3 parts". 3 goes into 10 three times (making nine), with remainder 1, so 10 % 3 is 1, 11 % 3 is 2, and 12 % 3 is 0 – i.e., 12 divides perfectly into 3 with no remainder. If score % 7 is 0, we know they have answered all seven words correctly.

That's all the parts explained, so here's the final submitTapped() method:

@IBAction func submitTapped(_ sender: Any) {
    if let solutionPosition = solutions.index(of: currentAnswer.text!) {
        activatedButtons.removeAll()

        var splitAnswers = answersLabel.text!.components(separatedBy: "\n")
        splitAnswers[solutionPosition] = currentAnswer.text!
        answersLabel.text = splitAnswers.joined(separator: "\n")

        currentAnswer.text = ""
        score += 1

        if score % 7 == 0 {
            let ac = UIAlertController(title: "Well done!", message: "Are you ready for the next level?", preferredStyle: .alert)
            ac.addAction(UIAlertAction(title: "Let's go!", style: .default, handler: levelUp))
            present(ac, animated: true)
        }
    }
}

The levelUp() call in there is just to get you started – there isn't a level up here, because I only created one level! But if you wanted to make more levels and continue the game, you'd need a levelUp() method something like this:

func levelUp(action: UIAlertAction) {
    level += 1
    solutions.removeAll(keepingCapacity: true)

    loadLevel()

    for btn in letterButtons {
        btn.isHidden = false
    }
}

As you can see, that code clears out the existing solutions array before refilling it inside loadLevel(). Then of course you'd need to create level2.txt, level3.txt and so on. To get you started, I've made an example level2.txt for you inside the Content folder – try adding that to the project and see what you think. Any further levels are for you to do – just make sure there's a total of 20 letter groups each time!

Test your Swift today

Think you know Swift? My book Swift Coding Challenges will put your Swift skills to the test – it's perfect for job interviews and more!

< Previous: Loading a level: addTarget and shuffling arrays   Next: Property observers: didSet >
MASTER SWIFT NOW
Buy Practical iOS 12 Buy Pro Swift Buy Swift Design Patterns Buy Practical iOS 11 Buy Swift Coding Challenges Buy Server-Side Swift (Vapor Edition) Buy Server-Side Swift (Kitura Edition) Buy Hacking with macOS Buy Advanced iOS Volume One Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with Swift Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let me know!

Click here to visit the Hacking with Swift store >>