mirror of
https://github.com/nicklockwood/SwiftFormat.git
synced 2026-06-16 10:34:34 +00:00
137 lines
3.3 KiB
Swift
137 lines
3.3 KiB
Swift
//
|
|
// ContentView.swift
|
|
// WordScramble
|
|
//
|
|
// Created by Nick Lockwood on 26/06/2020.
|
|
// Copyright © 2020 Nick Lockwood. All rights reserved.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
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 showError = false
|
|
|
|
var body: some View {
|
|
NavigationView {
|
|
VStack {
|
|
TextField(
|
|
"Enter your word",
|
|
text: $newWord,
|
|
onCommit: addNewWord
|
|
)
|
|
.textFieldStyle(RoundedBorderTextFieldStyle())
|
|
.padding()
|
|
.autocapitalization(.none)
|
|
|
|
List(usedWords, id: \.self) {
|
|
Image(systemName: "\($0.count).circle")
|
|
Text($0)
|
|
}
|
|
|
|
Text("Score: \(score)")
|
|
.font(.largeTitle)
|
|
.padding()
|
|
}
|
|
.navigationBarTitle(rootWord)
|
|
.onAppear(perform: startGame)
|
|
.alert(isPresented: $showError) {
|
|
Alert(title: Text(errorTitle), message: Text(errorMessage))
|
|
}
|
|
.navigationBarItems(leading: Button("Restart", action: startGame))
|
|
}
|
|
}
|
|
|
|
var score: Int {
|
|
usedWords.reduce(0) { total, word in total + word.count }
|
|
}
|
|
|
|
func addNewWord() {
|
|
let answer = newWord
|
|
.lowercased()
|
|
.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
|
|
guard !answer.isEmpty else {
|
|
return
|
|
}
|
|
|
|
guard answer.count >= 3 else {
|
|
wordError(title: "Word too short", message: "Must be at least 3 letters")
|
|
return
|
|
}
|
|
|
|
guard isOriginal(answer) else {
|
|
wordError(title: "Word used already", message: "Be more original")
|
|
return
|
|
}
|
|
|
|
guard isPossible(answer) else {
|
|
wordError(title: "Word not recognized", message: "You can't just make them up you know!")
|
|
return
|
|
}
|
|
|
|
guard isReal(answer) else {
|
|
wordError(title: "Word not possible", message: "That isn't a real word")
|
|
return
|
|
}
|
|
|
|
usedWords.insert(answer, at: 0)
|
|
newWord = ""
|
|
}
|
|
|
|
func startGame() {
|
|
usedWords.removeAll()
|
|
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")
|
|
}
|
|
|
|
func isOriginal(_ word: String) -> Bool {
|
|
!usedWords.contains(word) && word != rootWord
|
|
}
|
|
|
|
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
|
|
showError = true
|
|
}
|
|
}
|
|
|
|
struct ContentView_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
ContentView()
|
|
}
|
|
}
|