数独

最近摸鱼的时候玩数独,在leetcode上面也刷数独了,突发奇想自己写一个小游戏。

学到了dlx,真的很优雅的dancing呢

刷题

有效数独

https://leetcode.cn/problems/valid-sudoku/

遍历一次二维数组,行和列简单直接ij调换,九宫格旨在将每行的0-9列转换成每一个ceil的坐标,感觉像是转换成三进制一样👇由i来控制大ceil的坐标,j控制小ceil的坐标

(0,0) --> (0,0) (0,1) --> (0,1) (0,2) --> (0,2)

(0,3) --> (1,0) (0,4) --> (1,1) (0,5) --> (1,2)

(0,6) --> (2,0) (0,7) --> (2,1) (0,8) --> (2,2)

class Solution {
    public boolean isValidSudoku(char[][] board) {
        HashSet setx = new HashSet();
        HashSet sety = new HashSet();
        HashSet setceil = new HashSet();
        for (int i = 0 ;i < 9; i ++){
            for(int j = 0; j < 9; j ++){
                //
                if(board[i][j] != '.' && !setx.add(board[i][j])) return false;
                //
                if(board[j][i] != '.' && !sety.add(board[j][i])) return false;
                //九宫格
                if(board[(i % 3) * 3 + j / 3][(i / 3) * 3 + j % 3] != '.' && !setceil.add(board[(i % 3) * 3 + j / 3][(i / 3) * 3 + j % 3])) return false;
            }
            setx.clear();
            sety.clear();
            setceil.clear();
        }
        return true;
    }
}
View Code

解数独

https://leetcode.cn/problems/sudoku-solver/

如图,第一格为5,故第一行、第一列、第一大格均不能填写5

行列格的set均由000010000标记,标为1表示当前已经存在5;

第二格为3,故第一行,第二列,第一大格均不能填写3

行格set标记为000010100

列set标记为000000100

如此类推,通过9*9遍历压缩空格子填写数字的范围,减少产生n^9还判断是否合理的简单dfs

对于需要填写的地方要满足当前对应的行列格的01串均为0的位置,也就是异或后为0的位置

如图(0,2)的位置或后得到111110100,非一下得到000001011,标为1的地方即为(0,2)可填的数

数独变形

http://poj.org/problem?id=3076

这题真的看了挺久的

DLX模板修改一下。模板是要求每列有且只有一个1(精准覆盖),从行中选择,即行作为决策来覆盖解决列作为的任务。这题的决策就是某行某列填写某个字符即16行*16列*16个字符;任务就是每列填写字母且每列/每行/每个4*4格要有x字母(A-P),构建决策和任务的图是主要需要完成的任务。

16*16*16 每个决策都可进行标号,对于固定字符来说,该行决策只加入一列对应;对于待填写的位置,决策加入A-P所有字符(数独嘛,没有局限都是可填的,只是要找到一种多种决策集合精准覆盖条件,所以都加入)

 

数独生成

http://47.97.212.226:809/sudo/

https://pan.baidu.com/s/1K3gtXXB1FJMFKm9ArnneaQ?pwd=8888

我的弱智版已经写好了- -

看了几篇博客有些是通过现有数独交换行、列、旋转而产生的新数独,通过遮盖部分数字达到目的。确实比空棋盘上绘制棋盘再判断解题要简单得多。但是!but!however!先写个最简单的吧,完全是属于那种看了源码解一个格子就能解全部格子的那种。

作为基础的3*3方格
private void getCeilArray(){
    Random rand =new Random();
    ArrayList<Integer> list=new ArrayList<Integer>();
    for(int i=1;i<=length;i++) list.add(i);
    for(int i=0;i<length;i++){
        int index=rand.nextInt(10)%list.size();
        standard[i/3][i%3]=list.get(index);
        list.remove(index);
    }
}
View Code

3*3有了,通过操作最后一行提至第一行,进行两次操作就可以获得完整的3*9

假使我们得到standard为👇

1 2 3

4 5 6

7 8 9

将最后一行提至第一行两次得到两个3*3方阵,拼接后的3*9

_standard_______standard1______standard2_

1 2 3 | 7 8 9 | 4 5 6

