UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: adding a score to Word scramble

Forums > SwiftUI

hi all,

despite my best efforts here I am back at the forum seeking guidance.

i wrote the additional following code:

 @State private var score = 0
 @State private var scoreTitle = ""
 @State private var showingScore = false
  if newWord == isOriginal && isReal && isPossible && rootWord != newWord && answer.count >= 3 {
       scoreTitle = "Well done"
       score += 100
   } else {
       scoreTitle = "Try again"
       score -= 100
   }

        showingScore = true

I am trying to write that if all the conditions for isOriginal, isReal, isPossible, rootWord != newWord and the answer.count is >=3 are met (from guard) then the score adds/subtracts 100 accordingly. I've written it numerous ways but have had no success, and am really questioning my ability at this point...

appreciate any thoughts/guidance    

    full code below:
//
//  ContentView.swift
//  WordScramble
//
//  Created by paul taylor on 6/21/21.
//

import SwiftUI

struct ContentView: View {
    @State private var usedWords = [String]()
    @State private var rootWord = ""
    @State private var newWord = ""
    @State private var score = 0
    @State private var scoreTitle = ""
    @State private var showingScore = false

    @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)
                    .textFieldStyle(RoundedBorderTextFieldStyle())
                    .autocapitalization(.none)
                    .padding()

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

            }
            .navigationBarTitle(rootWord)

            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Start Game", action: startGame)
                }
            }

            .onAppear(perform: startGame)
            .alert(isPresented: $showingError) {
                Alert(title: Text(errorTitle), message: Text(errorMessage), dismissButton:
                        .default(Text("OK")))
            }
        }
    }
    func addNewWord() {
        let answer = newWord.lowercased()
            .trimmingCharacters(in:.whitespacesAndNewlines)

        guard answer.count > 0 else {
            return
        }

        guard isOriginal(word: answer) else {
            wordError(title: "Word used already", message: "Please be more original")
            return
        }

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

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

        guard answer.count >= 3 else {
            wordError(title: "Word isn't possible", message: "It is less than 3 characters")
            return
        }

        guard rootWord != newWord else {
            wordError(title: "Word isn't possible", message: "It is the same as the root word")
            return

        }

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

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

        //================================

        if newWord == isOriginal && isReal && isPossible && answer.count >= 3 {
            scoreTitle = "Well done"
            score += 1
        } else {
            scoreTitle = "Try again"
            score -= 1
        }

        showingScore = true

        // ================================

    }

    func startGame() {
        if let startWordsURL =
            Bundle.main.url(forResource: "start", withExtension: "txt") {
            if let startWords = try?
                String(contentsOf: startWordsURL) {
                let allWords =
                    startWords
                    .components(separatedBy: "\n")
                rootWord = allWords.randomElement()
                    ?? "silkworm"
                return
            }
        }
        fatalError("Could not load start.txt from bundle.")
    }

    func isOriginal(word: String) -> Bool {
        !usedWords.contains(word)
    }

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

        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
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

3      

Unfortunately SwiftUI, at the present moment, does not work well with multple alerts on a View. Maybe that will change in the future, but you only have one View at the moment (the VStack). If you have other views, for example a Button is another view that can have a .alert attached to it, then you could have a second alert. I think that that would be too much for this example. so I would suggest just showing the score anyway, under the word entry.

Secondly, you do not need the if statement, as the guard statements have effectively done all that work. Also, I see that you want to reduce the score when the word fails of the guard conditions. So put the score -= 1 in the else part of each guard statement.

VStack {
    TextField("Enter your word", text: $newWord, onCommit: addNewWord)
        .textFieldStyle(RoundedBorderTextFieldStyle())
        .autocapitalization(.none)
        .padding()

        Text("Your score is \(score)")

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

Put score -= 1 in each of the guard statements, here is an example.

guard isOriginal(word: answer) else {
    wordError(title: "Word used already", message: "Please be more original")
    score -= 1
    return
}

No need for if statement here, because of the guard statements above.

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

//================================

scoreTitle = "Well done"
score += 1

 // showingScore = true     // Until a second alert is possible no need to use this

 // ================================

showingScore = true and scoreTitle = "Try again" not useful until a second alert can be introduced into the code.

3      

thanks,

much appreciate. will work on ammending my code, thanks to your help.

Paul

3      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

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.