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

四子棋游戏获胜弹窗实现求助:已有胜负判断逻辑但方案失效

四子棋获胜检测与弹窗实现修复方案

一、核心问题修复

1. 获胜检测的颜色判断错误

在handleCellClick中,你落子后立即翻转了isRedTurn,导致后续检测获胜时用的是下一位玩家的颜色,而非刚落子玩家的颜色。这是弹窗不触发的主要原因:

原错误代码片段:

_state.value = _state.value.copy(board = updateBoard, isRedTurn = !_state.value.isRedTurn)

val currentColor = if (_state.value.isRedTurn) Color.Red else Color.Yellow
if (checkForWin(updateBoard, currentColor)) {
    // ... 弹窗逻辑
}

修复后代码:

// 先记录当前落子的颜色,再翻转回合
val currentColor = if (_state.value.isRedTurn) Color.Red else Color.Yellow
val updateBoard = _state.value.board.map { it.toMutableList().toList() }.toMutableList()
updateBoard[emptyRow] = 
    updateBoard[emptyRow].toMutableList().apply {
        set(boardWidth, currentColor)
    }.toList()
// 更新状态并翻转回合
_state.value = _state.value.copy(board = updateBoard, isRedTurn = !_state.value.isRedTurn)

// 用刚落子的颜色检测获胜
if (checkForWin(updateBoard, currentColor)) {
    winMessageState.winnerColor.value = currentColor
    winMessageState.isVisible.value = true
}

2. 胜负判断逻辑的边界优化

原代码的循环范围存在无效遍历,优化后减少不必要的判断,同时避免空指针风险:

优化后的checkForWin函数:

fun checkForWin(board: List<List<Color>>, colorToCheck: Color): Boolean {
    val rows = board.size
    if (rows == 0) return false
    val cols = board[0].size

    // 横向检测:每行从左到右,最多到 cols-4 的位置
    for (row in 0 until rows) {
        for (col in 0 until cols - 3) {
            if (board[row][col] == colorToCheck &&
                board[row][col+1] == colorToCheck &&
                board[row][col+2] == colorToCheck &&
                board[row][col+3] == colorToCheck
            ) {
                return true
            }
        }
    }

    // 纵向检测:每列从上到下,最多到 rows-4 的位置
    for (col in 0 until cols) {
        for (row in 0 until rows - 3) {
            if (board[row][col] == colorToCheck &&
                board[row+1][col] == colorToCheck &&
                board[row+2][col] == colorToCheck &&
                board[row+3][col] == colorToCheck
            ) {
                return true
            }
        }
    }

    // 对角线(左上到右下):起始位置最多到 rows-4 和 cols-4
    for (row in 0 until rows - 3) {
        for (col in 0 until cols - 3) {
            if (board[row][col] == colorToCheck &&
                board[row+1][col+1] == colorToCheck &&
                board[row+2][col+2] == colorToCheck &&
                board[row+3][col+3] == colorToCheck
            ) {
                return true
            }
        }
    }

    // 对角线(左下到右上):起始行从3开始,列最多到 cols-4
    for (row in 3 until rows) {
        for (col in 0 until cols - 3) {
            if (board[row][col] == colorToCheck &&
                board[row-1][col+1] == colorToCheck &&
                board[row-2][col+2] == colorToCheck &&
                board[row-3][col+3] == colorToCheck
            ) {
                return true
            }
        }
    }

    return false
}

二、获胜弹窗实现(Jetpack Compose)

基于你已有的winMessageState,用Compose的AlertDialog实现弹窗,同时锁定棋盘操作:

// 状态类定义
data class WinMessageState(
    var winnerColor: MutableState<Color> = mutableStateOf(Color.Transparent),
    var isVisible: MutableState<Boolean> = mutableStateOf(false)
)

// 弹窗组件
@Composable
fun WinDialog(winState: WinMessageState, onDismiss: () -> Unit) {
    if (winState.isVisible.value) {
        AlertDialog(
            onDismissRequest = onDismiss,
            title = { Text(text = "游戏结束") },
            text = {
                Text(
                    text = "${if (winState.winnerColor.value == Color.Red) "红方" else "黄方"}获胜!",
                    color = winState.winnerColor.value
                )
            },
            confirmButton = {
                Button(onClick = onDismiss) {
                    Text("再来一局")
                }
            }
        )
    }
}

// 主界面调用示例
@Composable
fun ConnectFourGame() {
    val winMessageState = remember { WinMessageState() }
    // ... 你的棋盘UI、状态逻辑

    WinDialog(winState = winMessageState) {
        // 重置游戏逻辑
        winMessageState.isVisible.value = false
        _state.value = _state.value.copy(
            board = createEmptyBoard(), // 替换为你的空棋盘创建逻辑
            isRedTurn = true
        )
    }
}

三、额外注意事项

  • 确保findLowestEmpty函数能正确找到当前列最下方的空位置
  • 弹窗显示时,需禁用棋盘的点击事件,避免误操作
  • 可添加平局检测逻辑(棋盘填满但无人获胜时触发对应弹窗)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 13:50:05