当前位置:   article > 正文

【休闲益智】【HTML】我的数独我做主_html 数独解答

html 数独解答

我正在参加掘金社区游戏创意投稿大赛个人赛,详情请看:游戏创意投稿大赛

我正在参加 码上掘金体验活动,详情:show出你的创意代码块

前言

借鉴了数独参考资料:JavaScript九宫格数独生成算法
在原来的基础上进行了改造,完成了逆数独~ (即我的数独我做主~)

《我的数独我做主》:是一款pc端单机html小休闲益智游戏;需要键盘和鼠标搭配,自己制作数独,自己解数独~
make-sudoku.gif

一、游戏介绍与规则

技术介绍

css + jq

游戏名称

《我的数独我做主》

游戏规则

随心所欲,自己的数独自己做主;想怎么分配数字就怎么分配数字。(没有限制,任由发挥,可以创建空的数独,再去自己填补完整的数独。也可以直接创建完整的数独,再点击解答~)

1.建数独

输入数字到对应位置,创建数独。

2.解数独

完成数独创建,再去解数独。

3.完成

流程完成会出现有显示创建的完成时间、解答的完成时间~

二、大体设计与代码讲解

大体设计

先“画”表格,往表格里填写数字,点击创建数独;数独判断是否成立;成立即为创建数独成功;开行进行解答数独,填写正确数独;点击完成,判断是否解对,对了即可胜利!

完整代码

/**
 * author:ls
 * email:liusaint@gmail.com
 * date:2016年4月9日
 * 
 * update: nfz
 * updateDate:2022年4月24日
 */

function SD() {
    this.sdArr = []; //生成的数独数组	
    this.errorArr = []; //错误的格子。
    this.blankNum = 81; //空白格子数量 
    this.backupSdArr = []; //数独数组备份。
    this.createTime = 1076275213; // 开始创建时间
    this.createEndTime = 1076275213; // 创建完成时间
}

