首页 > 代码库 > 随机生成一个数独

随机生成一个数独

最近学习用Java编写GUI程序,感觉从做一个小东西入手最好,选择了编写一些小游戏开始,第一个为数独游戏。

http://en.wikipedia.org/wiki/Sudoku

编写数独游戏第一步考虑的就是该如何生成一个原始的数独题目,要想生成数独题目最简单的办法就是先随机生成一个完整的数独,然后从中摘除一些数字,这样就可以生成一道数独题。所以需要考虑如何随机的生成一个完整的数独,这里考虑使用回溯法生成:

  • 在数独的某个位置插入一个1~9的值
  • 如果这个值能正常插入,则递归在下一个位置插入
  • 如果这个位置没有值可以插入,则回溯上一个位置插入的值
  • 递归以上步骤直到所有的位置全部都插入了合适的值
import java.util.Random;public class Main {    private static int[] num = new int[81];    private static Random random = new Random();    /**     * 随机产生一个数独     * @return 返回一个随机产生的数独     */    public static int[] generate() {        for (int i = 0; i < 81; i++) {            num[i] = 0;        }        solve(0);        return num;    }    /**     * 递归产生数独位置i的值     * @param 数独位置i     * @return 位置i是否可以填入值     */    private static boolean solve(int i) {        /* 如果已经填满81个格子则返回true */        if (i == 81) {            return true;        }        /* 如果位置i已经填入了合适的值则递归产生下一个位置的值 */        else if (num[i] != 0) {            return solve(i + 1);        }        /* 如果恰好需要填入位置i的值 */        else {            /* 用数组randOrder存储每个位置可能产生的值,即为1~9 */            int[] randOrder = new int[10];            for (int val = 1; val < 10; val++) {                randOrder[val] = val;            }            /* 将数组randOrder变为一个随机存储1~9的数组 */            for (int val = 1; val < 10; val++) {                int rand = random.nextInt(10);                int tmp = randOrder[rand];                randOrder[rand] = randOrder[val];                randOrder[val] = tmp;            }            /* 在位置i随机填入一个值,并且判断是否有效 */            for (int val = 1; val < 10; val++) {                /* 如果在位置i填入的1~9中的某个随机数有效 */                if (isLegal(i, randOrder[val])) {                    /* 则将此随机值放入位置i */                    num[i] = randOrder[val];                    /* 探索i的下一个位置是否能正确填入,如果可以则返回true */                    if (solve(i + 1)) {                        return true;                    }                }            }        }        /* 如果在位置i不能填入1~9中的任何值,则需要回溯 */        num[i] = 0;        return false;    }    /**     * 在位置i填入value数字是否有效,通过按行列和小矩阵判断     * @param 填入的位置i     * @param 填入位置i的数字value     * @return 在位置i填入数字value是否有效     */    private static boolean isLegal(int i, int value) {        /* 判断行是否有效 */        if (!isRowLegal(i, value)) {            return false;        }        /* 判断列是否有效 */        if (!isColLegal(i, value)) {            return false;        }        /* 判断小矩阵是否有效 */        if (!isSubLegal(i, value)) {            return false;        }        return true;    }    /**     * 判断在位置i填入value行规则是否满足     * @param 填入的位置i     * @param 填入位置i的数字value     * @return 在位置i填入数字value行规则是否有效     */    private static boolean isRowLegal(int i, int value) {        int row = i / 9;        for (int val = 0; val < 9; val++) {            if (value =http://www.mamicode.com/= num[row * 9 + val]) {                return false;            }        }        return true;    }    /**     * 判断在位置i填入value列规则是否满足     * @param 填入的位置i     * @param 填入位置i的数字value     * @return 在位置i填入数字value列规则是否有效     */    private static boolean isColLegal(int i, int value) {        int col = i % 9;        for (int val = 0; val < 9; val++) {            if (value =http://www.mamicode.com/= num[val * 9 + col]) {                return false;            }        }        return true;    }    /**     * 判断在位置i填入value小矩阵规则是否满足     * @param 填入的位置i     * @param 填入位置i的数字value     * @return 在位置i填入数字value小矩阵规则是否有效     */    private static boolean isSubLegal(int i, int value) {        int row = i / 9;        int col = i % 9;        int xOff = row / 3 * 3;        int yOff = col / 3 * 3;        for (int x = 0; x < 3; x++) {            for (int y = 0; y < 3; y++) {                if (value =http://www.mamicode.com/= num[(xOff + x) * 9 + yOff + y]) {                    return false;                }            }        }        return true;    }    public static void main(String[] args) {        int[][] grid = new int[9][9];        int[] sudoku = new int[81];        for (int i = 0; i < 81; i++) {            sudoku[i] = 0;        }        sudoku = generate();        for (int i = 0; i < 9; i++) {            for (int j = 0; j < 9; j++) {                grid[i][j] = sudoku[i * 9 + j];            }        }        System.out.println("***********************");        for (int i = 0; i < 9; i++) {            for (int j = 0; j < 9; j++) {                System.out.print(grid[i][j] + " ");                if (j % 3 == 2) {                    System.out.print("| ");                }            }            System.out.println();            if (i % 3 == 2) {                System.out.println("***********************");            }        }    }}

运行结果:

***********************2 3 9 | 7 6 8 | 1 5 4 | 8 4 7 | 1 5 3 | 6 9 2 | 1 5 6 | 2 4 9 | 8 7 3 | ***********************3 7 8 | 5 2 1 | 9 4 6 | 6 1 5 | 4 9 7 | 3 2 8 | 9 2 4 | 3 8 6 | 5 1 7 | ***********************5 8 1 | 6 7 2 | 4 3 9 | 4 9 2 | 8 3 5 | 7 6 1 | 7 6 3 | 9 1 4 | 2 8 5 | **********************************************2 4 6 | 7 5 3 | 9 8 1 | 9 1 8 | 6 4 2 | 5 7 3 | 5 7 3 | 9 8 1 | 6 4 2 | ***********************4 5 7 | 3 2 9 | 8 1 6 | 8 3 9 | 5 1 6 | 7 2 4 | 6 2 1 | 8 7 4 | 3 5 9 | ***********************3 8 2 | 1 9 7 | 4 6 5 | 7 6 4 | 2 3 5 | 1 9 8 | 1 9 5 | 4 6 8 | 2 3 7 | ***********************

 

随机生成一个数独