JavaScript之破解数独(附详细代码)

  在上一篇分享中,我们用Python和Django来破解数独,这对不熟悉Python和Django的人来说是非常不友好的。这次,笔者只用HTML和JavaScript写了破解数独的程序,对于熟悉前端的人,这是十分友好的。
  话不多说,直接上代码。
  首页index.html的代码如下:

<html>
    
<head>
    <link rel="stylesheet" type="text/css" href="mystyle.css" />
    <script type="text/javascript" src="answer.js"></script>
</head>

<body background="mountain.jpg">
    <center><h1>Solve A Sudoku</h1></center>
    <table class="sd" border="0" align="center" cellspacing="1" cellpadding="1">
        <tr>
            <td class="xx"><input id="1" class="big" maxlength="1"></td>
            <td class="xx"><input id="2" class="big" maxlength="1"></td>
            <td class="rr"><input id="3" class="big" maxlength="1"></td>
            <td class="xx"><input id="4" class="big" maxlength="1"></td>
            <td class="xx"><input id="5" class="big" maxlength="1"></td>
            <td class="rr"><input id="6" class="big" maxlength="1"></td>
            <td class="xx"><input id="7" class="big" maxlength="1"></td>
            <td class="xx"><input id="8" class="big" maxlength="1"></td>
            <td class="xx"><input id="9" class="big" maxlength="1"></td>
        </tr>
        <tr>
            <td class="xx"><input id="10" class="big" maxlength="1"></td>
            <td class="xx"><input id="11" class="big" maxlength="1"></td>
            <td class="rr"><input id="12" class="big" maxlength="1"></td>
            <td class="xx"><input id="13" class="big" maxlength="1"></td>
            <td class="xx"><input id="14" class="big" maxlength="1"></td>
            <td class="rr"><input id="15" class="big" maxlength="1"></td>
            <td class="xx"><input id="16" class="big" maxlength="1"></td>
            <td class="xx"><input id="17" class="big" maxlength="1"></td>
            <td class="xx"><input id="18" class="big" maxlength="1"></td>
        </tr>
        <tr>
            <td class="xx"><input id="19" class="big" maxlength="1"></td>
            <td class="xx"><input id="20" class="big" maxlength="1"></td>
            <td class="rr"><input id="21" class="big" maxlength="1"></td>
            <td class="xx"><input id="22" class="big" maxlength="1"></td>
            <td class="xx"><input id="23" class="big" maxlength="1"></td>
            <td class="rr"><input id="24" class="big" maxlength="1"></td>
            <td class="xx"><input id="25" class="big" maxlength="1"></td>
            <td class="xx"><input id="26" class="big" maxlength="1"></td>
            <td class="xx"><input id="27" class="big" maxlength="1"></td>
        </tr>
        <tr>
            <td class="top"><input id="28" class="big" maxlength="1"></td>
            <td class="top"><input id="29" class="big" maxlength="1"></td>
            <td class="topr"><input id="30" class="big" maxlength="1"></td>
            <td class="top"><input id="31" class="big" maxlength="1"></td>
            <td class="top"><input id="32" class="big" maxlength="1"></td>
            <td class="topr"><input id="33" class="big" maxlength="1"></td>
            <td class="top"><input id="34" class="big" maxlength="1"></td>
            <td class="top"><input id="35" class="big" maxlength="1"></td>
            <td class="top"><input id="36" class="big" maxlength="1"></td>
        </tr>
        <tr>
            <td class="xx"><input id="37" class="big" maxlength="1"></td>
            <td class="xx"><input id="38" class="big" maxlength="1"></td>
            <td class="rr"><input id="39" class="big" maxlength="1"></td>
            <td class="xx"><input id="40" class="big" maxlength="1"></td>
            <td class="xx"><input id="41" class="big" maxlength="1"></td>
            <td class="rr"><input id="42" class="big" maxlength="1"></td>
            <td class="xx"><input id="43" class="big" maxlength="1"></td>
            <td class="xx"><input id="44" class="big" maxlength="1"></td>
            <td class="xx"><input id="45" class="big" maxlength="1"></td>
        </tr>
        <tr>
            <td class="xx"><input id="46" class="big" maxlength="1"></td>
            <td class="xx"><input id="47" class="big" maxlength="1"></td>
            <td class="rr"><input id="48" class="big" maxlength="1"></td>
            <td class="xx"><input id="49" class="big" maxlength="1"></td>
            <td class="xx"><input id="50" class="big" maxlength="1"></td>
            <td class="rr"><input id="51" class="big" maxlength="1"></td>
            <td class="xx"><input id="52" class="big" maxlength="1"></td>
            <td class="xx"><input id="53" class="big" maxlength="1"></td>
            <td class="xx"><input id="54" class="big" maxlength="1"></td>
        </tr>
        <tr>
            <td class="top"><input id="55" class="big" maxlength="1"></td>
            <td class="top"><input id="56" class="big" maxlength="1"></td>
            <td class="topr"><input id="57" class="big" maxlength="1"></td>
            <td class="top"><input id="58" class="big" maxlength="1"></td>
            <td class="top"><input id="59" class="big" maxlength="1"></td>
            <td class="topr"><input id="60" class="big" maxlength="1"></td>
            <td class="top"><input id="61" class="big" maxlength="1"></td>
            <td class="top"><input id="52" class="big" maxlength="1"></td>
            <td class="top"><input id="63" class="big" maxlength="1"></td>
        </tr>
        <tr>
            <td class="xx"><input id="64" class="big" maxlength="1"></td>
            <td class="xx"><input id="65" class="big" maxlength="1"></td>
            <td class="rr"><input id="66" class="big" maxlength="1"></td>
            <td class="xx"><input id="67" class="big" maxlength="1"></td>
            <td class="xx"><input id="68" class="big" maxlength="1"></td>
            <td class="rr"><input id="69" class="big" maxlength="1"></td>
            <td class="xx"><input id="70" class="big" maxlength="1"></td>
            <td class="xx"><input id="71" class="big" maxlength="1"></td>
            <td class="xx"><input id="72" class="big" maxlength="1"></td>
        </tr>
        <tr>
            <td class="xx"><input id="73" class="big" maxlength="1"></td>
            <td class="xx"><input id="74" class="big" maxlength="1"></td>
            <td class="rr"><input id="75" class="big" maxlength="1"></td>
            <td class="xx"><input id="76" class="big" maxlength="1"></td>
            <td class="xx"><input id="77" class="big" maxlength="1"></td>
            <td class="rr"><input id="78" class="big" maxlength="1"></td>
            <td class="xx"><input id="79" class="big" maxlength="1"></td>
            <td class="xx"><input id="80" class="big" maxlength="1"></td>
            <td class="xx"><input id="81" class="big" maxlength="1"></td>
        </tr>
    </table>
    <br>
    <center>
    <button type="button" onclick="clc()">Clear</button> 
    <button type="button" onclick="get_answer()">Show Answer</button> 
    </center>