SD.prototype = {
    constructor: SD,
    // 判断是否为数独
    isSudoku: function() {
        var backupSdArr = this.backupSdArr;
        // console.log(this.sdArr)
        var board = [];
        for (var i = 1; i < 10; i++) {
            var b = [];
            for (var j = 0; j < 9; j++) {
                if (backupSdArr[i * 10 + j + 1] == undefined) {
                    b[j] = "";
                } else {
                    b[j] = backupSdArr[i * 10 + j + 1];
                }
            }
            board[i - 1] = b;
        }
        // console.log(board)
        for (let i = 0; i < 9; i++) {
            let col = new Set()
            let row = new Set()
            for (let j = 0; j < 9; j++) {
                // console.log(board[i][j] )
                if (board[i][j] != "") { //判断行
                    if (!row.has(board[i][j])) {
                        row.add(board[i][j])
                    } else {
                        return false
                    }
                }
                if (board[j][i] != "") { //判断列
                    if (!col.has(board[j][i])) {
                        col.add(board[j][i])
                    } else {
                        return false
                    }
                }
            }
            let block = new Set()
            let x = parseInt(i / 3) * 3 //关键是找到块的x,y坐标
            let y = i % 3 * 3
            for (let k = 0; k < 9; k++) {
                if (board[x][y] != "") { //判断块
                    if (!block.has(board[x][y])) {
                        block.add(board[x][y])
                    } else {
                        return false
                    }
                }
                y++
                if ((k + 1) % 3 == 0) { //第4个换行
                    x += 1
                    y -= 3
                }
            }
        }

        return true;
    },
    createSudoku: function() {
        // console.log(this.sdArr)
        this.getInputVals();
        // console.log(this.backupSdArr)
        // console.log(this.sdArr)
        var isFlag = this.isSudoku();
        if (!isFlag) { // 不符合数独
            alert("当前数独不符合,请检查~");
            return;
        }
        this.createEndTime = new Date().getTime();
        var createShow = document.getElementById("createShow");
        var runningShow = document.getElementById("runningShow");
        createShow.style.display = "none";
        runningShow.style.display = "block";
    },
    init: function() {
        this.createDoms();
        this.drawCells();
        this.createBlank(this.blankNum);
        this.createBlankCells();
        this.createTime = new Date().getTime(); // 创建时间
    },
    reset: function() {
        //重置程序。
        this.errorArr = [];
        $(".sdspan").removeClass('bg_red blankCell');
        this.createSdArr();
        $(".sdspan[contenteditable=true]").prop('contenteditable', false);
        this.drawCells();
        this.createBlank(this.blankNum);
        this.createBlankCells();
        var createShow = document.getElementById("createShow");
        var runningShow = document.getElementById("runningShow");
        createShow.style.display = "block";
        runningShow.style.display = "none";
    },
    createSdArr: function() {
        //生成数独数组。
        var that = this;
        try {
            this.sdArr = [];
            this.setThird(2, 2);
            this.setThird(5, 5);
            this.setThird(8, 8);
            var allNum = [1, 2, 3, 4, 5, 6, 7, 8, 9];
            outerfor:
                for (var i = 1; i <= 9; i++) {
                    innerfor: for (var j = 1; j <= 9; j++) {
                        if (this.sdArr[parseInt(i + '' + j)]) {
                            continue innerfor;
                        }
                        var XArr = this.getXArr(j, this.sdArr);
                        var YArr = this.getYArr(i, this.sdArr);
                        var thArr = this.getThArr(i, j, this.sdArr);
                        var arr = getConnect(getConnect(XArr, YArr), thArr);
                        var ableArr = arrMinus(allNum, arr);

                        if (ableArr.length == 0) {
                            this.createSdArr();
                            return;
                            break outerfor;
                        }

                        var item;
                        //如果生成的重复了就重新生成。
                        do {
                            item = ableArr[getRandom(ableArr.length) - 1];
                        } while (($.inArray(item, arr) > -1));

                        this.sdArr[parseInt(i + '' + j)] = item;
                    }
                }
            this.backupSdArr = this.sdArr.slice();
        } catch (e) {
            //如果因为超出浏览器的栈限制出错,就重新运行。
            that.createSdArr();
        }
    },
    getXArr: function(j, sdArr) {
        //获取所在行的值。
        var arr = [];
        for (var a = 1; a <= 9; a++) {
            if (this.sdArr[parseInt(a + "" + j)]) {
                arr.push(sdArr[parseInt(a + "" + j)])
            }
        }
        return arr;
    },
    getYArr: function(i, sdArr) {
        //获取所在列的值。
        var arr = [];
        for (var a = 1; a <= 9; a++) {
            if (sdArr[parseInt(i + '' + a)]) {
                arr.push(sdArr[parseInt(i + '' + a)])
            }
        }
        return arr;
    },
    getThArr: function(i, j, sdArr) {
        //获取所在三宫格的值。
        var arr = [];
        var cenNum = this.getTh(i, j);
        var thIndexArr = [cenNum - 11, cenNum - 1, cenNum + 9, cenNum - 10, cenNum, cenNum + 10, cenNum - 9, cenNum + 1, cenNum + 11];
        for (var a = 0; a < 9; a++) {
            if (sdArr[thIndexArr[a]]) {
                arr.push(sdArr[thIndexArr[a]]);
            }
        }
        return arr;
    },
    getTh: function(i, j) {
        //获取所在三宫格的中间位坐标。
        var cenArr = [22, 52, 82, 25, 55, 85, 28, 58, 88];
        var index = (Math.ceil(j / 3) - 1) * 3 + Math.ceil(i / 3) - 1;
        var cenNum = cenArr[index];
        return cenNum;
    },
    setThird: function(i, j) {
        //为对角线上的三个三宫格随机生成。
        var numArr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
        var sortedNumArr = numArr.sort(function() { return Math.random() - 0.5 > 0 ? -1 : 1 });
        var cenNum = parseInt(i + '' + j);
        var thIndexArr = [cenNum - 11, cenNum - 1, cenNum + 9, cenNum - 10, cenNum, cenNum + 10, cenNum - 9, cenNum + 1, cenNum + 11];
        for (var a = 0; a < 9; a++) {
            this.sdArr[thIndexArr[a]] = sortedNumArr[a];
        }
    },
    drawCells: function() {
        //将生成的数组填写到九宫格
        for (var j = 1; j <= 9; j++) {
            for (var i = 1; i <= 9; i++) {
                $(".sdli").eq(j - 1).find(".sdspan").eq(i - 1).html(this.sdArr[parseInt(i + '' + j)]);
            }
        }
    },
    createBlank: function(num) {
        //生成指定数量的空白格子的坐标。
        var blankArr = [];
        var numArr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
        var item;
        for (var a = 0; a < num; a++) {
            do {
                item = parseInt(numArr[getRandom(9) - 1] + '' + numArr[getRandom(9) - 1]);
            } while ($.inArray(item, blankArr) > -1);
            blankArr.push(item);
        }
        this.blankArr = blankArr;
    },
    createBlankCells: function() {
        //在创建好的数独中去除一部分格子的值,给用户自己填写。把对应格子变成可编辑,并添加事件。
        var blankArr = this.blankArr,
            len = this.blankArr.length,
            x, y, dom;

        for (var i = 0; i < len; i++) {
            x = parseInt(blankArr[i] / 10);
            y = blankArr[i] % 10;
            dom = $(".sdli").eq(y - 1).find(".sdspan").eq(x - 1);
            dom.attr('contenteditable', true).html('').addClass('blankCell');
            this.backupSdArr[blankArr[i]] = undefined;
        }

        $(".sdspan[contenteditable=true]").keyup(function(event) {
            var val = $(this).html();
            var reStr = /^[1-9]{1}$/;
            if (!reStr.test(val)) {
                $(this).html('');
            };
        });
    },
    checkRes: function() {
        //检测用户输入结果。检测前将输入加入数组。检测单个的时候将这一个的值缓存起来并从数组中删除,检测结束在赋值回去。
        var blankArr = this.blankArr,
            len = this.blankArr.length,
            x, y, dom, done, temp;
        this.getInputVals();
        this.errorArr.length = 0;
        for (var i = 0; i < len; i++) {
            x = parseInt(blankArr[i] / 10);
            y = blankArr[i] % 10;
            temp = this.backupSdArr[blankArr[i]];
            this.backupSdArr[blankArr[i]] = undefined;
            this.checkCell(x, y);
            this.backupSdArr[blankArr[i]] = temp;
        }
        done = this.isAllInputed();
        if (this.errorArr.length == 0 && done) {
            var gameTime = ((new Date().getTime()) - this.createEndTime) / 1000;
            var createTime = (this.createEndTime - this.createTime) / 1000;
            alert('你胜利了!创建数独耗时:' + createTime + ';完成数独耗时:' + gameTime + "秒!");
            $(".bg_red").removeClass('bg_red');
        } else {
            if (!done) {
                alert("你没有完成游戏!");
            }
            this.showErrors();
        }
    },
    checkCell: function(i, j) {
        //检测一个格子中输入的值,在横竖宫里是否已存在。
        var index = parseInt(i + '' + j);
        var backupSdArr = this.backupSdArr;
        var XArr = this.getXArr(j, backupSdArr);
        var YArr = this.getYArr(i, backupSdArr);
        var thArr = this.getThArr(i, j, backupSdArr);
        var arr = getConnect(getConnect(XArr, YArr), thArr);
        var val = parseInt($(".sdli").eq(j - 1).find(".sdspan").eq(i - 1).html());
        if ($.inArray(val, arr) > -1) {
            this.errorArr.push(index);
        }
    },
    getInputVals: function() {
        //将用户输入的结果添加到数组中。
        var blankArr = this.blankArr,
            len = this.blankArr.length,
            i, x, y, dom, theval;
        for (i = 0; i < len; i++) {
            x = parseInt(blankArr[i] / 10);
            y = blankArr[i] % 10;
            dom = $(".sdli").eq(y - 1).find(".sdspan").eq(x - 1);
            theval = parseInt(dom.text()) || undefined;
            this.backupSdArr[blankArr[i]] = theval;
        }
    },
    isAllInputed: function() {
        //检测是否全部空格都有输入。
        var blankArr = this.blankArr,
            len = this.blankArr.length,
            i, x, y, dom;
        for (i = 0; i < len; i++) {
            x = parseInt(blankArr[i] / 10);
            y = blankArr[i] % 10;
            dom = $(".sdli").eq(y - 1).find(".sdspan").eq(x - 1);
            if (dom.text() == '') {
                return false
            }
        }
        return true;
    },
    showErrors: function() {
        //把错误显示出来。
        var errorArr = this.errorArr,
            len = this.errorArr.length,
            x, y, dom;
        $(".bg_red").removeClass('bg_red');
        for (var i = 0; i < len; i++) {
            x = parseInt(errorArr[i] / 10);
            y = errorArr[i] % 10;
            dom = $(".sdli").eq(y - 1).find(".sdspan").eq(x - 1);
            dom.addClass('bg_red');
        }
    },
    createDoms: function() {
        //生成九宫格。
        var html = '<ul class="sd clearfix">';
        String.prototype.times = String.prototype.times || function(n) { return (new Array(n + 1)).join(this); };
        html = html + ('<li class="sdli">' + '<span class="sdspan"></span>'.times(9) + '</li>').times(9) + '</ul>';
        $("#sudoku-body").prepend(html);

        for (var k = 0; k < 9; k++) {
            $(".sdli:eq(" + k + ") .sdspan").eq(2).addClass('br');
            $(".sdli:eq(" + k + ") .sdspan").eq(5).addClass('br');
            $(".sdli:eq(" + k + ") .sdspan").eq(3).addClass('bl');
            $(".sdli:eq(" + k + ") .sdspan").eq(6).addClass('bl');
        }
        $(".sdli:eq(2) .sdspan,.sdli:eq(5) .sdspan").addClass('bb');
        $(".sdli:eq(3) .sdspan,.sdli:eq(6) .sdspan").addClass('bt');
    }
}


