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

Jetpack Compose中能否在ViewModel实现双空白单元格的拼图游戏?

在Jetpack Compose中实现双空白单元格拼图的解决方案

Jetpack Compose完全可以实现双空白单元格的拼图功能,你之前遇到的仅一个生效的问题,大概率是状态管理或交换逻辑的疏漏导致的。以下是具体实现思路和关键代码示例:

1. 正确管理双空白位置的状态

需要用状态变量存储两个空白单元格的位置,推荐使用Set<Position>(天然避免重复,且方便遍历判断):

data class Position(val x: Int, val y: Int)

// 初始化两个空白单元格的位置(示例为4x4棋盘的右下角两个位置)
var emptyPositions by remember {
    mutableStateOf(
        setOf(
            Position(x = 3, y = 3),
            Position(x = 3, y = 2)
        )
    )
}

// 用mutableStateListOf存储拼图数据,确保数据变动能触发UI重组
val puzzleData = remember {
    mutableStateListOf(
        listOf(1,2,3,4),
        listOf(5,6,7,8),
        listOf(9,10,11,12),
        listOf(13,0,0,16) // 0代表空白占位
    )
}

2. 完善相邻交换逻辑

点击单元格时,需要遍历所有空白位置,判断当前点击位置是否与任意空白单元格相邻(上下左右),匹配后执行交换并更新状态:

fun handleCellClick(clickedPos: Position) {
    // 找到与点击位置相邻的空白单元格
    val matchedEmpty = emptyPositions.firstOrNull { emptyPos ->
        (clickedPos.x == emptyPos.x && kotlin.math.abs(clickedPos.y - emptyPos.y) == 1) ||
        (clickedPos.y == emptyPos.y && kotlin.math.abs(clickedPos.x - emptyPos.x) == 1)
    }

    matchedEmpty?.let {
        // 更新空白位置集合:移除匹配的空白,添加点击位置
        emptyPositions = emptyPositions - it + clickedPos
        // 交换拼图数据中点击位置与空白位置的内容
        swapPuzzleCells(clickedPos, it)
    }
}

private fun swapPuzzleCells(pos1: Position, pos2: Position) {
    val temp = puzzleData[pos1.x][pos2.y]
    // 由于mutableStateListOf是不可变列表的集合,需要先替换行数据
    puzzleData[pos1.x] = puzzleData[pos1.x].toMutableList().apply {
        set(pos1.y, puzzleData[pos2.x][pos2.y])
    }
    puzzleData[pos2.x] = puzzleData[pos2.x].toMutableList().apply {
        set(pos2.y, temp)
    }
}

3. UI渲染区分空白单元格

在绘制棋盘时,检查当前位置是否属于空白集合,以此渲染不同样式:

LazyVerticalGrid(columns = GridCells.Fixed(4), modifier = Modifier.padding(16.dp)) {
    itemsIndexed(puzzleData) { x, row ->
        row.forEachIndexed { y, cellValue ->
            val isEmpty = emptyPositions.contains(Position(x, y))
            Box(
                modifier = Modifier
                    .size(80.dp)
                    .border(1.dp, Color.Gray)
                    .background(if (isEmpty) Color.LightGray else Color.White)
                    .clickable(enabled = !isEmpty) {
                        handleCellClick(Position(x, y))
                    },
                contentAlignment = Alignment.Center
            ) {
                if (!isEmpty) {
                    Text(text = cellValue.toString(), fontSize = 24.sp, fontWeight = FontWeight.Bold)
                }
            }
        }
    }
}

常见问题排查

  • 若之前仅用单个变量存储空白位置,会导致第二个空白无法参与逻辑判断;
  • 交换逻辑未遍历所有空白位置,仅处理了第一个空白,导致第二个空白无法触发交换;
  • 拼图数据更新时未关联第二个空白的位置,导致UI与数据状态不一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 20:01:13