4 5 6 | 1 2 3 | 7 8 9

7 8 9 | 4 5 6 | 1 2 3

同样的方法,改变列可以获得9*3,每个方格作为基准时执行两次即可,如下用count作为标记

private int[][] changeCeil(boolean isLine,int count,int[][] origin){
    int[][] res=new int[3][3];
    if(isLine){
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                res[(count+i)%3][j]=origin[i][j];
            }
        }
    }else{
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                res[i][(count+j)%3]=origin[i][j];
            }
        }
    }
    return res;
}
View Code

如上想是这么想的,但是最后写的时候确实是没用到......就是写死了三个,然后进行数字替换,交换行交换列的操作

交换数字,就是棋盘上所有1变成2,2变成3那样

private List<Integer> buildRandomList() {
    List<Integer> result = Arrays.asList( 1, 2, 3, 4, 5, 6, 7, 8, 9 );
    Collections.shuffle(result);
    return result;
}
View Code
public int[][] generateSudokuArray(int[][] sampleArray) {
    List<Integer> randomList = buildRandomList();
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            for (int k = 0; k < 9; k++) {
                if (sampleArray[i][j] == randomList.get(k)) {
                    sampleArray[i][j] = randomList.get((k + 1) % 9);
                    break;
                }
            }
        }
    }
    return sampleArray;
}
View Code

将9*9进行变化就得到最终的了,然后随机挖空就好了。

大佬版  https://github.com/huolizhuminh/AndroidSkills/tree/master/JavaSkillDemo/src/minhui/demo/mysodu/generator

 

数独的生成结束后!就是页面的问题了!

页面(真的不会写html,我好为难我自己

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:fragment="head">
<head>
    <meta charset="UTF-8"/>
    <title>Sudoku</title>
    <script type="text/javascript" th:inline="javascript">
        function doCheck(){
            /* <![CDATA[ */
            let origin = [[${originMap}]];
            let tbo = document.getElementById("sudoku-board");
            let trs = tbo.getElementsByTagName("tr");
            let flag = 0;
            let markWr = [];
            for(var i = 0; i < trs.length; i ++){
                let target = trs[i].getElementsByTagName("input");
                let row = []
                for(var j = 0; j < target.length; j ++){
                    if(target[j].value == ''){
                        flag = 1;
                        continue;
                    }else if(target[j].value != origin[i][j]){
                        flag = 2;
                        markWr.push({i,j})
                        //修改样式
                        target[j].style.setProperty('background','#FFDAB9')
                    }
                }
            }

            if(flag == 0)
                alert("bingo");
            else if(flag == 1)
                alert("你都还没填完!");
            else if(flag == 2)
                alert("答案错了~再瞅瞅?")
            /* ]]> */
        }
    </script>
    <style>
        #sudoku-table {
            margin: 0 auto;
            max-width: 658px;
            max-height: 658px;
        }
        #sudoku-board {
            border: 2px solid black;
            text-align:center;
            font-size:40px;
        }
        #sudoku-board td {
            padding: 0px;
            margin: 0px;
            border-collapse: collapse;
            border: none;
        }
        .mybtn{
            text-align:center;
            margin-left:20%;
        }
        input{
            width:62px;
            height:62px;
            font-size:40px;
            text-align:center;
            margin:4px;
        }
    </style>
</head>
<body>
<div class="panel-body" id="sudoku-panel">
    <table class="table table-striped" id="sudoku-table">
            <button class="mybtn" id="check" onclick="doCheck()">检查</button>
        <tbody id="sudoku-board">
            <tr th:each="row:${sudoMap}">
                <td th:each="col:${row}">
                    <input th:if="${col} != 0" th:value="${col}" disabled="disabled"/>
                    <input th:if="${col} == 0" th:type="text" onkeyup="if(this.value.length==1){this.value=this.value.replace(/[^1-9]/g,'')}else{this.value=this.value.slice(0,1)}"/>
                </td>
            </tr>
        </tbody>
    </table>
</div>

</body>

</html>
View Code
 

2022/9/9 13:36 新增安装程序链接

 
posted @ 2022-09-09 09:08  Aaaa_mber  阅读(120)  评论(0编辑  收藏  举报