亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

Javascript 實現的數獨解題算法網頁實例

2019-11-20 21:53:22
字體:
來源:轉載
供稿:網友

1)當我們拿到一個題目時,首先會根據已經知道的條件,進行數據的初步整理和分析。

相當于填寫出9宮格里,所有的“確定項”,以及標記“可能選項”。

function refreshStat()

2)此后,思考會進入 猜測/驗證 的循環階段。

在9宮格中,可以對于“可能選項”進行嘗試,驗證是否違背現有條件。

每一個新的分支,最后的結果無非是兩種,答案/出錯。

復制代碼 代碼如下:

                while(true){
                    var a=setOne();
                    var b=refreshStat();
                    if(!a||b){ //如果 a==false 或者 b==ture,則可以跳出循環
                        break;
                    }
                }

實際人腦思考的過程,也是要先遍歷選項較少的分支。

所以,程序實現上也是 確定點/2叉分支/3叉分支/....

3)當所有的路徑搜索下來,答案不是唯一的情況,是和數獨游戲的宗旨相悖的。

以下部分是全部代碼,為方便閱讀,調試信息未刪除。

復制代碼 代碼如下:

<html>
 <head>
  <title>數獨解題程序</title>
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
  <script>
   function keygo(evt,obj){
       key = window .event?evt.keyCode:evt.which;
       var next=obj.tabIndex ;
       var inputs=document.getElementsByTagName("input");
       if (key==38){//↑
           if (next -9>=0 ) {
               inputs[next-9].select()
           }
       }
       if (key==40){//↓
           if (next +9<81 ) {
               inputs[next+9].select()
           }
       }
       if (key==37){//←
           if (next -1>=0 ) {
               inputs[next-1].select()
           }
       }
       if (key==39){//→
           if(next+1<81)inputs[next+1].select();
       }
   }
  </script>
 </head>
<body onload="init();">
<div id="sodukuTable"></div><input type=button name="cal" onclick="calculate()" value="計算">
<input type=button name="clear" onclick="clearGrid()" value="清空">
<br><span><textarea id="gtxt" cols="19" rows="10">004502006
000000005
002014007
008000012
070080050
930020700
600190200
020000000
300208500</textarea></span>
<input type=button name="cal" onclick="paste()" value="粘貼" >可以文本拷貝到下框中后點粘貼,從左到右從上往下的81個數字序列,未填為0,中間非數字字符將忽略<br>
<span></span><br><span id="statusDiv"></span><span id="log"></span>
  <script>
   var maxRow =9;
   var maxCol = 9;
   var strTbody = ["<table id='sodukuTable' border='0'><tbody>"];
   for(var i = 0; i < maxRow; i++){
    strTbody.push("<tr>");
     for(var j = 0; j < maxCol; j++){
      strTbody.push("<td style='border-left:"+(j%3==0?1:0)
            +"px solid black ;border-right:"+(j%3==2?1:0)
            +"px solid black;border-top:"+(i%3==0?1:0)
            +"px solid black;border-bottom:"+(i%3==2?1:0)+"px solid black;' ><input style='width:20px;' tabindex='"+(i*9+j)
        +"'onclick='check(this);' onKeyUp='return keygo(event,this)'type='text' id='input"+(i*9+j)+"'name='n"+(i*9+j)+"'value='"+i+j+"' ></td>");
     }
    strTbody.push("</tr>");
   }
   strTbody.push("</tbody></table>");
   var sTbody = ["<table border='1'><tbody>"];
   for(var i = 0; i < maxRow; i++){
    sTbody.push("<tr>");
     for(var j = 0; j < maxCol; j++){
      sTbody.push("<td style='border-left:"+(j%3==0?1:0)
            +"px solid black ;border-right:"+(j%3==2?1:0)
            +"px solid black;border-top:"+(i%3==0?1:0)
            +"px solid black;border-bottom:"+(i%3==2?1:0)+"px solid black;'><div style='width:25px;height:25px'  id='status"+(i*9+j)+"'name='div"+i+j+"'  ></div></td>");
     }
    sTbody.push("</tr>");
   }
   sTbody.push("</tbody></table>");
   var obj = document.getElementById("sodukuTable");
   obj.innerHTML = strTbody.join("");
   var obj2 = document.getElementById("statusDiv");
   var grid=[   
    [5, 7, 0, 1, 2, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 6, 7, 0, 0, 0, 8, 0],
    [3, 0, 4, 0, 0, 9, 0, 7, 0],
    [0, 2, 0, 0, 7, 0, 0, 5, 0],
    [0, 1, 0, 3, 0, 0, 9, 0, 2],
    [0, 8, 0, 0, 0, 2, 1, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 5, 4, 0, 6, 3]];
   var candidatNum=[];
   var columns=[];
   var rows=[];
   var blook=[];
   var papers=0;
   var discards=0;
   var success=false;
   var steps = new Array();
   var log1 = document.getElementById("statusDiv");

