modify files

This commit is contained in:
2025-07-18 20:44:44 +08:00
parent 197dcbfc03
commit 01a5ae0042
8 changed files with 3487 additions and 1 deletions

View File

@ -0,0 +1,153 @@
//
// WordPuzzleView.swift
// AIGrammar
//
// Created by oscar on 2025/7/16.
//
import SwiftUI
import AVFoundation
struct WordPuzzleGameView: View {
@State private var letters: [[String]] = []
@State private var selectedLetters: [(Int, Int)] = []
@State private var foundWords: [String] = []
@State private var score: Int = 0
@State private var remainingTime = 60
@State private var isGameOver = false
@GestureState private var dragLocation: CGPoint? = nil
@State private var audioPlayer: AVAudioPlayer?
let validWords = ["WORD", "GAME", "PUZZLE", "MET", "ME", "GO"]
let gridSize = 4
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
init() {
var chars = Array("WORDPUZZLEGAMETO").map { String($0) }
chars.shuffle()
_letters = State(initialValue: stride(from: 0, to: chars.count, by: gridSize).map {
Array(chars[$0..<$0+gridSize])
})
}
var body: some View {
VStack {
Text("Time: \(remainingTime)s Score: \(score)")
.font(.headline)
if isGameOver {
Text("Game Over!")
.font(.largeTitle)
.foregroundColor(.red)
} else {
VStack(spacing: 4) {
ForEach(0..<gridSize, id: \.self) { row in
HStack(spacing: 4) {
ForEach(0..<gridSize, id: \.self) { col in
Text(letters[row][col])
.font(.title)
.frame(width: 50, height: 50)
.background(
selectedLetters.contains(where: { $0 == (row, col) }) ?
Color.blue.opacity(0.7) : Color.gray.opacity(0.2)
)
.cornerRadius(8)
.onTapGesture {
handleSelect(row: row, col: col)
}
}
}
}
}
.gesture(
DragGesture()
.updating($dragLocation) { value, state, _ in
state = value.location
selectLetter(at: value.location)
}
.onEnded { _ in
submitWord()
}
)
}
ScrollView(.horizontal) {
HStack {
ForEach(foundWords, id: \.self) { word in
Text(word)
.padding(6)
.background(Color.green.opacity(0.3))
.cornerRadius(6)
}
}
.padding()
}
}
.padding()
.onReceive(timer) { _ in
guard !isGameOver else { return }
if remainingTime > 0 {
remainingTime -= 1
} else {
isGameOver = true
timer.upstream.connect().cancel()
}
}
}
///
private func handleSelect(row: Int, col: Int) {
if !selectedLetters.contains(where: { $0 == (row, col) }) {
selectedLetters.append((row, col))
}
}
///
private func selectLetter(at point: CGPoint?) {
guard let point = point else { return }
for row in 0..<gridSize {
for col in 0..<gridSize {
let cellSize: CGFloat = 50 + 4
let cellOrigin = CGPoint(x: CGFloat(col) * cellSize + 20,
y: CGFloat(row) * cellSize + 120)
let cellRect = CGRect(origin: cellOrigin, size: CGSize(width: 50, height: 50))
if cellRect.contains(point) {
if !selectedLetters.contains(where: { $0 == (row, col) }) {
selectedLetters.append((row, col))
}
}
}
}
}
///
private func submitWord() {
let word = selectedLetters.map { letters[$0.0][$0.1] }.joined()
if validWords.contains(word) && !foundWords.contains(word) {
foundWords.append(word)
score += word.count * 10
playSound(named: "success")
} else {
playSound(named: "fail")
}
selectedLetters.removeAll()
}
///
private func playSound(named name: String) {
guard let url = Bundle.main.url(forResource: name, withExtension: "mp3") else { return }
audioPlayer = try? AVAudioPlayer(contentsOf: url)
audioPlayer?.play()
}
}
struct WordPuzzleGameView_Previews: PreviewProvider {
static var previews: some View {
WordPuzzleGameView()
}
}
#Preview {
WordPuzzleGameView()
}