본문 바로가기
IT/swift

100 days of SwiftUI - Day31

by 가능성1g 2024. 11. 27.
반응형

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

 

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

점점 자신감이 붙는다!

반응형