鉴于是一款带有九张方形牌的益智游戏.
在每张卡片上,顶部,右侧,底部和左侧有4张图片.
卡片上的每张图片都描绘了动物的前部或后部(鳄鱼).每张图片有5种颜色中的一种.
目标:在3×3网格中布置九张卡片,使所有“内部”(完整)鳄鱼与相邻的卡片正确组合,即具有前端和后端以及匹配的颜色.
为了直观地解决问题,这里有一个难题的图片:
我手工找到了所描述的解决方案.
即使谜团看起来很简单,但由于你可以用4种不同的方式旋转每个部件,因此存在极大数量的组合.
现在的问题是,我希望有一个算法生成所有可能的3×3布局,以便检查所有可能的解决方案(如果有其他的话).最好在Processing / Java中.
思念至今:
我的方法是用4个整数数组来表示9个部分中的每个,表示一个部分的4个旋转状态.然后生成这9个片段的所有可能的排列,从片段阵列中挑选4个旋转状态中的1个.函数isValidSolution()然后可以检查违反约束的解决方案(颜色匹配和前后匹配).
有关如何实现这一点的任何想法?
最佳答案 可以找到所有解决方案,尽量不要探索搜索树的所有不成功路径.下面的C代码,没有高度优化,发现总共有两个解决方案(结果是相同的独特解决方案,因为有一个重复的磁贴,正确答案?)几乎是我的计算机瞬间.
这里避免探索所有可能性的技巧是在我们仍然放置切片时调用函数isValidSolution()(函数处理空切片).另外,为了加快这个过程,我按照给定的顺序放置瓷砖,从中间开始,然后在左,右,顶部和底部围绕它的交叉,然后是左上角,右上角,底部的角落 – 左右两边.可能其他组合可以更快地执行.
当然可以对此进行优化,因为这个拼图中的特殊模式分布(带有字母的模式只接受一个可能的匹配),但这超出了我的答案范围.
#include<iostream>
// possible pattern pairs (head, body)
#define PINK 1
#define YELLOW 2
#define BLUE 3
#define GREEN 4
#define LACOSTE 5
typedef int8_t pattern_t; // a pattern is a possible color, positive for head, and negative for body
typedef struct {
pattern_t p[4]; // four patterns per piece: top, right, bottom, left
} piece_t;
unsigned long long int solutionsCounter = 0;
piece_t emptyPiece = {.p = {0, 0, 0, 0} };
piece_t board[3][3] = {
{ emptyPiece, emptyPiece, emptyPiece},
{ emptyPiece, emptyPiece, emptyPiece},
{ emptyPiece, emptyPiece, emptyPiece},
};
inline bool isEmpty(const piece_t& piece) {
bool result = (piece.p[0] == 0);
return result;
}
// check current solution
bool isValidSolution() {
int i, j;
for (i = 0; i < 2; i++) {
for (j = 0; j < 3; j++) {
if (!isEmpty(board[i][j]) && !isEmpty(board[i+1][j]) && (board[i][j].p[1] != -board[i+1][j].p[3])) {
return false;
}
}
}
for (i = 0; i < 3; i++) {
for (j = 0; j < 2; j++) {
if (!isEmpty(board[i][j]) && !isEmpty(board[i][j+1]) && (board[i][j].p[2] != -board[i][j+1].p[0])) {
return false;
}
}
}
return true;
}
// rotate piece
void rotatePiece(piece_t& piece) {
pattern_t paux = piece.p[0];
piece.p[0] = piece.p[1];
piece.p[1] = piece.p[2];
piece.p[2] = piece.p[3];
piece.p[3] = paux;
}
void printSolution() {
printf("Solution:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("\t %2i ", (int) board[j][i].p[0]);
}
printf("\n");
for (int j = 0; j < 3; j++) {
printf("\t%2i %2i", (int) board[j][i].p[3], (int) board[j][i].p[1]);
}
printf("\n");
for (int j = 0; j < 3; j++) {
printf("\t %2i ", (int) board[j][i].p[2]);
}
printf("\n");
}
printf("\n");
}
bool usedPiece[9] = { false, false, false, false, false, false, false, false, false };
int colocationOrder[9] = { 4, 3, 5, 1, 7, 0, 2, 6, 8 };
void putNextPiece(piece_t pieces[9], int pieceNumber) {
if (pieceNumber == 9) {
if (isValidSolution()) {
solutionsCounter++;
printSolution();
}
} else {
int nextPosition = colocationOrder[pieceNumber];
int maxRotations = (pieceNumber == 0) ? 1 : 4; // avoids rotation symmetries.
for (int pieceIndex = 0; pieceIndex < 9; pieceIndex++) {
if (!usedPiece[pieceIndex]) {
usedPiece[pieceIndex] = true;
for (int rotationIndex = 0; rotationIndex < maxRotations; rotationIndex++) {
((piece_t*) board)[nextPosition] = pieces[pieceIndex];
if (isValidSolution()) {
putNextPiece(pieces, pieceNumber + 1);
}
rotatePiece(pieces[pieceIndex]);
}
usedPiece[pieceIndex] = false;
((piece_t*) board)[nextPosition] = emptyPiece;
}
}
}
}
int main() {
// register all the pieces (already solved, scramble!)
piece_t pieces[9] = {
{.p = { -YELLOW, -BLUE, +GREEN, +PINK} },
{.p = { -YELLOW, -GREEN, +PINK, +BLUE} },
{.p = { -BLUE, -YELLOW, +PINK, +GREEN }},
{.p = { -GREEN, -BLUE, +PINK, +YELLOW }},
{.p = { -PINK, -LACOSTE, +GREEN, +BLUE }},
{.p = { -PINK, -BLUE, +GREEN, +LACOSTE }},
{.p = { -PINK, -BLUE, +PINK, +YELLOW }},
{.p = { -GREEN, -YELLOW, +GREEN, +BLUE }},
{.p = { -GREEN, -BLUE, +PINK, +YELLOW }}
};
putNextPiece(pieces, 0);
printf("found %llu solutions\n", solutionsCounter);
return 0;
}