卡拼图的算法解决方案

鉴于是一款带有九张方形牌的益智游戏.

在每张卡片上,顶部,右侧,底部和左侧有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;
}
点赞