mramine364

sudoku-app.js

Aug 30th, 2016
117
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2.  
  3. function sudoku_cell() {
  4.     return {
  5.         p: [1,2,3,4,5,6,7,8,9],
  6.         v: 0,
  7.         rand: function(){
  8.             let max = this.p.length-1;
  9.             let min = 0;
  10.             let i = Math.floor( Math.random()*(max-min+1)+min );
  11.             this.v = this.p.splice(i,1)[0];
  12.             return this.v;
  13.         },
  14.         remove: function(el){ // remove elem if contains
  15.             for(let i=0;i<this.p.length;i++){
  16.                 if( this.p[i]==el ){
  17.                     this.p.splice(i,1);
  18.                     break;
  19.                 }
  20.             }
  21.         },
  22.         isEmpty: function(){
  23.             if( this.v==0 && this.p.length==0 )
  24.                 return true;
  25.             return false;
  26.         }
  27.     }
  28. }
  29.  
  30. function sudoku_cell_copy(v, p) {
  31.     return {
  32.         p: p,
  33.         v: v,
  34.         rand: function(){
  35.             let max = this.p.length-1;
  36.             let min = 0;
  37.             let i = Math.floor( Math.random()*(max-min+1)+min );
  38.             this.v = this.p.splice(i,1)[0];
  39.             return this.v;
  40.         },
  41.         remove: function(el){ // remove elem if contains
  42.             for(let i=0;i<this.p.length;i++){
  43.                 if( this.p[i]==el ){
  44.                     this.p.splice(i,1);
  45.                     break;
  46.                 }
  47.             }
  48.         },
  49.         isEmpty: function(){
  50.             if( this.v==0 && this.p.length==0 )
  51.                 return true;
  52.             return false;
  53.         }
  54.     }
  55. }
  56.  
  57. let steps=0;
  58.  
  59. let sudoku = { // 9*9 sudoku
  60.     t: null,
  61.     init: function(){
  62.         this.t = [];
  63.         for(let i=0;i<9;i++){
  64.             let mt = [];
  65.             for(let j=0;j<9;j++){
  66.                 mt.push( sudoku_cell() );
  67.             }
  68.             this.t.push(mt);
  69.         }
  70.     },
  71.     eliminate: function(t, n, ki, kj){
  72.         // row elimination
  73.         for(let i=0;i<9;i++){
  74.             if( t[ki][i].v==0 ){
  75.                 t[ki][i].remove(n);
  76.             }
  77.             if( t[ki][i].isEmpty() ){
  78.                 return false;
  79.             }
  80.         }
  81.         // column elimination
  82.         for(let i=0;i<9;i++){
  83.             if( t[i][kj].v==0 ){
  84.                 t[i][kj].remove(n);
  85.             }
  86.             if( t[i][kj].isEmpty() ){
  87.                 return false;
  88.             }
  89.         }
  90.         // mini-grid elimination
  91.         let ci=Math.floor(ki/3)*3, cj=Math.floor(kj/3)*3;
  92.         for(let i=0;i<3;i++){
  93.             for(let j=0;j<3;j++){
  94.                 if( t[ci+i][cj+j].v==0 ){
  95.                     t[ci+i][cj+j].remove(n);
  96.                 }
  97.                 if( t[ci+i][cj+j].isEmpty() ){
  98.                     return false;
  99.                 }
  100.             }
  101.         }
  102.         return true;
  103.     },
  104.     copy: function(t){
  105.         let r = [];
  106.         for(let i=0;i<9;i++){
  107.             let mt = [];
  108.             for(let j=0;j<9;j++){
  109.                 let obj = sudoku_cell_copy(t[i][j].v, t[i][j].p.slice());
  110.                 mt.push( obj );
  111.             }
  112.             r.push(mt);
  113.         }
  114.         return r;
  115.     },
  116.     gen: function(t, ki, kj, n, lki, lkj){
  117.        
  118.         // steps++;
  119.         // if( steps>100 )
  120.         //  return null;
  121.         // eleminate possibilities
  122.         if( !(ki==0 && kj==0) && !this.eliminate(t, n, lki, lkj) ){
  123.             return null;
  124.         }
  125.         // this.print(t);
  126.         // next
  127.         let nki, nkj;
  128.         if( kj==8 ){
  129.             nki = ki+1;
  130.             nkj = 0;
  131.         }else{
  132.             nki = ki;
  133.             nkj = kj+1;
  134.         }
  135.        
  136.         while( t[ki][kj].p.length!=0 ){
  137.             let nv = t[ki][kj].rand();
  138.             if( nki==9 ){
  139.                 // job done
  140.                 return t;
  141.             }
  142.             let r = this.gen(this.copy(t), nki, nkj, nv, ki, kj);
  143.             if( r!=null ){
  144.                 // this.print(r);
  145.                 return r;
  146.             }
  147.         }
  148.         return null;
  149.     },
  150.     rand: function(){
  151.         console.log(" init.. ");
  152.         this.init();
  153.         console.log(" randering.. ");
  154.         let r = this.gen(this.t, 0, 0, 0, 0, 0);
  155.         // console.log(r);
  156.         console.log(" printing.. ");
  157.         this.print(r);
  158.         console.log(" digging.. ");
  159.         this.dig(r, 30);
  160.         this.print(r);
  161.         console.log(" solving.. ");
  162.         let s;
  163.         // console.log(s);
  164.         while( (s=this.solve(r)).length>1 ){
  165.             // for(let i=0;i<s.length;i++){
  166.             //  console.log(" -------------- ");
  167.             //  this.print(s[i]);
  168.             // }
  169.             let objs = [];
  170.             mn:
  171.             for(let i=0;i<9;i++){
  172.                 for(let j=0;j<9;j++){
  173.                     if( s[0][i][j].v!=s[1][i][j].v ){
  174.                         objs.push({
  175.                             i: i, j: j,
  176.                             v: s[0][i][j].v
  177.                         });
  178.                     }
  179.                 }
  180.             }
  181.             let obj = objs[Math.floor(Math.random()*objs.length)];
  182.             r[obj.i][obj.j].v = obj.v;
  183.         }
  184.         console.log(" final randering.. ");
  185.         // this.print(r);
  186.         // console.log(s);
  187.         return [r, s[0]];
  188.     },
  189.     print: function(t){
  190.         // let obj =null;
  191.         let str = "";
  192.         for(let i=0;i<9;i++){          
  193.             for(let j=0;j<9;j++){
  194.                 // if( obj==null && t[i][j].v==0 ){
  195.                 //  obj = t[i][j];
  196.                 //  // console.log(obj.v, obj.p.join(", "));
  197.                 // }
  198.                 str += t[i][j].v;
  199.                 if( j%3==2 )
  200.                     str += " ";
  201.             }
  202.             str +="\n";
  203.         }
  204.         console.log(str);
  205.     },
  206.     dig: function(t, N){
  207.         let pz = [];
  208.         for(let i=0;i<9;i++){      
  209.             let tpz = [];
  210.             for(let j=0;j<9;j++){
  211.                 tpz.push( {i: i, j: j} );
  212.             }
  213.             pz.push( tpz );
  214.         }
  215.         let n=9*9;
  216.         while(n>N){
  217.             let ti = Math.floor( Math.random()*pz.length );
  218.             let tj = Math.floor( Math.random()*pz[ti].length );
  219.             let obj = pz[ti][tj];
  220.             t[obj.i][obj.j].v = 0;
  221.             pz[ti].splice(tj, 1);
  222.             if( pz[ti].length==0 ){
  223.                 pz.splice(ti, 1);
  224.             }
  225.             n--;
  226.         }
  227.         return t;
  228.     },
  229.     solve: function(t){
  230.         for(let i=0;i<9;i++){
  231.             for(let j=0;j<9;j++){
  232.                 if( t[i][j].v==0 ){
  233.                     t[i][j].p = [1,2,3,4,5,6,7,8,9];
  234.                 }
  235.             }
  236.         }
  237.         for(let i=0;i<9;i++){
  238.             for(let j=0;j<9;j++){
  239.                 if( t[i][j].v!=0 ){
  240.                     this.eliminate(t, t[i][j].v, i, j);
  241.                 }
  242.             }
  243.         }
  244.         let sols = [];
  245.         this._solve(sols, t, 0, 0, 0);
  246.         return sols;
  247.     },
  248.     _solve: function(sols, t, si ,sj, n){
  249.         // steps++;
  250.         // if( steps>10000 )
  251.         //  return null;
  252.         if( sols.length>1 )
  253.             return null;
  254.         if( !(si==0 && sj==0) && !this.eliminate(t, n, si, sj) ){
  255.             return null;
  256.         }
  257.         // console.log("t")
  258.         // this.print(t);
  259.         let i=si, j=sj;
  260.         while( i<9 && t[i][j].v!=0 ){
  261.             if( j==8 ){
  262.                 j=0;
  263.                 i++;
  264.             }else{
  265.                 j++;
  266.             }
  267.         }
  268.         if( i==9 ){
  269.             // console.log("i==9")
  270.             // this.print(t);
  271.             sols.push( t );
  272.             return null;
  273.         }
  274.         while( t[i][j].p.length>0 ){
  275.             let nv = t[i][j].rand();
  276.             this._solve(sols, this.copy(t), i, j, nv);
  277.             if( sols.length>1 )
  278.                 return null;
  279.         }
  280.     }
  281. };
  282.  
  283. let generate = document.getElementById('generate');
  284. let check = document.getElementById('check');
  285. let clear = document.getElementById('clear');
  286. let note = document.getElementById('note');
  287.  
  288. generate.addEventListener('click', function(event){
  289.     try{
  290.         sudoku_UI.gen();       
  291.     }
  292.     catch(e){
  293.         console.log(e);
  294.     }
  295.     let sto = setTimeout(function(){
  296.         while( sudoku_UI.sol==undefined ){
  297.             try{
  298.                 sudoku_UI.gen();       
  299.             }
  300.             catch(e){
  301.                 console.log(e);
  302.             }
  303.         }
  304.         clearTimeout(sto);
  305.     }, 100);
  306.    
  307. });
  308. check.addEventListener('click', function(event){
  309.     sudoku_UI.check();
  310. });
  311. clear.addEventListener('click', function(event){
  312.     sudoku_UI.clear();
  313. });
  314.  
  315. let sudoku_UI = {
  316.     init: function(){
  317.         let rs = document.getElementsByClassName('row');
  318.         for(let i=0;i<rs.length;i++){
  319.             this.grid_UI.push( rs[i].getElementsByClassName('col') );
  320.         }
  321.     },
  322.     grid_UI: [],
  323.     grid: null,
  324.     sol: null,
  325.     gen: function(){
  326.         // let s, r;
  327.         note.className = "";
  328.         note.textContent = "Generating... (it may take long time)";
  329.         let tab = sudoku.rand();
  330.         // console.log(tab)
  331.         this.grid = tab[0];
  332.         this.sol = tab[1];
  333.         // console.log(this.sol);
  334.         // sudoku.print(this.sol);
  335.         note.textContent = "";
  336.         for(let i=0;i<this.grid.length;i++){
  337.             for(let j=0;j<this.grid[i].length;j++){
  338.                 if( this.grid[i][j].v==0 ){
  339.                     this.grid_UI[i][j].innerHTML = "<input type='text' class='inp'></td>";
  340.                 }else{
  341.                     this.grid_UI[i][j].textContent = this.grid[i][j].v;
  342.                 }
  343.             }
  344.         }
  345.  
  346.     }, 
  347.     check: function(){
  348.         if( this.grid==null )
  349.             return null;
  350.         let emp = 0;
  351.         for(let i=0;i<this.grid.length;i++){
  352.             for(let j=0;j<this.grid[i].length;j++){
  353.                 if( this.grid[i][j].v==0 ){
  354.                     let inp = this.grid_UI[i][j].getElementsByClassName('inp');
  355.                     // console.log(inp)
  356.                     if( inp.length==0 ){
  357.                         // exception                       
  358.                         return null;
  359.                     }
  360.                     if( inp[0].value!="" && inp[0].value!=this.sol[i][j].v ){
  361.                         note.className = "not-ok-note";
  362.                         note.textContent = "You have made some mistakes.";
  363.                         return null;
  364.                     }
  365.                     else if( inp[0].value=="" ){
  366.                         emp++;
  367.                     }
  368.                 }/*else{
  369.                     this.grid_UI[i][j].textContent = this.grid[i][j].v;
  370.                 }*/
  371.             }
  372.         }
  373.         note.className = "ok-note";
  374.         if( emp>0 ){
  375.             note.textContent = "Everything is OK, you still have "+emp+" to go!";
  376.         }else{
  377.             note.textContent = "Sudoku solved. Congratulations!";
  378.         }
  379.     },
  380.     clear: function(){
  381.         if( this.grid==null )
  382.             return null;
  383.         for(let i=0;i<this.grid.length;i++){
  384.             for(let j=0;j<this.grid[i].length;j++){
  385.                 if( this.grid[i][j].v==0 ){
  386.                     let inp = this.grid_UI[i][j].getElementsByClassName('inp');
  387.                     // console.log(inp)
  388.                     if( inp.length==0 ){
  389.                         // exception                       
  390.                         return null;
  391.                     }
  392.                     inp[0].value="";                   
  393.                 }
  394.             }
  395.         }
  396.     }
  397. }
  398.  
  399. sudoku_UI.init();
Advertisement
Add Comment
Please, Sign In to add comment