gpt4 book ai didi

SwiftUI 井字游戏板

转载 作者:行者123 更新时间:2023-12-04 11:26:52 26 4
gpt4 key购买 nike

我对 SwiftUI 非常陌生,我正在为我的类(class)开发井字游戏板。我正在关注 this Medium 上的文章,但我遇到了一个问题。

当您玩游戏时,方块不会激活。直到游戏结束,您才能看到移动的位置。
我不明白为什么会发生这种情况或如何解决它。任何帮助将非常感激!

import SwiftUI
import Combine

enum SquareStatus {
case empty
case visitor
case home
}

class Square: ObservableObject {
let didChange = PassthroughSubject<Void, Never>()

var status: SquareStatus {
didSet {
didChange.send(())
}
}

init(status: SquareStatus) {
self.status = status
}
}

class ModelBoard {
var squares = [Square]()
init() {
for _ in 0...8 {
squares.append(Square(status: .empty))
}
}
func resetGame() {
for i in 0...8 {
squares[i].status = .empty
}
}
var gameOver: (SquareStatus, Bool) {
get {
if thereIsAWinner != .empty {
return (thereIsAWinner, true)
} else {
for i in 0...8 {
if squares[i].status == .empty {
return (.empty, false)
}
}
return (.empty, true)
}
}
}
private var thereIsAWinner:SquareStatus {
get {
if let check = self.checkIndexes([0, 1, 2]) {
return check
} else if let check = self.checkIndexes([3, 4, 5]) {
return check
} else if let check = self.checkIndexes([6, 7, 8]) {
return check
} else if let check = self.checkIndexes([0, 3, 6]) {
return check
} else if let check = self.checkIndexes([1, 4, 7]) {
return check
} else if let check = self.checkIndexes([2, 5, 8]) {
return check
} else if let check = self.checkIndexes([0, 4, 8]) {
return check
} else if let check = self.checkIndexes([2, 4, 6]) {
return check
}
return .empty
}
}
private func checkIndexes(_ indexes: [Int]) -> SquareStatus? {
var homeCounter:Int = 0
var visitorCounter:Int = 0
for anIndex in indexes {
let aSquare = squares[anIndex]
if aSquare.status == .home {
homeCounter = homeCounter + 1
} else if aSquare.status == .visitor {
visitorCounter = visitorCounter + 1
}
}
if homeCounter == 3 {
return .home
} else if visitorCounter == 3 {
return .visitor
}
return nil
}
private func aiMove() {
var anIndex = Int.random(in: 0 ... 8)
while (makeMove(index: anIndex, player: .visitor) == false && gameOver.1 == false) {
anIndex = Int.random(in: 0 ... 8)
}
}
func makeMove(index: Int, player:SquareStatus) -> Bool {
if squares[index].status == .empty {
squares[index].status = player
if player == .home { aiMove() }
return true
}
return false
}
}

struct SquareView: View {
@ObservedObject var dataSource:Square
var action: () -> Void
var body: some View {
Button(action: {
self.action()
}) {
Text((dataSource.status != .empty) ?
(dataSource.status != .visitor) ? "X" : "0"
: " ")
.font(.largeTitle)
.foregroundColor(Color.black)
.frame(minWidth: 60, minHeight: 60)
.background(Color.gray)
.padding(EdgeInsets(top: 4, leading: 4, bottom: 4, trailing: 4))
}
}
}

