zoukankan      html  css  js  c++  java
  • 随机生成一个数独

    最近学习用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 == 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 == 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 == 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 | 
    ***********************
    ------------------------------- 问道,修仙 -------------------------------
  • 相关阅读:
    python爬虫 --- 简书评论
    python 爬虫 伪装
    pygal的简单使用
    anaconda安装不存在的包
    python爬虫 赶集网
    my.conf 修改编码
    python3.6 使用 pymysql 连接 Mysql 数据库及 简单的增删改查操作
    基于visual Studio2013解决C语言竞赛题之1021九九乘法表
    基于visual Studio2013解决C语言竞赛题之1020订票
    基于visual Studio2013解决C语言竞赛题之1019填数
  • 原文地址:https://www.cnblogs.com/elvalad/p/4179239.html
Copyright © 2011-2022 走看看