function Step(current1,arrys){
        this.temp1=new Array();
        this.step=[arrys[0],arrys[1],arrys[2]];
        for (var i = 0; i < 9; i++)
            {
                this.temp1[i]=new Array();
                for (var j = 0; j < 9; j++)
                    {
                    this.temp1[i][j]=current1[i][j];
                    }
                }
}
out(grid);
init();

function push( current1,  i,  j,  n) {
        var s = new Step(current1, [ i, j, n ]);
        steps.push(s);
}
function pop(){
        var step = steps.pop();
        discards ++;
        grid=step.temp1;
        grid[step.step[0]][step.step[1]] = step.step[2];
                var timeline = document.getElementById('PaperList');
                timeline.value += ('discard: ['+discards+']:['+papers+']/n');
                timeline.scrollTop = timeline.scrollHeight;
        return step;
}

function check(obj){
    if(obj.value==0)return;
    for(var i=0;i<9;i++){
        for(var j=0;j<9;j++){
            var text = document.getElementById("input"+(i*9+j));
            if(text.value==obj.value){
                text.style.background="green";
            }else{
                text.style.background="";
            }
        }

    }

}
function CheckNumInput(array,num,  x,  y)  {
    //  目標:
    //      沖突檢查  參數 array:矩陣 num:檢測值 x/y:檢測位置
    //      行列宮均無沖突,return true;
    //            發現沖突,return false;
    if (((rows[x] & (1 << num)) == 0) && (columns[y] & (1 << num)) == 0
        && (blook[parseInt(x / 3) * 3 + parseInt(y / 3)] & (1 << num)) == 0) {
        return true;
        }
    return false;
}

function out(array){
    var result=true;
    for (var i = 0; i < 9; i++)
        {
            for (var j = 0; j < 9; j++)
            {
        document.getElementById("input"+(i*9+j)).value=array[i][j];
                if(array[i][j]==0)result=false;
            }
        }
        return result;
}
function setOne(){
    var result = false;
    //目標:
    //    遍歷矩陣,當前是否可以簡單刷新,或者已經可以發現出錯.
    for (var i = 0; i < 9; i++) {
        for (var j = 0; j < 9; j++) {
            //目標:
            // (grid[i][j] == 0 && candidatNum[i][j][0] == 0)  >> 沒有候選數字,出錯了
            // (candidatNum[i][j][0] == 1)                     >> 候選數字唯一
            // CheckNumInput(grid,candidatNum[i][j][10],i,j)   >> 檢查此數字是否符合邏輯
            // 判斷 沒有候選數字||最后一個候選數字不符合邏輯的條件,  從這里回退或者返回出錯
            if (grid[i][j] == 0 && candidatNum[i][j][0] == 0||
               (candidatNum[i][j][0] == 1&&!CheckNumInput(grid,candidatNum[i][j][10],i,j))) {
                    if (grid[i][j] == 0) {
                       result = false;
                    }
                    if (steps.length>0) {// 回退
                        pop();           // 當前標簽已經被證明邏輯錯誤,廢棄
                        return true;
                    } else {
                        if (!success) {
                            alert("棧為空 結束!");    //題目出錯,結束
                            }
                        return false;
                    }
            }
            if (candidatNum[i][j][0] == 1) {              //唯一選擇
                grid[i][j] = candidatNum[i][j][10];       //  更新矩陣
                refreshStat3(candidatNum[i][j][10],i,j);  //  更新行列宮
                candidatNum[i][j][0] = 0;                 //  標記已選
                result = true;
                continue;
            }

        }
    }
    if (result == false) { //對于(candidatNum[i][j][0] != 1)的情況,進行篩選
        return choose();
    }
    return result;
}
function refreshStat3( num, x, y) {   //  更新行列宮
        rows[x] |= 1<<num;
        columns[y] |= 1<<num;
        blook[parseInt(x / 3) * 3 + parseInt(y / 3)] |= 1 << num ;

}
/*********************
 * 矩陣 數據分析
 * 統計 剩余可選項
 *********************/
