c++ 像俄罗斯方块算法一样随机块的拼图
Posted
技术标签:
【中文标题】c++ 像俄罗斯方块算法一样随机块的拼图【英文标题】:c++ Puzzle like tetris algorithm for random pieces 【发布时间】:2021-11-08 00:15:20 【问题描述】:所以有一个小游戏,我试图根据以下描述找到解决方案:
你有一个 6x4 的棋盘,你会在棋盘上随机放置“俄罗斯方块”来填满棋盘。当棋盘填满时,您就成功完成了游戏。您从空板开始,然后在玩时将其填满。 不是“最合适”的那块可以扔掉,所以你可以用另一个随机的替换它。主要目标是用尽可能少的“替换”来完成比赛以获得最好的成绩。 另一个规则是你不能旋转这些碎片,所以它们只能按照给定的方式放置。你要么把它放在板上,要么把它扔掉。 由于它是基于 RNG 的,因此您可以连续 X 次获得相同的作品。
后期编辑:我想出了另一种方法来跟踪板上的棋子,因为“I”形状也被跟踪为旋转,所以我硬编码了它们可以使用的可能数组被放入,所以这里是新版本:
typedef struct StructSlotsInfo
bool isPosBusy;
BYTE shapeIndex;
;
int MAX_SLOTS_NR = 24;
StructSlotsInfo* piecesSlots = (StructSlotsInfo*)malloc(sizeof(StructSlotsInfo) * MAX_SLOTS_NR);
enum EnumShapes
SHAPE_NONE, // declared for indexing purposes so I won't go i+1;
SHAPE_1, // "I" shape 1x3
SHAPE_2, // single square
SHAPE_3, // "L" shape 2x2
SHAPE_4, // "L" shape - rotated version
SHAPE_5, // big square 2x2
SHAPE_6, // "Z" shape
SHAPE_7, // 3x2 shape - rectangle
;
bool IsValidPosition(BYTE shapePos, BYTE shapeType)
bool finalReturn = false;
BYTE posList[7][8] =
SHAPE_1, 12, 0, 6, 12, 0, 0, 0 ,
SHAPE_2, 24, 0, 0, 0, 0, 0, 0 ,
SHAPE_3, 17, 0, 6, 7, 0, 0, 0 ,
SHAPE_4, 17, 0, 1, 7, 0, 0, 0 ,
SHAPE_5, 17, 0, 1, 6, 7, 0, 0 ,
SHAPE_6, 16, 0, 1, 7, 8, 0, 0 ,
SHAPE_7, 16, 0, 1, 2, 6, 7, 8 ,
;
for (int i = 0; i < sizeof(posList) / sizeof(posList[0]); i++)
if (posList[i][0] == shapeType)
for (int j = 0; j < posList[i][1]; j++)
if (shapePos == j
&& piecesSlots[j + posList[i][2]].shapeIndex == 0
&& piecesSlots[j + posList[i][3]].shapeIndex == 0
&& piecesSlots[j + posList[i][4]].shapeIndex == 0
&& piecesSlots[j + posList[i][5]].shapeIndex == 0
&& piecesSlots[j + posList[i][6]].shapeIndex == 0
&& piecesSlots[j + posList[i][7]].shapeIndex == 0)
finalReturn = true;
break;
break;
return finalReturn;
void PlaceShape(BYTE shapePos, BYTE shapeType)
BYTE posList[7][7] =
SHAPE_1, 0, 6, 12, 0, 0, 0 ,
SHAPE_2, 0, 0, 0, 0, 0, 0 ,
SHAPE_3, 0, 6, 7, 0, 0, 0 ,
SHAPE_4, 0, 1, 7, 0, 0, 0 ,
SHAPE_5, 0, 1, 6, 7, 0, 0 ,
SHAPE_6, 0, 1, 7, 8, 0, 0 ,
SHAPE_7, 0, 1, 2, 6, 7, 8 ,
;
for (int i = 0; i < sizeof(posList) / sizeof(posList[0]); i++)
if (posList[i][0] == shapeType)
for (int j = 1; j < 7; j++)
if (j > 1 && posList[i][j] == 0)
continue;
if (posList[i][j] == 0)
piecesSlots[shapePos].isPosBusy = true;
piecesSlots[shapePos].shapeIndex = shapeType;
else
piecesSlots[shapePos + posList[i][j]].isPosBusy = false;
piecesSlots[shapePos + posList[i][j]].shapeIndex = shapeType;
break;
void CheckCompletedBoard()
bool isBoardCompleted = true;
for (int i = 0; i < MAX_SLOTS_NR; i++)
if (piecesSlots[i].shapeIndex == 0)
isBoardCompleted = false;
break;
if (isBoardCompleted)
for (int i = 0; i < MAX_SLOTS_NR; i++)
piecesSlots[i].isPosBusy = false;
piecesSlots[i].shapeIndex = 0;
cout << "The game is complete, resetted the board." << endl;
当我再次编写形状部分时,我已经评论了什么形状是他们枚举中的索引。
现在我有点卡住了。我应该如何将它们分配到“puzzleBoard”数组中并迭代以获得最佳可能性?对于这么大的问题,我很抱歉,但我已经尝试找到类似 2 天的东西了。
完成的棋盘本身看起来像这样:https://imgur.com/a/IYZbfGN(棋盘上并不是所有棋子,这只是一个示例,因为它们是随机给你的,你扔掉不合适的棋子),这里是完整作品列表:https://imgur.com/a/zPtuviY
非常感谢!
【问题讨论】:
你可以在github上搜索解决方案:俄罗斯方块机器人网站:github.com 顺便说一句,“俄罗斯方块”碎片被称为“tetrominos”(参见en.wikipedia.org/wiki/Tetromino),但您的作品似乎不是(除了两个)普通的tetrominos,而是“polyminos”(en.wikipedia.org/wiki/Polyomino) . 感谢 cmets。 Gowiser,我在 github 上查看了拼图和俄罗斯方块求解器,但基于这种游戏逻辑,我找不到像这样的解决方案。 jferard 感谢您的提醒,我对这些术语不太熟悉,所以我尝试尽可能清楚地解释。英语不是我的母语:P。 【参考方案1】:注意我误读了这个问题,并认为它是一个 C 问题。因此,我的答案是用 C 编写的,也不是 C++(哎呀)。我认为基本原则仍然适用。
我不能给你一个完整的答案,因为这需要很长时间,但我会给你一些建议。
您遇到的第一个问题是您所知道的关于arrayTemp
的全部内容是它是一个数组。你不知道它有多大,你不知道它的宽度和高度。因此,您的每个形状都需要具有该信息以及图案。
struct Shape
int width;
int height;
BYTE pattern[];
;
我会创建一个函数来填写数据(下面的代码不能保证没有错误,我直接将它输入到答案中而无需测试)。
struct Shape* makeShape(int with, int height, char* pattern)
struct Shape* ret = malloc(sizeof *ret);
ret->pattern = malloc(width * height);
for (i = 0 ; i < width * height ; ++i)
ret->pattern[i] = pattern[i]
return ret;
void freeShape(struct Shape* shape)
if (shape != NULL)
free(shape->pattern);
free(shape);
// example
struct Shape *zShape = makeShape(3, 2, shapeZ);
// Do stuff
freeShape(zShape);
那么当你需要将形状复制到你的puzzleBoard中时,你需要先根据形状的尺寸和拼图板的尺寸计算出源索引和目标索引,然后再决定是否可以复制。然后,如果你能复制它,你就复制它。
这是一个检查源形状中的BYTE
是否可以复制到目标形状的函数
bool cellCanBeCopied(struct Shape* sourceShape, int sourceRow, int sourceCol, struct Shape* destShape, int destRow, int destCol)
// Assume rows and cols are within the respective bounds of the shapes
// Leave the checks as an exercise for the reader
int sourceCell = sourceShape->width * sourceRow + sourceCol;
// If the cell is empty in the source shape, it doesn't matter
// if it's occupied in the dest shape
if (sourceShape->pattern[sourceCell] == 0)
return true;
int destCell = destShape->width * destRow + destCol;
return destShape=>pattern[destCell] == 0;
这里是如何使用它来检查是否可以复制整个形状。
bool shapeCanBeCopied(struct Shape* sourceShapestruct Shape* destShape, int destRow, int destCol)
// First check that the source shape will fit in the destination shape
if (destRow + sourceShape->height > destShape->height
|| destCol + sourceShape->width > destShape->width)
return false;
for (int sourceRow = 0 ; sourceRow < sourceShape.height ; ++sourceRow)
for (int sourceCol = 0 ; sourceCol < sourceShape.height ; ++sourceCol)
if (!cellCanBeCopied(sourceShape, sourceRow, sourceCol, destShape, destRow + sourceRow, destCol + souceCol))
return false;
return true;
您可能会问,当目的地是拼图板时,您是如何做到的?好吧,你可以像其他所有东西一样存储拼图板。
【讨论】:
非常感谢您的指导!我现在已经把支票放在了:)。事实上,通过结构等来跟踪形状更容易。我会看看我能想出什么来解决问题……在我看来,这是最难的逻辑,因为我必须尽可能用最少的动作来做。 @Aerya 我刚刚注意到这是一个 C++ 问题而不是 C 问题。在 C++ 中,您可能会创建一个类,但基本原理是相同的。 是的,我已经修复了所有需要修复和转换的部件,非常感谢!现在我要开始测试了。 我已经清理了代码并使其现在更易于理解(编辑了主帖),采取了另一种方法来跟踪零件,因为某些形状被视为“旋转”为有效,不是。非常感谢您的宝贵时间!以上是关于c++ 像俄罗斯方块算法一样随机块的拼图的主要内容,如果未能解决你的问题,请参考以下文章