BLACK FRIDAY SALE: Save big on all my Swift books and bundles! >>

WordScramble app

Forums > 100 Days of SwiftUI

I've just completed the Word Scramble game, everything seemed to run smoothly however the rootWord (if you don't remember, the word users spell from) does not change from aardvark, which is the first word in the start.tx. I've had a look over the code a number of times, first looking at it logically then repeating the exercise. The code seems right and the start.tx file hasn't been corrupted, but I don't appear to have found a solution. Is anyone able to spot any errors in the code that are causing this issue?

struct ContentView: View {
    @State private var usedWords = [String]()
    @State private var rootWord = ""
    @State private var newWord = ""
    @State private var errorTitle = ""
    @State private var errorMessage = ""
    @State private var showingError = false

    var body: some View {
        NavigationView {
            VStack {
                TextField("Enter your word", text: $newWord, onCommit: addNewWord)

                List(usedWords, id: \.self) {
                    Image(systemName: "\($0.count).circle")

            .onAppear(perform: startGame)
            .alert(isPresented: $showingError) {
                Alert(title: Text(errorTitle), message: Text(errorMessage), dismissButton: .default(Text("OK")))

    func addNewWord() {
        //lower cas and trim the word, to make sure we don't add duplicate words with case diffrences
        let answer = newWord.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)

        // exit if the remaining string is empty
        guard answer.count > 0 else {

        guard isOriginal(word: answer) else {
            wordError(title: "Word used already", message: "Be more original!")

        guard isPossible(word: answer) else {
            wordError(title: "Word not recognized", message: "You can't just make them up, you know!")

        guard isReal(word: answer) else {
            wordError(title: "Word not possible", message: "That isn't a real world")

        usedWords.insert(answer, at: 0)
        newWord = ""


    func startGame() {
        // 1. Find the URL for start.txt in our app bundle
        if let startWordsURL = Bundle.main.url(forResource: "start", withExtension: "txt") {
            // 2. Load start.txt into a string
            if let startWords = try? String(contentsOf: startWordsURL) {
                // 3. Split the string up into an array of strings, splitting on line breaks
                let allWords = startWords.components(separatedBy: "\n)")

                // 4. Pick one random word, or use "silkworm" as a sensible default
                rootWord = allWords.randomElement() ?? "silkworm"

                // If we are here everything has worked, so we can exit

        //If we're here then there was a problem -  trigger a crash and report the error
        fatalError("Could not load start.txt from bundle.")

    func isOriginal(word: String) -> Bool {

    func isPossible(word: String) -> Bool {
        var tempWord = rootWord

        for letter in word {
            if let pos = tempWord.firstIndex(of: letter) {
                tempWord.remove(at: pos)
        } else {
            return false
    return true

    func isReal(word: String) -> Bool {
        let checker = UITextChecker()
        let range = NSRange(location: 0, length: word.utf16.count)
        let misspelledRange = checker.rangeOfMisspelledWord(in: word, range: range, startingAt: 0, wrap: false, language: "en")

        return misspelledRange.location == NSNotFound

    func wordError(title: String, message: String) {
        errorTitle = title
        errorMessage = message
        showingError = true



Hi There,

So it's always showing 'aardvark', the first word in start.txt. First thought I had, was that your randomElement statement wasn't working correctly. That looked ok to me. Your line to separate the word list into an array looks correct to me, too. I'd add a print statement after that line, to print out the length of allWords. My guess is allWords just contains the one word, aardvark! If that's the case, and start.txt does indeed contain all the words, does the file actually not contain newlines but contains special characters instead? You can tell by opening up the file in vi, going to escape mode, and typing :set list.


You have a parenthesis in this line just after the n:

let allWords = startWords.components(separatedBy: "\n)")

Notice after the n there should be nothing:

let allWords = startWords.components(separatedBy: "\n")


Hacking with Swift is sponsored by RevenueCat

SPONSORED In-app subscriptions are a pain to implement, hard to test, and full of edge cases. RevenueCat makes it straightforward and reliable so you can get back to building your app. Oh, and it's free if your app makes less than $10k/mo.

Learn more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.