function refreshStat(){
    var over = true;
    //  目標:
    //      分解行/列/宮
    for (var i = 0; i < 9; i++) {
        rows[i] = 0;    //行
        columns[i] = 0; //列
        blook[i] = 0;   //宮
        for (var j = 0; j < 9; j++) {
            if (grid[i][j] != 0) {
                rows[i] |= 1 << grid[i][j];
            } else {
                rows[i] &= ~(1 << grid[i][j]);
            }
            if (grid[j][i] != 0) {
                columns[i] |= 1 << grid[j][i];
            } else {
                columns[i] &= ~(1 << grid[j][i]);
            }
            if (grid[parseInt(i / 3) * 3 + parseInt(j / 3)][i % 3 * 3 + j % 3] != 0) {
                blook[i] |= 1 << grid[parseInt(i / 3 )* 3 + parseInt(j / 3)][i % 3 * 3 + j % 3];
            }
        }
    }
    //  目標:
    //      遍歷矩陣,進行候選標記candidatNum[i][j][0]
    //      candidatNum[i][j][0] = 0;    >>>>    已有確定值
    //      candidatNum[i][j][0] = k;    >>>>    可能值數目
    //      candidatNum[i][j][1] = 987654321x    2進制數位表示的可選數字
    for (var i = 0; i < 9; i++) {
        for (var j = 0; j < 9; j++) {
        if (grid[i][j] != 0) {
            candidatNum[i][j][0] = 0;
            continue;
        }
        var size = 0;
        over = false;
        for (var k = 1; k < 10; k++) {
            if (CheckNumInput(grid, k, i, j)) {
                candidatNum[i][j][1] |= 1 << k;
                candidatNum[i][j][10] = k;
                over = false;
                size++;
            } else {
                candidatNum[i][j][1] &= ~(1 << k);
            }
        }
        candidatNum[i][j][0] = size;  //標記剩余選項數目
    }
    }
    return over;
}

