You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin开发井字棋应用玩家对战电脑功能实现故障求助

井字棋玩家对战电脑功能问题修复方案

核心问题汇总

  • 主线程阻塞:playGame方法中调用Thread.sleep会阻塞Android主线程,容易触发ANR闪退,且同步循环逻辑不符合点击交互的异步特性,无法等待玩家手动落子。
  • 点击事件重复绑定:update_player方法每次调用都会给所有按钮重新绑定点击事件,会导致单次点击触发多次回调,且绑定事件后直接切换回合,未等待玩家实际落子。
  • 电脑落子逻辑错误:子线程生成随机坐标是异步执行,主线程判断坐标状态时子线程还未完成赋值,拿到的永远是初始值row=0、column=0;随机数计算逻辑简单,完全不需要放到子线程执行,额外开线程反而导致逻辑混乱。
  • 状态判断错误:boardStatus初始值为-1代表未占用,现有占用判断逻辑写反,且未等落子成功就累加turnCount、判断胜负,计数和胜负判定完全失准。
  • 递归风险:电脑落子位置占用后递归调用自身,满盘状态下会出现无限递归导致栈溢出。

修复思路

  1. 移除playGame中的同步循环和Thread.sleep逻辑,改为异步事件驱动流程:初始化时仅绑定一次按钮点击事件,玩家点击落子完成后,自动触发电脑落子逻辑。
  2. 电脑落子逻辑去掉无用的子线程,直接在主线程生成随机坐标,循环判断直到找到可用位置即可,不需要递归。
  3. 胜负判断、回合切换都放在落子成功之后执行,UI延迟切换用postDelayed实现,不阻塞主线程。

修复后完整代码

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.widget.Button
import kotlinx.android.synthetic.main.activity_computer.*

class ComputerActivity : AppCompatActivity() {
    var player = true
    var turnCount = 0
    var boardStatus = Array(3) { IntArray(3) }
    lateinit var board: Array<Array<Button>>
    private val mainHandler = Handler(Looper.getMainLooper())
    private var isGameOver = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_computer)
        board = arrayOf(
            arrayOf(First, Second, Third),
            arrayOf(Fourth, Fifth, Sixth),
            arrayOf(Seventh, Eighth, Ninth)
        )
        initButtonClick()
        resetBtn.setOnClickListener{
            resetGame()
        }
        resetGame()
    }

    private fun initButtonClick() {
        // 仅初始化时绑定一次点击事件
        for (i in 0..2) {
            for (j in 0..2) {
                board[i][j].setOnClickListener{
                    if (player && !isGameOver && boardStatus[i][j] == -1) {
                        // 玩家落子
                        updateBoardStatus(i, j, player)
                        afterMove()
                    }
                }
            }
        }
    }

    private fun resetGame() {
        player = true
        turnCount = 0
        isGameOver = false
        Status.text = "Player's Turn"
        // 重置棋盘状态
        for (i in 0..2) {
            for (j in 0..2) {
                boardStatus[i][j] = -1
                board[i][j].apply {
                    isEnabled = true
                    text = ""
                }
            }
        }
    }

    private fun afterMove() {
        turnCount++
        checkWinner()
        if (isGameOver) return
        if (turnCount == 9) {
            Status.text = "Game Draw"
            isGameOver = true
            disableButton()
            return
        }
        // 切换回合
        player = !player
        if (!player) {
            Status.text = "Computer's Turn"
            disableButton()
            // 延迟1秒后电脑落子,模拟思考过程
            mainHandler.postDelayed({
                computerMove()
            }, 1000)
        } else {
            Status.text = "Player's Turn"
            enableButton()
        }
    }

    private fun computerMove() {
        // 生成可用的随机坐标
        var row: Int
        var column: Int
        do {
            row = (0..2).random()
            column = (0..2).random()
        } while (boardStatus[row][column] != -1)
        // 电脑落子
        updateBoardStatus(row, column, player)
        afterMove()
    }

    private fun updateBoardStatus(row:Int, column:Int, player:Boolean){
        val text = if (player) "X" else "0"
        val value = if (player) 1 else 0
        board[row][column].apply {
            isEnabled = false
            setText(text)
        }
        boardStatus[row][column] = value
    }

    private fun checkWinner(){
        //Horizontal --- rows
        for (i in 0..2) {
            if (boardStatus[i][0] == boardStatus[i][1] && boardStatus[i][0] == boardStatus[i][2] && boardStatus[i][0] != -1) {
                if (boardStatus[i][0] == 1) {
                    result("Player Won!!")
                } else if (boardStatus[i][0] == 0) {
                    result("Computer Won")
                }
                return
            }
        }
        //Vertical --- columns
        for (i in 0..2) {
            if (boardStatus[0][i] == boardStatus[1][i] && boardStatus[0][i] == boardStatus[2][i] && boardStatus[0][i] != -1) {
                if (boardStatus[0][i] == 1) {
                    result("Player Won!!")
                } else if (boardStatus[0][i] == 0) {
                    result("Computer Won!!")
                }
                return
            }
        }
        //First diagonal
        if (boardStatus[0][0] == boardStatus[1][1] && boardStatus[0][0] == boardStatus[2][2] && boardStatus[0][0] != -1) {
            if (boardStatus[0][0] == 1) {
                result("Player Won!!")
            } else if (boardStatus[0][0] == 0) {
                result("Computer won!!")
            }
            return
        }
        //Second diagonal
        if (boardStatus[0][2] == boardStatus[1][1] && boardStatus[0][2] == boardStatus[2][0] && boardStatus[0][2] != -1) {
            if (boardStatus[0][2] == 1) {
                result("Player Won!!")
            } else if (boardStatus[0][2] == 0) {
                result("Computer Won!!")
            }
            return
        }
    }

    private fun result(res:String){
        Status.text = res
        isGameOver = true
        disableButton()
    }

    private fun disableButton(){
        for(i in board){
            for(button in i){
                button.isEnabled = false
            }
        }
    }

    private fun enableButton(){
        for(i in 0..2){
            for(j in 0..2){
                if (boardStatus[i][j] == -1) {
                    board[i][j].isEnabled = true
                }
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Divyanshu Dobriyal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.08 20:48:00