//生成随机正整数
function getRandom(n) {
    return Math.floor(Math.random() * n + 1)
}

//两个简单数组的并集。
function getConnect(arr1, arr2) {
    var i, len = arr1.length,
        resArr = arr2.slice();
    for (i = 0; i < len; i++) {
        if ($.inArray(arr1[i], arr2) < 0) {
            resArr.push(arr1[i]);
        }
    }
    return resArr;
}

//两个简单数组差集,arr1为大数组
function arrMinus(arr1, arr2) {
    var resArr = [],
        len = arr1.length;
    for (var i = 0; i < len; i++) {
        if ($.inArray(arr1[i], arr2) < 0) {
            resArr.push(arr1[i]);
        }
    }
    return resArr;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378

三、仓库地址与体验地址

这里代码片段展示(布局不会弄,太拉了~ alter 弹窗不支持,最好去网站体验~)
代码片段

  (没有做适配,很抱歉~ 手机端也不友好。献丑了~ )
  大家可以直接来笔者的网站来体验


  在线体验(pc端):体验传送门
  仓库地址:等建好活动GitHub的要求申请了,就给大家放(着急想要的可以直接去扒我的网站传送门

文章小尾巴

文章写作、模板、文章小尾巴可参考:《写作“小心思”》

  感谢你看到最后,最后再说两点~
  ①如果你持有不同的看法,欢迎你在文章下方进行留言、评论。
  ②如果对你有帮助,或者你认可的话,欢迎给个小点赞,支持一下~
  我是南方者,一个热爱计算机更热爱祖国的南方人。

  (文章内容仅供学习参考,如有侵权,非常抱歉,请立即联系作者删除。)

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号