function calculate(){  //功能入口
    //讀取數據
    var start=new Date();
    for (var i = 0; i < 9; i++)
        {   
            for (var j = 0; j < 9; j++)
            {
                var text = document.getElementById("input"+(i*9+j));
                grid[i][j]=parseInt(text.value);
        }
    }

    //刷新網格   
    refreshStat();
    out(grid);
    //計算矩陣
    while(true){
        var a=setOne();
        var b=refreshStat();
        if(!a||b){ //如果 a==false 或者 b==ture,則可以跳出循環
            break;
        }
    }
    out(grid);    //答案
    alert("用時:"+(new Date()-start)+"ms");
    success = true;
    //計算結束

    //驗證答案是否唯一
    if (papers != discards){
            if (steps.length>0) {// 回退
                pop();           // 當前標簽廢棄
                //計算矩陣
                while(true){
                    var a=setOne();
                    var b=refreshStat();
                    if(!a||b){ //如果 a==false 或者 b==ture,則可以跳出循環
                        break;
                    }
                }
                if (b) {
                    alert("答案不唯一!記錄!");
                    out(grid);    //答案
                    }
                else {
                    alert("答案唯一!!");    //答案唯一
                }
            } else {
                alert("出錯 結束!");
                return false;
            }
    }
}
function clearGrid(){
    for (var i = 0; i < 9; i++){
        for (var j = 0; j < 9; j++){
            grid[i][j]=0;
            document.getElementById("input"+(i*9+j)).value=grid[i][j];
        }
    }
    out(grid);
}
function init(){
     for (var i = 0; i < 9; i++)
        {    candidatNum[i]=new Array();

            for (var j = 0; j < 9; j++)
            {    candidatNum[i][j]=new Array();

        for (var k = 0; k < 11; k++)
                {    candidatNum[i][j][k]=0;
        }
        }
    }
}
function choose() {
    //目標:
    //    遍歷矩陣,從當前位置建立搜索分支.
    var binarynode = false;
    for (var i = 0; i < 9; i++) {
        for (var j = 0; j < 9; j++) {
    //      2叉樹分支:
    //      如果在某位置有兩種可能,選項1/選項2
    //      則假設是選項1,并進行驗算,同時按選項2生成一個新的標簽
            if (candidatNum[i][j][0] == 2) {// 有2種選擇
                binarynode = true;
                var found = -1;
                for (var k = 1; k < 10; k++) {
                    if  ((candidatNum[i][j][1] & (1 << k)) > 0) {
                        if (found > 0) {
                            papers ++;
                            var timeline = document.getElementById('PaperList');
                            timeline.value += ('add papers:'+papers+':'+i+' '+j+' '+k+'/n');
                            timeline.scrollTop = timeline.scrollHeight;
                            push(grid, i, j, k);
                        }else{
                            found = k;
                        }
                    }
                }
                grid[i][j] = found;
                candidatNum[i][j][0] = 0; // 在當前標簽上標記已選
                            var timeline = document.getElementById('PaperList');
                            timeline.value += ('TRY CURRENT:'+i+' '+j+' '+found+'/n');
                            timeline.scrollTop = timeline.scrollHeight;
                return true;
            }
        }
    }
    if (!binarynode) {
    var timeline = document.getElementById('PaperList');
    timeline.value += ('2叉分支未找到!/n');
    timeline.scrollTop = timeline.scrollHeight;
        for (var i = 0; i < 9; i++) {
            for (var j = 0; j < 9; j++) {
        // 2叉樹查找失敗時,啟動3叉樹分支,作為擴充,還可以啟動3叉樹分支:
        //      如果在某位置有三種可能,選項1/選項2/選項3
        //      則假設是選項1,并進行驗算,同時按選項2生成一個新的標簽
                if (candidatNum[i][j][0] == 3) {// 有3種選擇
                            var timeline = document.getElementById('PaperList');
                            timeline.value += ('發現3叉分支!/n');
                            timeline.scrollTop = timeline.scrollHeight;
                    binarynode = true;
                    var found = -1;
                    for (var k = 1; k < 10; k++) {
                        if  ((candidatNum[i][j][1] & (1 << k)) > 0) {
                            if (found > 0) {
                                papers ++;
                            var timeline = document.getElementById('PaperList');
                            timeline.value += ('add papers:'+papers+':'+i+' '+j+' '+k+'/n');
                            timeline.scrollTop = timeline.scrollHeight;
                                push(grid, i, j, k);
                            }else{
                                found = k;
                            }
                        }
                    }
                    grid[i][j] = found;
                    candidatNum[i][j][0] = 0; // 在當前標簽上標記已選
                            var timeline = document.getElementById('PaperList');
                            timeline.value += ('TRY CURRENT:'+i+' '+j+' '+found+'/n');
                            timeline.scrollTop = timeline.scrollHeight;
                    return true;
                }
            }
        }
    }
    return false;
}
function paste(){
    var gridstr= document.getElementById("gtxt").value;
    var a = gridstr.replace(/[^0-9]/g,'');
    if(a.length!=81){
       alert("數據格式不正確:/n"+gridstr);
       return;
    }
    for (var i = 0; i < 9; i++)
        {
            for (var j = 0; j < 9; j++){
                grid[i][j]=a.charAt(i*9+j);
                document.getElementById("input"+(i*9+j)).value=grid[i][j];
        }
    }
    out(grid);
    papers = 0;
    discards = 0;
    success = false;
    steps = new Array();
}
  </script>
  建議使用IE瀏覽器,F12開啟調試模式<br>
<br><span>
<textarea id="PaperList" cols="30" rows="20" style="position:absolute;left:550px;"></textarea></span>
 </body>
