一、问题描述:

数独是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个九宫格内的数字均含1-9,不重复

要求:设计算法随机生成不同难度的数独游戏,阐述如何评价所生成数独的难度。

  • 问题分析:

(在此只涉及数独的生成,不涉及数独的求解)

数独问题的约束条件:
(1)每个矩阵的数字范围仅限1—9;

(2)每个数字在当前行不允许重复;

(3)每个数字在当前列不允许重复;

(4)每个数字在每一宫内不允许重复。

  • 问题求解思路

数独的生成,最好的情况就是,先得到一个完整的数独,然后根据难度需要,随机地挖一些空格出来,保证有解。所以关键就是如何得到完整的数独,也要有一定的随机化。

先要生成一个数独数组shudo[9][9],用memset函数对数组初始化,按照规则随机填数,然后根据给定的难度等级再随机挖洞,这就是我们生成的数独游戏。

  • 算法测试
    1.按照问题求解思路,在生成数独数组并将其完成初始化后,用shudu_1函数先对中间的九宫格完成随机填数。

随机填数具体实现是由一个a[10]数组来完成,用一个while循环用m变量给a[0]到a[8]随机赋值,且保证每个数组元素都各不相同。而在这过程中,用到了flag变量来进行数组元素是否重复的判断。在for循环遍历a[ ]数组前,给flag赋初值为0,一旦之前保存的数中出现了与m相同的数,就将flag标记为1并跳出循环,重新生成一个随机数m给a[ ]数组赋值,直到a[ ]数组随机填充数完毕。

数独生成代码java 生成数独算法_算法

 

2.在中间的九宫格完成随机填数后,用shudu_2函数对上下左右四个九宫格进行填数。

填数方法十分简单,利用已经填好的中间九宫格的数,交叉变换填充这四个九宫格。

数独生成代码java 生成数独算法_数据结构_02

数独生成代码java 生成数独算法_九宫格_03

3.最后shudu_3函数再对四个角上的数组填数,填数原理同第二步。到这一步为止,初始的随机填数数组已经生成好了。

数独生成代码java 生成数独算法_九宫格_04

 

4.再就是根据游玩者输入的难度随机挖洞,这里设置了4个难度。

(level 1)

数独生成代码java 生成数独算法_数独生成代码java_05

(level 2)

 

数独生成代码java 生成数独算法_数独生成代码java_06

(level 3)

数独生成代码java 生成数独算法_数独_07

 

(level 4)

数独生成代码java 生成数独算法_九宫格_08

 

以下是完整代码:

#include <stdio.h>

#include <cstring>

#include <iostream>

#include <algorithm>



using namespace std;



int shudu[9][9], hole[9][9];



//打印数独

void ouput()

{

    for (int i = 0; i < 9; ++i)

    {

        for (int j = 0; j < 9; ++j)

        {

            cout << shudu[i][j] << " ";

        }

        cout << endl;

    }

}



// 初始化中间的九宫格

void shudu_1()

{

    int a[10] = {};//初始化数组

int n = 0;

while(n < 9){

int m = rand() % 9 + 1;

int flag = 0;

for(int i = 0;i < n+1;i ++){

if(a[i] == m){

flag = 1;//如果之前保存的数中出现了和m相同的数,就把flag标记为1并跳出循环,表示需要重新生成随机数m

break;

}

}

if(flag == 0){

a[n] = m;//如果flag是0,表示前n个数中没有和m相同的数,因此可以把第n+1个元素赋值为m

n ++;

}

    int k = 0;

    for (int i = 3; i < 6; ++i)

        for (int j = 3; j < 6; ++j)

            shudu[i][j] = a[k++];

  }

}



// 由中间的九宫格交叉变换,初始化上下左右四个九宫格 (交换行列)

void shudu_2()

{

    for (int i = 3; i < 6; ++i)

    {

        int l = 0;

        for (int j = 3; j < 6; ++j)

        {

            if (i == 3)

            {

                shudu[i + 1][l] = shudu[i][j];

                shudu[i + 2][l + 6] = shudu[i][j];

                l++;

            }

            else if (i == 4)

            {

                shudu[i + 1][l] = shudu[i][j];

                shudu[i - 1][l + 6] = shudu[i][j];

                l++;

            }

            else if (i == 5)

            {

                shudu[i - 2][l] = shudu[i][j];

                shudu[i - 1][l + 6] = shudu[i][j];

                l++;

            }

        }

    }

    for (int j = 3; j < 6; ++j)

    {

        int l = 0;

        for (int i = 3; i < 6; ++i)

        {

            if (j == 3)

            {

                shudu[l][j + 1] = shudu[i][j];

                shudu[l + 6][j + 2] = shudu[i][j];

                l++;

            }

            else if (j == 4)

            {

                shudu[l][j + 1] = shudu[i][j];

                shudu[l + 6][j - 1] = shudu[i][j];

                l++;

            }

            else if (j == 5)

            {

                shudu[l][j - 2] = shudu[i][j];

                shudu[l + 6][j - 1] = shudu[i][j];

                l++;

            }

        }

    }

}



// 初始化四个角上的四个九宫格(和上面原理相同)

void shudu_3()

{

    for (int i = 0; i < 3; ++i)

    {

        int l = 0;

        for (int j = 3; j < 6; ++j)

        {

            if (i == 0)

            {

                shudu[i + 1][l] = shudu[i][j];

                shudu[i + 2][l + 6] = shudu[i][j];

                l++;

            }

            else if (i == 1)

            {

                shudu[i + 1][l] = shudu[i][j];

                shudu[i - 1][l + 6] = shudu[i][j];

                l++;

            }

            else if (i == 2)

            {

                shudu[i - 2][l] = shudu[i][j];

                shudu[i - 1][l + 6] = shudu[i][j];

                l++;

            }

        }

    }

    for (int i = 6; i < 9; ++i)

    {

        int l = 0;

        for (int j = 3; j < 6; ++j)

        {

            if (i == 6)

            {

                shudu[i + 1][l] = shudu[i][j];

                shudu[i + 2][l + 6] = shudu[i][j];

                l++;

            }

            else if (i == 7)

            {

                shudu[i + 1][l] = shudu[i][j];

                shudu[i - 1][l + 6] = shudu[i][j];

                l++;

            }

            else if (i == 8)

            {

                shudu[i - 2][l] = shudu[i][j];

                shudu[i - 1][l + 6] = shudu[i][j];

                l++;

            }

        }

    }

}



// 根据选择的难度随机挖数

void dighole(int difficulty)

{

    difficulty *= 20;

    while (difficulty--)

    {

        shudu[rand() % 9][rand() % 9] = 0;

    }

}



   

// 初始化数独

// 先随机生成中间的九宫格,再通过交叉生成上下左右四个九宫格,

// 最后通过交叉生成四个角上的九宫格

void Shudu(int difficulty)

{

    memset(shudu, 0, sizeof(shudu));

    shudu_1();

    shudu_2();

    shudu_3();

    dighole(difficulty);

}



int main()

{

    int d;

    cout << "请选择您希望生成数独难度(输入1~4,数字越大难度越高): ";

    cin >> d;

    Shudu(d);

    ouput();



    return 0;

}
  • 总结

总的来说,代码较为简单,用随机法生成数独,将一个随机的一维数组转化成二维数组,生成的数独是一个伪随机的数独。