四子棋游戏获胜弹窗实现求助:已有胜负判断逻辑但方案失效
四子棋获胜检测与弹窗实现修复方案
一、核心问题修复
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
相关产品推荐
相关产品推荐