</body>

</html>

  其使用的样式表mystyle.css的代码如下:

.sd {
    table-layout: fixed;
    border: #443 3px solid;
    width: 355px;
    height: 355px;
    background-color: #fff;
    vertical-align: middle;
    border-collapse: collapse;
    text-align: center;
}
.big {
    FONT-SIZE: 25px;
    border: none;
    background-color: transparent;
    WIDTH: 30px;
    HEIGHT: 30px;
    LINE-HEIGHT: 28px;
    TEXT-ALIGN: center;
    margin: 0px;
    COLOR: #0000FF;
    FONT-FAMILY: Verdana;
}
td.xx {
    border-right: #999 1px solid;
    border-top: #999 1px solid;
    width: 30px;
    height: 30px;
    text-align: center;
    LINE-height: 30px;
}
td.rr {
    border-right: #443 2px solid;
    border-top: #999 1px solid;
    width: 30px;
    height: 30px;
    text-align: center;
    LINE-height: 30px;
}
td.top {
    border-right: #999 1px solid;
    border-top: #443 2px solid;
    width: 30px;
    height: 30px;
    text-align: center;
    LINE-height: 30px;
}
td.topr {
    border-right: #443 2px solid;
    border-top: #443 2px solid;
    width: 30px;
    height: 30px;
    text-align: center;
    LINE-height: 30px;
}

  其使用的JavaScript的代码(answer.js)如下:

//clear all the input
function clc(){
    for(var i=0; i<81; i++){
        document.getElementsByTagName("input")[i].value = "";
        document.getElementsByTagName("input")[i].style.color = 'blue';
    }
    document.body.style.backgroundImage = "url(mountain.jpg)";
}

//press "show answer" button and show answer then
function get_answer(){
    var bool = check_input();
    if(bool){
        var grid = readAPuzzle();
        if(!isValidGrid(grid)){
            alert("Invalid input, please try again!");
        }
        else{
            if(search(grid)){
                output_ans();
                document.body.style.backgroundImage = "url(sky.jpg)";
            }
            else{
                alert("Found no solution!");
            }
        }
    }
}

//check if the input are valid
function check_input(){
    var arr = new Array();
    
    for(var i=0; i<81; i++){
        arr[i] = Number(document.getElementsByTagName("input")[i].value);
        if(isNaN(arr[i])){
            alert('Input should be any number between 1 and 9 !');
            return false
        }
    }
    
    if(arr.every(function isZero(x){return x== 0})){
        alert('There is no input!');
        return false
    }
    
    return true
}

//read a puzzle from the web page
function readAPuzzle(){
    var arr = new Array();
    
    for(var i=0; i<81; i++){
        arr[i] = Number(document.getElementsByTagName("input")[i].value);
    }
    
    var grid = new Array();
    for(var i=0; i<9; i++){
        grid[i] = new Array();
        for(var j=0; j<9; j++){
            grid[i][j] = 0;
        }    
    }
    
    
    for(var i=0; i<81; i++){
        grid[Math.floor(i/9)][i%9] = arr[i];
    }
    
    return grid
}