struct ContentView : View {
private var checker = ModelBoard()
@State private var isGameOver = false

func buttonAction(_ index: Int) {
_ = self.checker.makeMove(index: index, player: .home)
self.isGameOver = self.checker.gameOver.1
}
var body: some View {
VStack {
HStack {
SquareView(dataSource: checker.squares[0]) { self.buttonAction(0) }
SquareView(dataSource: checker.squares[1]) { self.buttonAction(1) }
SquareView(dataSource: checker.squares[2]) { self.buttonAction(2) }
}
HStack {
SquareView(dataSource: checker.squares[3]) { self.buttonAction(3) }
SquareView(dataSource: checker.squares[4]) { self.buttonAction(4) }
SquareView(dataSource: checker.squares[5]) { self.buttonAction(5) }
}
HStack {
SquareView(dataSource: checker.squares[6]) { self.buttonAction(6) }
SquareView(dataSource: checker.squares[7]) { self.buttonAction(7) }
SquareView(dataSource: checker.squares[8]) { self.buttonAction(8) }
}
}
.alert(isPresented: $isGameOver) {
Alert(title: Text("Game Over"),
message: Text(self.checker.gameOver.0 != .empty ?
(self.checker.gameOver.0 == .home) ? "You Win!" : "iPhone Wins!"
: "Parity"), dismissButton: Alert.Button.destructive(Text("Ok"), action: {
self.checker.resetGame()
}) )
}
}
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif

最佳答案

您可能希望将 View 模型作为环境对象传递到 View 层次结构中,而不是在 View 中硬编码 VM 的构造。我稍微整理了一下代码。以下代码在 XCode 12.5 上运行良好。
我无法让 @NikzJon 版本或 Costantino Pistagna 的版本在最新的 XCode 上工作。
完整的项目可以在 GitHub 找到。

//  ContentView.swift

import SwiftUI

enum Owner
{
case vacant
case naught
case cross

var show: String
{
get {
switch self
{
case .vacant:
return " "
case .naught:
return "0"
case .cross:
return "X"
}
}
}
var showWinnerAsCross : String
{
switch self
{
case .vacant:
return "Draw!"
case .naught:
return "Lose!"
case .cross:
return "Win!"
}
}
var showWinnerAsNaught : String
{
switch self
{
case .vacant:
return "Draw!"
case .cross:
return "Lose!"
case .naught:
return "Win!"
}
}
static func blankSquares(_ n: Int) -> [Owner]
{
return [Owner](repeating: .vacant, count: n)
}
}
enum Slant
{
case forward
case back
}
enum WinCondition
{
case row (y:Int)
case col (x: Int)
case diag (slant: Slant)

static let rows : [WinCondition] = Array((0...2).map { row(y: $0)})
static let cols : [WinCondition] = Array((0...2).map { col(x: $0)})
static let diags : [WinCondition] = [diag(slant: .forward), diag(slant: .back)]

static let all : [WinCondition] = rows + cols + diags

var line : [Int] { get {
switch self{
case .row(y: let y) :
return [3*y+0,3*y+1,3*y+2]
case .col(x: let x):
return [x+0,x+3,x+6]
case .diag(slant: let slant):
return slant == .forward ? [0,4,8] : [2,4,6]
}
}
}

}
extension Array where Element == Owner
{
var free: [Int] { get
{
self
.enumerated()
.filter { $0.element == .vacant }
.map { $0.offset }
}
}
var randomFreeIndex: Int { get
{
let moves = self.free

let move = Int.random(in: 0..<moves.count)
return moves[move]
}
}
var isFull: Bool {
get
{
return self.free.isEmpty
}
}
}
class GameBoard : ObservableObject
{
@Published var squares = Owner.blankSquares( 9)

var currentPlayer = Owner.cross
var computerPlayer = Owner.naught

func reset() {
squares = Owner.blankSquares( 9)
}


func hasWon(player: Owner) -> Bool {
return WinCondition.all.contains { $0.line.allSatisfy { squares[$0] == player }}
}
var winner : Owner?
{
get {
if hasWon(player: .cross)
{
return .cross
}
else if hasWon(player: .naught)
{
return .naught
}
else if squares.free.isEmpty
{
return .vacant
}
return nil
}
}

@Published var isOver : Bool = false;
func checkIsOver()
{
if winner != nil
{
isOver = true
}
}
var showWinner : String
{
get{
return "You " + (winner?.showWinnerAsCross ?? " ")
}
}
func randomMove(player: Owner) {
if squares.isFull
{
return
}
squares[squares.randomFreeIndex] = player
}
func turn(squareIndex:Int) {
if squares[squareIndex] != .vacant
{
return
}
squares[squareIndex] = currentPlayer
checkIsOver()
randomMove(player: computerPlayer)
checkIsOver()
}

}
struct SquareView: View {
@EnvironmentObject var board: GameBoard
var index: Int
var body: some View {
Button(action: {
board.turn(squareIndex: index)
}) {
Text( board.squares[index].show)
.foregroundColor(Color.white)
.font(.largeTitle)
.frame(minWidth: 80, minHeight: 80)
.background(Color.blue)
.padding(EdgeInsets(top: 3, leading: 3, bottom: 3, trailing: 3))
}
}
}
struct ContentView: View {
@EnvironmentObject var board: GameBoard

var body: some View {
VStack {
HStack {
SquareView(index:0)
SquareView(index:1)
SquareView(index:2)
}
HStack {
SquareView(index:3)
SquareView(index:4)
SquareView(index:5)
}
HStack {
SquareView(index:6)
SquareView(index:7)
SquareView(index:8)
}
}
.alert(isPresented: $board.isOver) {
Alert(title: Text( board.showWinner) , dismissButton: Alert.Button.destructive(Text("Try Again"), action:
board.reset
) )
}
}
}

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

// tictactoeApp.swift


import SwiftUI

@main
struct tictactoeApp: App {
@StateObject var board = GameBoard()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(board)
}
}
}

关于SwiftUI 井字游戏板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61622170/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com