鍍金池/ 問答/人工智能  數(shù)據(jù)分析&挖掘  HTML/ 用JavaScript寫生成數(shù)獨算法時瀏覽器變慢

用JavaScript寫生成數(shù)獨算法時瀏覽器變慢

我的想法是這樣的:先定義一個數(shù)組sudoku9,然后通過for循環(huán)依次把數(shù)字1填入到每個小九宮格中,然后再把數(shù)字2填入到每個小九宮格中,以此類推。小九宮格的編號從0~8,數(shù)字在每個小九宮格的位置(position)可以是0~8。請問有什么可以改進的地方

var sudoku=[
     [0,0,0,0,0,0,0,0,0],
     [0,0,0,0,0,0,0,0,0],
     [0,0,0,0,0,0,0,0,0],
     [0,0,0,0,0,0,0,0,0],
     [0,0,0,0,0,0,0,0,0],
     [0,0,0,0,0,0,0,0,0],
     [0,0,0,0,0,0,0,0,0],
     [0,0,0,0,0,0,0,0,0],
     [0,0,0,0,0,0,0,0,0],
  ];

function generateSudoku(){
    for(var i=1;i<10;i++){
      for(var j=0;j<9;j++){
        fillNumberInOneArray(i,j);//把數(shù)字填入到某個小九宮格中
      }
       }
   }

//根據(jù)position和n計算出在數(shù)組sudoku中的位置,并通過數(shù)組coor返回坐標
   function calculateCoordinate(position,n){
    var i=0,j=0;
    var coor=[0,0]
      switch(position){
      case 0:{
         i=(n%3)*3;
         j=parseInt(n/3)*3;
        break;
      }
      case 1:{
         i=(n%3)*3+1;
         j=parseInt(n/3)*3;
        break;
      }
      case 2:{
         i=(n%3)*3+2;
         j=parseInt(n/3)*3;
        break;
      }
      case 3:{
         i=(n%3)*3;
         j=parseInt(n/3)*3+1;
        break;
      }
      case 4:{
         i=(n%3)*3+1;
         j=parseInt(n/3)*3+1;
        break;
      }
      case 5:{
         i=(n%3)*3+2;
         j=parseInt(n/3)*3+1;
        break;
      }
      case 6:{
        i=(n%3)*3;
        j=parseInt(n/3)*3+2;
        break;
      }
      case 7:{
         i=(n%3)*3+1;
         j=parseInt(n/3)*3+2;
        break;
      }
      case 8:{
         i=(n%3)*3+2;
         j=parseInt(n/3)*3+2;
        break;
      }
      
    }
    coor=[j,i];
    //console.log("算出來的coor=("+coor+")");
    return coor;
   }

//隨機產生在[min,max]之間的隨機數(shù)
   function RandomNumBoth(Min,Max){
      var Range = Max - Min;
      var Rand = Math.random();
      var num = Min + Math.round(Rand * Range); //四舍五入
      return num;
   }

//將數(shù)字m填入到第n個小九宮格中
   function fillNumberInOneArray(m,n){
      do{
        var position=RandomNumBoth(0,8);
      var coor=calculateCoordinate(position,n);
    }while(!judgeElse(n,coor[0],coor[1])||!lockRow(m,n,coor[1])||!lockColumn(m,n,coor[0]))
     sudoku[coor[0]][coor[1]]=m;
     
   } 
//判斷在數(shù)組sudoku中填入的數(shù)字num所在的列上是否有相同的數(shù)字
function lockRow(num,n,y){
    var ii=parseInt(n/3);
    if(ii==1){
      for(var i=0;i<3;i++){
          if(sudoku[i][y]==num){
            return false;
          }
        }
      }else if(ii==2){
        for(var i=0;i<6;i++){
          if(sudoku[i][y]==num){
            return false;
          }
        }
      }
      return true;
   }
//判斷在數(shù)組sudoku中填入的數(shù)字num所在的行上是否有相同的數(shù)字
   function lockColumn(num,n,x){
    var jj=n%3;
    if(jj==1){
      for(var j=0;j<3;j++){
          if(sudoku[x][j]==num){
            return false;
          }
        }
    }else if(jj==2){
      for(var j=0;j<6;j++){
          if(sudoku[x][j]==num){
            return false;
          }
        }
    }
   }
//判斷在要填入數(shù)字的位置上是否已經(jīng)有其他數(shù)字
   function judgeElse(n,x,y){
    if(sudoku[x][y]!=0){
      return false;
    }
    return true;
   }
回答
編輯回答
尐飯團

fillNumberInOneArray 將數(shù)字 m 填入到 第 n 個小宮格中,為什么要隨機選一個位置放呢?后期快放滿的時候,沖突的概率越來越大,根本不收斂的呀。你都能 judgeElse 了,為什么不能在生成 random 坐標之前就排除一下已經(jīng)放了數(shù)字的格子呢?這一步浪費的效率不計其數(shù),甚至導致了算法有極大可能無法停止。9個格子有一個空位,用random去撞這個空位置,那有 8/9 的概率撞不到,一直死循環(huán)。

已經(jīng)被占的格子提前排除,這是其一。其二,假設小9宮格都剩下3個格子,需要放 7 了對吧,隨機一下,得到一個空格子,檢查了一下橫豎,發(fā)現(xiàn)不能放,接下來你需要標記這個格子不可用,否則下次再 random 還有 1/3 的概率打中這個不可用的格子,導致算法不收斂。犯過的錯,為什么下次還要繼續(xù)犯?下次你就該排除掉它,在剩下的選項里挑,否則這次試錯就沒有意義啦,那這就不是算法,完全就是在碰運氣。

function calculateCoordinate(position,n) 也可以精簡一下,沒必要那么多 switch-case:

function calculateCoordinate(position, n) {
  // 先計算九宮格是幾排幾列的九宮格, 我們把數(shù)獨看成是 3*3 的9個9宮格
  var nx = n % 3;
  var ny = Math.floor(n / 3); 

  var px = position % 3;
  var py = Math.floor(position / 3);
  // 同樣的套路處理小9宮格內的坐標,
  
  // 轉換一下坐標系
  var returnX = px + nx * 3; 
  var returnY = py + ny * 3;
  return [returnY, returnX];
}
2018年6月29日 02:03