//Obtain a list of free cells from the puzzle
function getFreeCellList(grid){
    var freeCellList = new Array();
    index = 0
    
    for(var i=0; i<9; i++){
        for(var j=0; j<9; j++){
            if(grid[i][j] == 0){
                freeCellList[index] = new Array(i,j);
                index++;
            }
        }
    }
                
    return freeCellList
}

//Check whether grid[i][j] is valid in the grid
function isValid(i,j,grid){
    //Check whether grid[i][j] is valid at the i's row
    for(var column=0; column<9; column++){
        if((column != j) && (grid[i][column] == grid[i][j])){
            return false
        }
    }
         
    //Check whether grid[i][j] is valid at the j's column
    for(var row=0; row<9; row++){
        if((row != i) && (grid[row][j] == grid[i][j])){
            return false
        }
    }
 
    //Check whether grid[i][j] is valid at the 3-by-3 box
    for(var row=Math.floor(i/3)*3; row < Math.floor(i/3)*3+3; row++){
        for(var col=Math.floor(j/3)*3; col < Math.floor(j/3)*3+3; col++){
            if((row != i) && (col != j) && (grid[row][col] == grid[i][j])){
                return false
            }
        }
    }
             
    return true //The current value at grid[i][j] is valid
}

//Check whether the fixed cells are valid in the grid
function isValidGrid(grid){
    for(var i=0; i<9; i++){
        for(var j=0; j<9; j++){
            if((grid[i][j] < 0) || (grid[i][j] > 9) || ((grid[i][j] != 0) && (! isValid(i,j,grid)))){
                return false
            }
        }
    }
    return true
}


//Search for a solution
function search(grid){
    var freeCellList = getFreeCellList(grid);
    var numberOfFreeCells = freeCellList.length;
    if(numberOfFreeCells == 0){
        return true
    }
    
    var k = 0;  //Start from the first free cell
 
    while(true){
        var i = freeCellList[k][0];
        var j = freeCellList[k][1];
        if(grid[i][j] == 0){
            grid[i][j] = 1;
        }
 
        if(isValid(i,j,grid)){
            if(k+1 == numberOfFreeCells){
                //no more free cells
                return true  //A solution is found
            }
            else{
                //Move to the next free cell
                k++;
            }
        }
        else{
            if(grid[i][j] < 9){
                //Fill the free cell with the next possible value
                grid[i][j]++;
            }
        
            else{
                //grid[i][j] is 9,backtrack
                while(grid[i][j] == 9){
                    if(k == 0){
                        return false  //No possible value
                    }
                    grid[i][j] = 0;  //Reset to free cell
                    k--;  //Backtrack to the preceding free cell
                    i = freeCellList[k][0];
                    j = freeCellList[k][1];
 
                } 
                //Fill the free cell with the next possible value
                //search continues from this free cell at k
                grid[i][j]++;
            }
        }
    }
 
    return true  //A solution is found
}


//output the answer on the web page
function output_ans(){
    var grid = readAPuzzle();
    var grid_original = readAPuzzle();
    
    if(search(grid)){
        for(var i=0; i<81; i++){
            if(grid[Math.floor(i/9)][i%9] != grid_original[Math.floor(i/9)][i%9]){
                document.getElementsByTagName("input")[i].value = grid[Math.floor(i/9)][i%9];
                document.getElementsByTagName("input")[i].style.color = 'black';
            }
        }
    }
    
}

  我们将对如何操作做一个简单的图解说明。
  开始的页面如下:

开始页面

  首先,如果没有任何输入而直接点击“Show Answer”按钮,则会显示如下页面:

没有任何输入而直接点击“Show Answer”按钮

  如何在表格中一旦输入非数字,则会显示如下页面:

在表格中输入非数字

  若在九宫格中输入的数字不符合规则,则会显示页面如下:

在九宫格中输入的数字不符合规则

  当我们输入的数字符合规则时,就能得到正确的答案,比如,我们在http://www.cn.sudokupuzzle.org/上随便找一个“骨灰级”的数独并输入,页面如下:

“骨灰级”的数独

当我们按下“Show Answer”按钮时,显示的答案如下:

显示答案

  当按下“Clear”按钮时,所有格子将会被清空,这样我们就能就行下一次破解啦~~
  本次分享到此结束,欢迎大家交流~~
  P.S.写这个项目主要是为了学习JavaScript,因为最近刚开始接触前端。欢迎大家访问这个项目的Github地址:https://github.com/percent4/Sudoku-Solver-JavaScript-Version .

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,116评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,103评论 4 62
  • 我的神经大条已经让我自己觉得嗔目结舌,在别人一天都不差的各种纪念日中,我几乎什么都记不得!什么时候恋爱,什么时候领...
    安心1121阅读 166评论 0 1