IT/swift

100 days of SwiftUI - Day31

가능성1g 2024. 11. 27. 12:23
반응형

오늘은 훌륭하게 만든 단어게임 업그레이드 하기

 

1. 3글자 이하이거나 root단어와 동일하면 오류 발생하게 하기

2. 툴바에 다시 시작하기 버튼 넣기(당연히 기능도 해야쥬?)

3. 점수 넣기 ( 난 단어의 길이만큼 점수 추가! )

 

//
//  ContentView.swift
//  WordScramble
//
//  Created by HanTJ on 11/25/24.
//

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 showingError = false
    
    @State private var score = 0
    
    var body: some View {
        NavigationStack {
            List {
                Section {
                    Text("Score: \(score)")
                }
                Section {
                    TextField("Enter your word", text: $newWord)
                        .textInputAutocapitalization(.never)
                }
                
                Section {
                    ForEach(usedWords, id: \.self) { word in
                        HStack {
                            //동그란거 안에 길이를 표시해주게 아이콘 만들기!
                            Image(systemName: "\(word.count).circle")
                            Text(word)
                        }
                    }
                }
            }
            .navigationTitle(rootWord)
            .onSubmit(addNewWord)  //UI내에서 엔터 치면 호출하는 함수 정의
            .onAppear(perform: startGame) //프로그램 시작시 호출되는 함수 정의
            .alert(errorTitle, isPresented: $showingError) {} message: { //OK버튼 생략 가능
                Text(errorMessage)
            }
            .toolbar {
                Button("다시시작"){
                    startGame()
                }
            }
        }
    }
    
    func addNewWord() {
        let answer = newWord.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)
        
        // 남은 수가 empty 면 리턴
        guard answer.count > 0 else { return }
        
        //단어의 적정성 체크
        guard isOriginal(word: answer) else {
            wordError(title: "Word used already", message: "Be more original!")
            return
        }
        
        guard isPossible(word: answer) else {
            wordError(title: "Word not Possible", message: "You can't spell that word from '\(rootWord)'!")
            return
        }
        
        guard isReal(word: answer) else {
            wordError(title: "Word not recogized", message: "You can't just make them up, you know!")
            return
        }
        
        //기본으로 withAnimation으로 해도 동작한다!
        withAnimation {
            //가장 앞에 넣음
            usedWords.insert(answer, at: 0)
        }
        //점수 추가 단어의 길이 만큼 추가함
        score += answer.count
        newWord = ""
    }
    
    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"
                usedWords.removeAll()
                score = 0
                return
            }
        }
        //fatalError는 무조건 프로그램을 종료시킨다.
        fatalError("Could not load start.txt from bundle.")
    }
    
    //중복체크
    func isOriginal(word: String) -> Bool {
        !usedWords.contains(word)
    }
    
    //rootWord를 이용해서 만든 글자인가 체크
    //3개 이하 안됨 추가
    //오리지널과 같으면 안됨 추가
    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
            }
        }
        
        //3개이하 체크
        if word.count < 3 {
            return false
        }
        
        //오리지날과 같음 체크
        if word == rootWord {
            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
    }
}

#Preview {
    ContentView()
}

점점 자신감이 붙는다!

반응형