C++实现6x4无旋转类俄罗斯方块拼图随机块最优放置最小替换方案
形状映射到二维棋盘的实现
你当前使用的扁平化piecesSlots数组本质就是压缩存储的棋盘,6列4行的结构对应索引计算规则为:
// 扁平索引 <-> 二维坐标转换 #define GET_ROW(slot_idx) (slot_idx / 6) #define GET_COL(slot_idx) (slot_idx % 6) #define GET_SLOT_IDX(row, col) ((row) * 6 + (col))
如果需要显式的puzzleBoard二维数组,直接遍历24个槽位赋值即可:
bool puzzleBoard[4][6] = {0}; for (int i = 0; i < MAX_SLOTS_NR; i++) { puzzleBoard[GET_ROW(i)][GET_COL(i)] = piecesSlots[i].isPosBusy; }
你现有代码里的形状偏移规则已经完全适配该映射逻辑,无需额外调整。
最优放置搜索方案
第一步:遍历所有合法位置
你已经实现了IsValidPosition接口,直接遍历当前形状的所有可能起始位置即可,不同形状的最大起始位置可以直接从你定义的posList数组中读取。
第二步:放置评分逻辑
核心目标是最小化丢弃次数,所以评分规则按优先级从高到低排序:
- 无无效空白区域:放置后所有连通的空白区域的大小,可被现有形状的占格数(1/3/4/6)组合填充,不符合直接排除该位置
- 剩余空白数最少:相同条件下优先选填完后剩余空格更少的位置
- 空白区域数最少:相同剩余空格数下,优先选空白区域更集中的位置
第三步:模拟放置实现
新增三个辅助函数即可完成搜索:
// 临时缓存模拟放置前的槽位状态 StructSlotsInfo tempSlots[MAX_SLOTS_NR]; void SimulatePlace(BYTE shapePos, BYTE shapeType) { // 先备份当前槽位状态 memcpy(tempSlots, piecesSlots, sizeof(tempSlots)); // 调用现有放置逻辑 PlaceShape(shapePos, shapeType); } void RollbackPlace() { // 回滚到备份状态 memcpy(piecesSlots, tempSlots, sizeof(tempSlots)); } int CalcCurrentScore() { int score = 0; // 已填充格子数加分,填充越多分越高 for (int i = 0; i < MAX_SLOTS_NR; i++) { if (piecesSlots[i].shapeIndex != 0) score += 1; } // 连通空白区域检查,有无效区域扣1000分直接排除 int blankRegions = CheckBlankRegions(); if (blankRegions < 0) score -= 1000; return score; }
其中CheckBlankRegions用简单的DFS/BFS遍历所有空白格子,计算每个连通区域的大小,只要存在小于1或者无法被1/3/4/6组合的大小,直接返回负数即可。
第四步:搜索逻辑
int GetBestPlacePosition(BYTE currentShape) { int bestPos = -1; int maxScore = -10000; BYTE maxPos = 0; // 读取当前形状的最大起始位置 for (int i = 0; i < 7; i++) { if (posList[i][0] == currentShape) { maxPos = posList[i][1]; break; } } // 遍历所有可能位置 for (int pos = 0; pos < maxPos; pos++) { if (!IsValidPosition(pos, currentShape)) continue; SimulatePlace(pos, currentShape); int currentScore = CalcCurrentScore(); RollbackPlace(); if (currentScore > maxScore) { maxScore = currentScore; bestPos = pos; } } return bestPos; }
调用该函数后如果返回值>=0,直接放置即可;如果返回-1,直接丢弃当前块。
现有代码修复提示
你当前PlaceShape函数中,非0偏移位置的isPosBusy赋值写反了,应该统一设置为true,否则会导致后续合法位置判断错误。
内容的提问来源于stack exchange,提问作者Aerya
相关产品推荐
相关产品推荐