</html>

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
三级精品视频久久久久| 精品久久久久久久久国产字幕| 91国产美女在线观看| 亚洲综合社区网| 欧美激情视频在线| 丁香五六月婷婷久久激情| 欧美国产精品va在线观看| 亚洲自拍偷拍在线| 亚洲图中文字幕| 久久精品99久久香蕉国产色戒| 欧美精品电影在线| 亚洲最大av网站| 高清在线视频日韩欧美| 国产一区二区三区久久精品| 精品精品国产国产自在线| 日韩电视剧在线观看免费网站| 欧美日韩成人在线观看| 日韩精品中文字幕在线观看| 国产亚洲欧美日韩精品| 亚洲综合日韩在线| 欧美另类极品videosbest最新版本| 国产福利精品视频| 日韩高清电影免费观看完整版| 狠狠色狠色综合曰曰| 97超级碰在线看视频免费在线看| 日韩国产一区三区| 久久久免费精品| 国产精品久久国产精品99gif| 人妖精品videosex性欧美| 色午夜这里只有精品| 在线视频欧美日韩| 日韩精品免费在线视频观看| 成人精品网站在线观看| 日韩免费在线观看视频| 亚洲精品久久久久中文字幕欢迎你| 久久99精品久久久久久琪琪| 亚洲精品999| 俺也去精品视频在线观看| 国产91露脸中文字幕在线| 亚洲男人的天堂网站| 亚洲精品福利免费在线观看| 欧美日韩国产黄| 亚洲欧美www| 色噜噜久久综合伊人一本| 国产乱人伦真实精品视频| 91免费国产视频| 日韩小视频在线| 日本不卡视频在线播放| 日韩精品亚洲精品| 亚洲美女精品成人在线视频| 久久亚洲精品国产亚洲老地址| 亚洲欧美999| 欧美麻豆久久久久久中文| 555www成人网| 97精品视频在线播放| 久久久这里只有精品视频| 中文字幕欧美日韩| 欧美乱人伦中文字幕在线| 18一19gay欧美视频网站| 精品动漫一区二区三区| 久久精视频免费在线久久完整在线看| 国产精品免费视频xxxx| 亚洲wwwav| 在线精品91av| 亚洲第一精品福利| 亚洲自拍小视频| 国产一区二区三区中文| 久久99精品国产99久久6尤物| 亚洲日本欧美日韩高观看| 欧美激情a∨在线视频播放| 91精品国产综合久久香蕉最新版| 黑人巨大精品欧美一区二区一视频| 国产专区欧美专区| 国产美女精品视频免费观看| 久久精品国产清自在天天线| 日韩美女在线观看一区| 国产精品久久久久久亚洲调教| 国产成人在线一区| 日韩精品视频在线| 97免费视频在线播放| 日韩大胆人体377p| 亚洲欧美在线第一页| 欧美激情精品在线| 亚洲最大av网| 欧美中文字幕视频在线观看| 91精品国产综合久久久久久久久| 欧美日韩综合视频网址| 色婷婷综合久久久久| 欧美电影免费观看大全| 91久久精品久久国产性色也91| 欧美日韩在线观看视频| 欧美日韩国产精品一区| 亚洲精品成人久久久| 一本色道久久88亚洲综合88| 国产在线视频不卡| 国内精品久久久久久中文字幕| 久久亚洲一区二区三区四区五区高| 国产精品久久99久久| 亚洲一二在线观看| 国产美女高潮久久白浆| 亚洲午夜未删减在线观看| 日本成熟性欧美| 欧美性猛交99久久久久99按摩| 91在线观看免费高清完整版在线观看| 亚洲日韩欧美视频| 欧美一乱一性一交一视频| 国产精品视频999| 一区二区三区国产在线观看| 国产精品96久久久久久| 欧美肥婆姓交大片| 欧美电影院免费观看| 日韩欧美高清在线视频| 国产欧美一区二区白浆黑人| 98精品国产自产在线观看| 丰满岳妇乱一区二区三区| 97精品国产aⅴ7777| 亚洲伊人一本大道中文字幕| 97免费中文视频在线观看| 蜜臀久久99精品久久久无需会员| 亚洲日韩第一页| 国产免费一区二区三区香蕉精| 国产精品久久在线观看| 91国内揄拍国内精品对白| 亚洲成人激情在线观看| 亚洲天堂成人在线视频| 久久久免费观看| 欧美日韩不卡合集视频| 亚洲在线观看视频网站| 91sa在线看| 国产日韩精品在线| 久久偷看各类女兵18女厕嘘嘘| 久久久女女女女999久久| 91精品国产91久久久| 亚洲欧美在线x视频| 欧美国产高跟鞋裸体秀xxxhd| 国产成人拍精品视频午夜网站| 国产精品青青在线观看爽香蕉| 日韩欧美黄色动漫| 亚洲网址你懂得| 国产一区二区三区在线| 午夜精品一区二区三区在线播放| 亚洲精品日韩av| 91国产一区在线| 国产成人97精品免费看片| 亚洲国产欧美精品| 91久久精品日日躁夜夜躁国产| 国产精品久久久久久av下载红粉| 国模极品一区二区三区| 欧美成人精品在线播放| 亚洲大胆人体av| 国产精品综合网站| 欧美精品少妇videofree| 岛国视频午夜一区免费在线观看| 日本成人在线视频网址| 久久久久久久久久亚洲| 欧美性一区二区三区| 欧美洲成人男女午夜视频| 国产日韩欧美日韩大片| 亚洲午夜精品视频| 久久精品国产69国产精品亚洲| 亚洲成人亚洲激情| 亚洲综合精品伊人久久| 欧美日韩国产第一页| 亚洲国产成人精品一区二区|