564 lines, 20,874 bytes [toggle line numbers]
0001  ///////////////////////////////////////////////////////
0002  // xWinLib Sudoku, written by SM Repetti
0003  // (c) 2008-2013 by SM Repetti, All Rights Reserved
0004  //
0005  var NUM_PRESET = 1;
0006  var NUM_INIT   = 2;
0007  
0008  function xwin_Sudoku( ) {
0009      this.win = null;
0010      this.winNav = null;
0011      this.winResults = null;
0012      this.winTimer = null;
0013      this.aCell = null;
0014      this.cellWidth = 60;
0015      this.cellHeight = 60;
0016      this.cellMargin = 5;
0017      this.curCell = null;
0018      this.difficulty = "";
0019  
0020      this.gameStart = null;
0021      this.htimer = null;
0022  
0023      this.init( );
0024  }
0025  
0026  xwin_Sudoku.prototype.init = function( ) {
0027      var i, j;
0028  
0029      // create the main window
0030      this.win = new xWindow( "sudoku" );
0031      this.win.style = WS_NORMAL | WS_TRANSPARENT | WS_BORDER | WS_MOVEABLE;
0032      this.win.setposition( 0, 0, 750, 592 );
0033      this.win.displayMode = DISP_CENTERED;
0034      this.win.transLevel = 70;
0035      this.win.create( );
0036  
0037      // initialize the cell array
0038      this.aCell = new Array( 9 );
0039      for ( i=0; i<9; i++ ) {
0040          this.aCell[i] = new Array( 9 );
0041      }
0042  
0043      // create the cells
0044      for ( i=0; i<9; i++ ) {
0045          for ( j=0; j<9; j++ ) {
0046              this.aCell[i][j] = this.cellCreate( i, j );
0047          }
0048      }
0049  
0050      // create the side window
0051      this.winNav = new xWindow( "sudoku_nav" );
0052      this.winNav.style = WS_NORMAL | WS_TRANSPARENT | WS_BORDER | WS_CHILD;
0053      this.winNav.setposition( 590, 5, 153, 580 );
0054      this.winNav.bodyClass = "smtxtw";
0055      this.winNav.oparent = this.win;
0056      this.winNav.overflow = "hidden";
0057      this.winNav.padding = 7;
0058      this.winNav.transLevel = 50;
0059      this.winNav.action = "<b><font class=title>SUDOKU</font><br>xWinLib<p>" +
0060          "<a href='javascript:sudoku.gameNew();'>New Game</a><br>" +
0061          "<a href='javascript:sudoku.gameReset();'>Reset Game</a><br>" +
0062          "<a href='javascript:sudoku.gameBackgroundToggle();'>Toggle Background</a></b>" +
0063          "<div style='position:absolute; left:6; top:310; width:138'>" +
0064          "Use the ARROW KEYS, MOUSE, or TAB BUTTON to select a cell, then enter a number between 1 and 9. Enter hints by holding down the SHIFT button. Press DELETE or the SPACEBAR to erase an entry." +
0065          "<p><font color='FFFF80'>Written by SM Repetti using the xWinLib library. <a href='mailto:steve@steverepetti.com?subject=Request Sudoku Custom Version'><font color=white>Click here</font></a> to request a custom commercial version.</font>" +
0066          "<p><a href=\"javascript:exUndock( '/demos/sudoku/sudoku.js' )\">View source code...</a>" +
0067          "</div>";
0068      this.winNav.create( );
0069  
0070      // create the results window
0071      this.winResults = new xWindow( "sudoku_results" );
0072      this.winResults.style = WS_NORMAL | WS_TRANSPARENT | WS_BORDER;
0073      this.winResults.setposition( 6, 130, 138, 138 );
0074      this.winResults.bodyClass = "smtxtw";
0075      this.winResults.oparent = this.winNav;
0076      this.winResults.overflow = "hidden";
0077      this.winResults.padding = 0;
0078      this.winResults.transLevel = 100;
0079      this.winResults.action = "<table id='sResults' border=1 bordercolor='#606060' cellspacing=0 cellpadding=0 class=tblResults>" +
0080          "<tr height=15><td width=15> </td><td width=15> </td><td width=15> </td><td width=15> </td><td width=15> </td><td width=15> </td><td width=15> </td><td width=15> </td><td width=15> </td></tr>" +
0081          "<tr height=15><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td></tr>" +
0082          "<tr height=15><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td></tr>" +
0083          "<tr height=15><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td></tr>" +
0084          "<tr height=15><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td></tr>" +
0085          "<tr height=15><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td></tr>" +
0086          "<tr height=15><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td></tr>" +
0087          "<tr height=15><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td></tr>" +
0088          "<tr height=15><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td></tr>" +
0089          "</table>";
0090      this.winResults.create( );
0091  
0092      // create the timer window
0093      this.winTimer= new xWindow( "sudoku_timer" );
0094      this.winTimer.style = WS_NORMAL | WS_TRANSPARENT;
0095      this.winTimer.setposition( 7, 275, 138, 20 );
0096      this.winTimer.bodyClass = "smtxtw";
0097      this.winTimer.oparent = this.winNav;
0098      this.winTimer.overflow = "hidden";
0099      this.winTimer.padding = 0;
0100      this.winTimer.transLevel = 100;
0101      this.winTimer.action = "00:00.00";
0102      this.winTimer.create( );
0103  
0104      xlib.eventBind( document, "keydown", keyHandler, true );
0105      xlib.eventBind( document, "keyup", keyupHandler, false );
0106  };
0107  
0108  xwin_Sudoku.prototype.cellCreate = function( r, c ) {
0109      var w, x, y;
0110  
0111      w = new xWindow( "c" + r + c );
0112      w.style = WS_NORMAL | WS_TRANSPARENT | WS_BORDER;
0113      w.oparent = this.win;
0114      w.overflow = "hidden";
0115      w.transLevel = 80;
0116  
0117      if ( ( ( r < 3 || r > 5 ) && ( c < 3 || c > 5 ) ) ||
0118           ( ( r > 2 && r < 6 ) && ( c > 2 && c < 6 ) ) ) {
0119          w.transLevel = 50;
0120      }
0121  
0122      x = ( ( this.cellMargin + this.cellWidth ) * c ) + this.cellMargin;
0123      y = ( ( this.cellMargin + this.cellHeight ) * r ) + this.cellMargin;
0124  
0125      w.setposition( x, y, this.cellWidth, this.cellHeight );
0126  
0127      w.action = "<div style='position:absolute; left:0; top:0; width:" + this.cellWidth + "; height:" + this.cellHeight + ";'><table id='" + w.name + "_sHint' style='visibility:hidden;' class='hint' cellpadding=0 cellspacing=0>" +
0128          "<tr width=33% align=center><td width=33%> </td><td width=34%> </td><td width=33%> </td></tr>" +
0129          "<tr width=34% align=center><td> </td><td> </td><td> </td></tr>" +
0130          "<tr width=33% align=center><td> </td><td> </td><td> </td></tr>" +
0131          "</table></div>" +
0132          "<div style='position:absolute; left:0; top:0; width:" + this.cellWidth + "; height:" + this.cellHeight + ";'><table class='num' cellpadding=0 cellspacing=0>" +
0133          "<tr align=center><td style='visibility:hidden;' id='" + w.name + "_sNum'></td><tr>" +
0134          "</table></div>";
0135  
0136      w.eClick = clickHandler;
0137      w.create( );
0138  
0139      return( w );
0140  };
0141  
0142  xwin_Sudoku.prototype.cellIndex = function( w ) {
0143      var a, cnt, i;
0144  
0145      a = this.aCell;
0146      for ( i=0; i<9; i++ ) {
0147          for ( j=0; j<9; j++ ) {
0148              if ( a[i][j].name == w.name ) {
0149                  return( { "row": i, "col": j } );
0150              }
0151          }
0152      }
0153      return( null );
0154  };
0155  
0156  xwin_Sudoku.prototype.cellSetNum = function( r, c, val, ntype, k ) {
0157      var w, o, x, a, cname = "num";
0158  
0159      w = typeof( r ) == "number" ? this.aCell[r][c] : r;
0160      if ( ( ntype & NUM_PRESET ) && ( ! strempty( val ) ) ) {
0161          cname = "numPreset";
0162          w.eClick = null;
0163      }
0164      o = domObject( w.name + "_sNum" );
0165      if ( ! ( ntype & NUM_PRESET ) && ( o.className == "numPreset" ) ) {
0166          return;
0167      }
0168  
0169      if ( strempty( o.innerHTML ) && k && k.isSHIFT ) {
0170          o = domObject( w.name + "_sHint" );
0171          x = int( val ) - 1;
0172          a = [ 1,1,1,2,2,2,3,3,3 ];
0173          r = a[x];
0174          a = [ 1,2,3,1,2,3,1,2,3 ];
0175          c = a[x];
0176  
0177          o = tableCellObj( o, r, c );
0178          if ( strat( val, o.innerHTML ) ) {
0179              o.innerHTML = " ";
0180          }
0181          else {
0182              o.innerHTML = val;
0183          }
0184      }
0185      else {
0186          if ( ntype & NUM_INIT ) {
0187              w.eClick = clickHandler;
0188          }
0189          o.className = cname;
0190          o.innerHTML = val;
0191          o.style.visibility = strempty( val ) ? "hidden" : "visible";
0192          if ( cname != "numPreset" ) {
0193              o = domObject( w.name + "_sHint" );
0194              o.style.visibility = strempty( val ) ? "visible" : "hidden";
0195              if ( ! strempty( val ) ) {
0196                  sudoku.gameVerify( );
0197              }
0198          }
0199      }
0200  };
0201  
0202  xwin_Sudoku.prototype.cellTab = function( w, k ) {
0203      var p, x, y, r;
0204  
0205      p = this.cellIndex( w );
0206      if ( ! p ) { return; }
0207  
0208      switch ( k.code ) {
0209        case KEY_TAB:
0210            x = int( strextract( "" + ( p.col / 3 ), ".", 1 ) ) * 3;
0211            y = int( strextract( "" + ( p.row / 3 ), ".", 1 ) ) * 3;
0212            r = ( { 'x1': x, 'y1': y, 'x2': x+2, 'y2': y+2 } );
0213  
0214          if ( k.isSHIFT ) {
0215              p.col--;
0216              if ( p.col < r.x1 ) {
0217                  p.row--;
0218                  if ( p.row < r.y1 ) {
0219                      p.col = r.x2;
0220                      p.row = r.y2;
0221                  }
0222                  else {
0223                      p.col = r.x2;
0224                  }
0225              }
0226          }
0227          else {
0228              p.col++;
0229              if ( p.col > r.x2 ) {
0230                  p.row++;
0231                  if ( p.row > r.y2 ) {
0232                      p.col = r.x1;
0233                      p.row = r.y1;
0234                  }
0235                  else {
0236                      p.col = r.x1;
0237                  }
0238              }
0239          }
0240            break;
0241        case KEY_ARROWLEFT:
0242            p.col--; if ( p.col < 0 ) { p.col = 8; }
0243            break;
0244        case KEY_ARROWUP:
0245            p.row--; if ( p.row < 0 ) { p.row = 8; }
0246            break;
0247        case KEY_ARROWRIGHT:
0248            p.col++; if ( p.col > 8 ) { p.col = 0; }
0249            break;
0250        case KEY_ARROWDOWN:
0251            p.row++; if ( p.row > 8 ) { p.row = 0; }
0252            break;
0253      }
0254  
0255      this.cellToggle( this.aCell[p.row][p.col] );
0256  };
0257  
0258  xwin_Sudoku.prototype.cellToggle = function( w ) {
0259  
0260      if ( sudoku.curCell ) {
0261          if ( sudoku.curCell.name == w.name ) {
0262              return;
0263          }
0264          sudoku.curCell.obj.style.border = "solid 1px black";
0265          if ( sudoku.curCell.name == w.name ) {
0266              sudoku.curCell = null;
0267              return;
0268          }
0269      }
0270  
0271      w.obj.style.border = "solid 3px white";
0272      w.obj.focus( );
0273      sudoku.curCell = w;
0274  };
0275  
0276  xwin_Sudoku.prototype.gameBackgroundToggle = function(  ) {
0277      this.win.obj.style.background = strat( "white", this.win.obj.style.background ) ? "" : "white";
0278  };
0279  
0280  xwin_Sudoku.prototype.gameLoad = function( data ) {
0281      var a, i, cnt, r=0, c=0;
0282  
0283      if ( ! data ) {
0284          this.gameNew( 1 );
0285          return;
0286      }
0287  
0288  
0289      a = data.split( "," );
0290      this.difficulty = upper( a[81] );
0291      for ( i=0; i<81; i++ ) {
0292          if ( c > 8 ) {
0293              r++;
0294              c = 0;
0295          }
0296          this.cellSetNum( r, c++, a[i] == "0" ? "" : a[i], NUM_PRESET | NUM_INIT );
0297      }
0298      this.cellToggle( this.aCell[0][0] );
0299  
0300      this.gameStart = new Date( );
0301      this.gameTimer( 1 );
0302  
0303      this.gameVerify( );
0304  };
0305  
0306  xwin_Sudoku.prototype.gameNew = function( NoConfirm ) {
0307      var a;
0308  
0309      if ( ! NoConfirm ) {
0310          if ( ! confirm( "Are you sure you want to load a new game?" ) ) {
0311              return;
0312          }
0313      }
0314  
0315      a = new Array( );
0316  
0317      a[1]  = "0,8,6,0,3,9,4,0,0,0,1,0,0,0,2,0,0,0,0,7,0,0,0,0,0,1,8,0,2,0,0,0,3,0,0,4,0,0,0,6,0,1,0,0,0,6,0,0,5,0,0,0,7,0,7,3,0,0,0,0,0,9,0,0,0,0,9,0,0,0,4,0,0,0,9,3,5,0,1,2,0,easy";
0318      a[2]  = "0,0,0,0,9,0,3,0,0,2,0,8,3,0,4,0,0,5,0,6,0,0,0,0,0,2,0,0,0,9,0,0,0,1,3,0,0,4,0,9,0,7,0,6,0,0,2,6,0,0,0,8,0,0,0,7,0,0,0,0,0,9,0,9,0,0,6,0,5,7,0,3,0,0,1,0,7,0,0,0,0,easy";
0319      a[3]  = "3,0,0,0,0,1,8,0,2,0,1,6,0,0,0,0,9,0,0,2,4,0,0,7,0,0,0,0,6,0,0,9,0,2,0,0,0,0,2,0,0,0,6,0,0,0,0,9,0,1,0,0,7,0,0,0,0,6,0,0,5,1,0,0,3,0,0,0,0,4,2,0,7,0,1,3,0,0,0,0,8,easy";
0320      a[4]  = "0,0,0,9,0,6,0,0,0,0,9,0,0,0,0,0,7,0,6,8,7,0,0,0,4,2,9,0,0,6,8,0,3,5,0,0,5,0,0,0,0,0,0,0,2,0,0,9,7,0,2,1,0,0,1,4,2,0,0,0,7,8,6,0,6,0,0,0,0,0,4,0,0,0,0,6,0,7,0,0,0,easy";
0321      a[5]  = "6,0,2,7,5,0,0,4,0,0,0,0,9,6,2,0,0,0,0,7,0,4,0,0,0,0,0,0,1,6,0,9,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,7,0,8,5,0,0,0,0,0,0,9,0,3,0,0,0,0,1,8,7,0,0,0,0,8,0,0,3,4,6,0,7,easy";
0322      a[6]  = "0,0,2,9,0,7,5,0,0,0,8,0,0,6,0,0,2,0,1,0,3,0,0,0,4,0,9,0,0,4,3,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,9,2,0,8,1,0,0,2,0,6,0,0,0,7,0,5,0,5,0,0,4,0,0,3,0,0,0,1,7,0,2,6,0,0,easy";
0323      a[7]  = "0,0,0,9,0,6,0,0,0,0,9,0,0,0,0,0,7,0,6,8,7,0,0,0,4,2,9,0,0,6,8,0,3,5,0,0,5,0,0,0,0,0,0,0,2,0,0,9,7,0,2,1,0,0,1,4,2,0,0,0,7,8,6,0,6,0,0,0,0,0,4,0,0,0,0,6,0,7,0,0,0,easy";
0324  
0325      a[8]  = "0,0,1,7,0,0,2,0,0,0,7,0,0,8,4,0,0,3,0,0,0,0,0,9,1,0,8,4,0,3,0,0,2,0,0,0,8,0,0,0,0,0,0,0,7,0,0,0,6,0,0,3,0,9,9,0,8,4,0,0,0,0,0,1,0,0,5,2,0,0,8,0,0,0,5,0,0,6,7,0,0,medium";
0326      a[9]  = "0,9,0,0,0,0,8,0,0,0,0,1,0,0,2,4,6,5,2,0,0,0,7,0,0,0,0,0,0,0,0,0,3,5,0,9,0,6,0,0,0,0,0,3,0,3,0,5,1,0,0,0,0,0,0,0,0,0,6,0,0,0,8,7,1,2,3,0,0,9,0,0,0,0,9,0,0,0,0,7,0,medium";
0327      a[10] = "9,0,5,0,6,0,0,0,0,0,0,0,0,0,5,8,0,6,0,0,0,0,0,4,0,5,9,0,0,0,0,5,1,3,4,0,0,0,2,0,0,0,6,0,0,0,7,4,6,2,0,0,0,0,3,5,0,1,0,0,0,0,0,8,0,9,3,0,0,0,0,0,0,0,0,0,8,0,7,0,4,medium";
0328      a[11] = "0,3,0,2,0,4,0,0,8,0,0,9,0,6,0,5,0,0,0,4,0,8,0,0,0,7,0,9,0,0,0,4,0,0,8,0,0,0,3,0,0,0,4,0,0,0,5,0,0,1,0,0,0,3,0,8,0,0,0,7,0,2,0,0,0,1,0,8,0,7,0,0,6,0,0,5,0,1,0,3,0,medium";
0329      a[12] = "9,0,0,4,0,0,3,0,0,0,0,6,0,5,2,0,0,9,0,0,0,8,0,0,0,2,0,5,0,0,1,8,0,0,0,0,6,4,0,0,0,0,0,5,1,0,0,0,0,9,5,0,0,4,0,8,0,0,0,6,0,0,0,4,0,0,5,2,0,9,0,0,0,0,1,0,0,3,0,0,5,medium";
0330      a[13] = "6,0,0,0,0,0,8,0,0,0,3,1,8,0,0,6,0,0,2,0,0,9,0,6,3,0,4,0,5,0,0,0,7,0,1,0,0,0,0,0,8,0,0,0,0,0,1,0,3,0,0,0,8,0,1,0,9,2,0,8,0,0,6,0,0,7,0,0,9,2,4,0,0,0,3,0,0,0,0,0,9,medium";
0331      a[14] = "0,0,0,0,0,1,0,5,0,0,0,4,0,0,0,3,8,0,5,0,0,9,0,0,0,7,0,0,0,9,0,3,0,0,1,0,0,5,1,4,0,6,2,3,0,0,7,0,0,1,0,6,0,0,0,4,0,0,0,3,0,0,9,0,3,6,0,0,0,1,0,0,0,9,0,7,0,0,0,0,0,medium";
0332      a[15] = "4,5,0,0,6,0,7,1,0,7,0,0,1,0,0,0,6,0,0,0,0,0,0,0,5,0,3,0,2,0,0,3,0,0,0,0,8,0,1,0,0,0,6,0,5,0,0,0,0,5,0,0,9,0,1,0,4,0,0,0,0,0,0,0,6,0,0,0,4,0,0,8,0,3,8,0,1,0,0,5,9,medium";
0333      a[16] = "0,8,0,7,0,0,4,0,0,0,1,9,0,3,0,0,8,0,0,7,3,0,0,0,2,0,0,5,0,0,8,0,0,0,0,0,0,0,7,4,0,9,1,0,0,0,0,0,0,0,3,0,0,5,0,0,8,0,0,0,6,1,0,0,3,0,0,7,0,5,9,0,0,0,6,0,0,5,0,2,0,medium";
0334      a[17] = "0,1,0,0,0,0,9,0,0,3,8,0,0,2,9,1,0,0,0,0,4,0,0,8,0,2,0,4,0,0,9,0,3,0,0,0,1,0,0,0,0,0,0,0,4,0,0,0,2,0,1,0,0,7,0,2,0,3,0,0,8,0,0,0,0,8,1,5,0,0,3,2,0,0,6,0,0,0,0,7,0,medium";
0335      a[18] = "0,5,1,0,0,0,2,7,0,0,3,0,7,2,6,0,4,0,7,0,0,0,0,0,0,0,8,0,0,2,1,0,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,8,1,0,0,2,0,0,0,0,0,0,0,7,0,7,0,9,1,2,0,3,0,0,1,5,0,0,0,9,6,0,medium";
0336      a[19] = "5,0,0,4,0,0,6,8,0,0,2,0,0,0,0,0,0,4,0,6,0,2,0,8,0,0,9,9,0,1,0,0,0,2,6,0,0,0,0,0,1,0,0,0,0,0,5,7,0,0,0,9,0,3,2,0,0,7,0,4,0,5,0,4,0,0,0,0,0,0,9,0,0,1,8,0,0,5,0,0,6,medium";
0337  
0338      a[20] = "2,0,0,0,0,0,0,5,0,0,0,0,0,0,7,1,0,0,0,8,4,9,0,0,0,3,0,8,0,0,7,4,0,0,6,5,0,0,0,0,2,0,0,0,0,3,6,0,0,1,8,0,0,4,0,9,0,0,0,6,5,1,0,0,0,2,8,0,0,0,0,0,0,7,0,0,0,0,0,0,9,hard";
0339      a[21] = "0,0,3,0,0,0,0,7,6,0,1,0,5,0,0,0,4,0,5,2,0,0,6,0,0,3,0,0,0,0,1,0,5,0,0,0,0,5,2,0,0,0,1,9,0,0,0,0,8,0,7,0,0,0,0,4,0,0,5,0,0,8,7,0,7,0,0,0,4,0,2,0,9,8,0,0,0,0,4,0,0,hard";
0340      a[22] = "3,0,5,0,2,0,0,4,1,0,0,9,0,0,1,7,0,0,0,0,0,0,0,0,2,0,0,7,0,0,3,0,0,6,0,0,5,0,0,1,0,2,0,0,3,0,0,8,0,0,9,0,0,5,0,0,3,0,0,0,0,0,0,0,0,4,8,0,0,5,0,0,1,6,0,0,4,0,3,0,9,hard";
0341      a[23] = "2,0,0,0,3,0,0,7,5,0,5,0,0,0,2,3,8,0,0,0,0,5,0,9,0,0,0,0,0,0,4,0,0,5,0,8,9,0,0,0,0,0,0,0,7,7,0,2,0,0,6,0,0,0,0,0,0,1,0,5,0,0,0,0,2,4,9,0,0,0,6,0,8,9,0,0,6,0,0,0,3,hard";
0342      a[24] = "0,5,0,0,0,3,0,0,4,0,8,0,0,7,2,0,0,0,2,0,3,9,0,8,0,0,1,0,0,6,0,3,0,0,0,9,0,0,0,0,0,0,0,0,0,3,0,0,0,5,0,7,0,0,6,0,0,8,0,4,3,0,7,0,0,0,1,9,0,0,2,0,9,0,0,3,0,0,0,4,0,hard";
0343      a[25] = "0,1,0,0,0,0,0,0,8,6,0,2,0,3,0,0,0,9,0,0,0,1,0,2,4,0,0,0,3,0,4,0,9,8,0,0,0,5,0,0,0,0,0,4,0,0,0,4,3,0,8,0,7,0,0,0,1,2,0,3,0,0,0,8,0,0,0,4,0,6,0,1,9,0,0,0,0,0,0,3,0,hard";
0344  
0345      a[26] = "0,0,0,0,0,0,0,0,8,4,0,0,0,7,9,0,5,0,0,5,0,0,0,2,3,9,1,0,0,3,8,0,0,0,0,0,0,2,0,0,0,0,0,8,0,0,0,0,0,0,6,1,0,0,8,7,2,9,0,0,0,3,0,0,1,0,3,5,0,0,0,2,3,0,0,0,0,0,0,0,0,evil";
0346      a[27] = "0,5,0,0,0,1,6,0,0,3,0,6,0,0,0,0,0,0,0,0,9,3,0,0,2,0,4,0,0,0,0,3,0,1,0,2,0,0,0,8,0,4,0,0,0,8,0,5,0,2,0,0,0,0,6,0,1,0,0,5,3,0,0,0,0,0,0,0,0,9,0,1,0,0,7,2,0,0,0,4,0,evil";
0347       a[28] = "0,0,0,0,6,8,0,7,0,0,3,2,0,0,0,0,0,0,0,0,6,0,0,3,2,5,0,1,9,0,0,7,0,0,8,0,0,0,0,0,4,0,0,0,0,0,5,0,0,8,0,0,3,4,0,7,9,1,0,0,3,0,0,0,0,0,0,0,0,5,6,0,0,6,0,7,3,0,0,0,0,evil";
0348      a[29] = "0,3,0,6,9,0,0,0,0,5,7,0,0,3,8,0,0,0,0,0,0,0,0,0,6,0,0,4,9,5,3,0,0,0,8,0,0,6,0,0,0,0,0,1,0,0,8,0,0,0,6,5,3,9,0,0,7,0,0,0,0,0,0,0,0,0,8,2,0,0,4,5,0,0,0,0,6,1,0,2,0,evil";
0349  
0350      if ( ! NoConfirm ) {
0351          this.gameReset( 1 );
0352      }
0353  
0354      x = random( a.length - 1 );
0355      this.gameLoad( a[x] );
0356  };
0357  
0358  xwin_Sudoku.prototype.gameReset = function( NoConfirm ) {
0359      var a, cnt, i, oHint, o, x, y;
0360  
0361      if ( ! NoConfirm ) {
0362          if ( ! confirm( "Are you sure you want to reset the current game?" ) ) {
0363              return;
0364          }
0365      }
0366  
0367      aRows = [ 1,1,1,2,2,2,3,3,3 ];
0368      aCols = [ 1,2,3,1,2,3,1,2,3 ];
0369  
0370      a = this.aCell;
0371      for ( i=0; i<9; i++ ) {
0372          for ( j=0; j<9; j++ ) {
0373              if ( domObject( a[i][j].name + "_sNum" ).className != "numPreset" ) {
0374                  this.cellSetNum( a[i][j], 0, "" );
0375                  oHint = domObject( a[i][j].name + "_sHint" );
0376                  for ( x=0; x<3; x++ ) {
0377                      o = tableRowObj( oHint, x+1 );
0378                      for ( y=0; y<3; y++ ){
0379                          o.cells[y].innerHTML = " ";
0380                      }
0381                  }
0382              }
0383          }
0384      }
0385  
0386      if ( ! NoConfirm ) {
0387          this.cellToggle( this.aCell[0][0] );
0388      }
0389      this.gameStart = new Date( );
0390      this.gameVerify( );
0391  };
0392  
0393  xwin_Sudoku.prototype.gameResultsRow = function( row, flag ) {
0394      var i, otable;
0395  
0396      otable = domObject( "sResults" );
0397      for ( i=1; i<10; i++ ) {
0398          o = tableCellObj( otable, row+1, i );
0399          o.style.background = flag ? "#00FF00" : "";
0400      }
0401  };
0402  
0403  xwin_Sudoku.prototype.gameResultsCol = function( col, flag ) {
0404      var i, otable;
0405  
0406      otable = domObject( "sResults" );
0407      for ( i=1; i<10; i++ ) {
0408          o = tableCellObj( otable, i, col+1 );
0409          if ( flag ) { o.style.background = "#00FF00"; }
0410      }
0411  };
0412  
0413  xwin_Sudoku.prototype.gameResultsBlock = function( a, flag ) {
0414      var i, otable;
0415  
0416      otable = domObject( "sResults" );
0417      for ( i=0; i<9; i++ ) {
0418          o = tableCellObj( otable, a[i][0]+1, a[i][1]+1 );
0419          if ( flag ) { o.style.background = "#00FF00"; }
0420      }
0421  };
0422  
0423  xwin_Sudoku.prototype.gameTimer = function( flag ) {
0424      if ( this.htimer ) {
0425          clearTimeout( this.htimer );
0426          this.htimer = null;
0427      }
0428  
0429      if ( flag ) {
0430          this.htimer = setTimeout( "sudoku.gameTimerUpdate( )", 200 );
0431      }
0432  };
0433  
0434  xwin_Sudoku.prototype.gameTimerUpdate = function( flag ) {
0435      d = new xDate( );
0436      sudoku.winTimer.oBody.innerHTML = d.diff( d.date, sudoku.gameStart ) + "   <font color='FFFF80'>" + this.difficulty + "</font>";
0437      setTimeout( "sudoku.gameTimerUpdate( )", 200 );
0438  };
0439  
0440  xwin_Sudoku.prototype.gameVerify = function( ) {
0441      var a, cnt, i, ttl=1, d;
0442  
0443      // verify rows
0444      for ( i=0; i<9; i++ ) {
0445          a = [ 0,0,0,0,0,0,0,0,0 ];
0446          for ( j=0; j<9; j++ ) {
0447              x = int( "0" + domObject( this.aCell[i][j].name + "_sNum" ).innerHTML ) - 1;
0448              a[x]=1;
0449          }
0450  
0451          flag = 1;
0452          for ( j=0; j<9; j++ ) {
0453              if ( ! a[j] ) {
0454                  flag = 0;
0455                  break;
0456              }
0457          }
0458          this.gameResultsRow( i, flag );
0459          if ( ! flag ) { ttl = 0; }
0460      }
0461  
0462      // verify cols
0463      for ( i=0; i<9; i++ ) {
0464          a = [ 0,0,0,0,0,0,0,0,0 ];
0465          for ( j=0; j<9; j++ ) {
0466              x = int( "0" + domObject( this.aCell[j][i].name + "_sNum" ).innerHTML ) - 1;
0467              a[x]=1;
0468          }
0469  
0470          flag = 1;
0471          for ( j=0; j<9; j++ ) {
0472              if ( ! a[j] ) {
0473                  flag = 0;
0474                  break;
0475              }
0476          }
0477          if ( flag ) { this.gameResultsCol( i, flag ); }
0478          if ( ! flag ) { ttl = 0; }
0479      }
0480  
0481      // verify blocks
0482      a = new Array( 9 );
0483      a[0] = [ [0,0], [0,1], [0,2], [1,0], [1,1], [1,2], [2,0], [2,1], [2,2] ];
0484      a[1] = [ [3,0], [3,1], [3,2], [4,0], [4,1], [4,2], [5,0], [5,1], [5,2] ];
0485      a[2] = [ [6,0], [6,1], [6,2], [7,0], [7,1], [7,2], [8,0], [8,1], [8,2] ];
0486      a[3] = [ [0,3], [0,4], [0,5], [1,3], [1,4], [1,5], [2,3], [2,4], [2,5] ];
0487      a[4] = [ [3,3], [3,4], [3,5], [4,3], [4,4], [4,5], [5,3], [5,4], [5,5] ];
0488      a[5] = [ [6,3], [6,4], [6,5], [7,3], [7,4], [7,5], [8,3], [8,4], [8,5] ];
0489      a[6] = [ [0,6], [0,7], [0,8], [1,6], [1,7], [1,8], [2,6], [2,7], [2,8] ];
0490      a[7] = [ [3,6], [3,7], [3,8], [4,6], [4,7], [4,8], [5,6], [5,7], [5,8] ];
0491      a[8] = [ [6,6], [6,7], [6,8], [7,6], [7,7], [7,8], [8,6], [8,7], [8,8] ];
0492  
0493      for ( i=0; i<9; i++ ) {
0494          b = [ 0,0,0,0,0,0,0,0,0 ];
0495          for ( j=0; j<9; j++ ) {
0496              pt = a[i][j];
0497              x = int( "0" + domObject( this.aCell[pt[0]][pt[1]].name + "_sNum" ).innerHTML ) - 1;
0498              b[x]=1;
0499          }
0500  
0501          flag = 1;
0502          for ( j=0; j<9; j++ ) {
0503              if ( ! b[j] ) {
0504                  flag = 0;
0505                  break;
0506              }
0507          }
0508          if ( flag ) { this.gameResultsBlock( a[i], flag ); }
0509          if ( ! flag ) { ttl = 0; }
0510      }
0511  
0512      if ( ttl ) {
0513          this.gameTimer( 0 );
0514          d = new xDate( );
0515          alert( "Congratulations!  You have successfully completed the puzzle.\nYour final time was " + d.diff( d.date, this.gameStart )  );
0516      }
0517  };
0518  
0519  function clickHandler( w, e ) {
0520      sudoku.cellToggle( w );
0521  }
0522  
0523  
0524  function keyupHandler( e ) {
0525      xlib.editClearSelection( e );
0526  }
0527  
0528  function keyHandler( e ) {
0529      var k = xlib.keyGet( e );
0530  
0531      if ( sudoku.curCell    ) {
0532          switch ( k.code ) {
0533            case KEY_SPACE:
0534            case KEY_DELETE:
0535                sudoku.cellSetNum( sudoku.curCell, 0, "" );
0536                break;
0537            case KEY_TAB:
0538            case KEY_ARROWLEFT:
0539            case KEY_ARROWUP:
0540            case KEY_ARROWRIGHT:
0541            case KEY_ARROWDOWN:
0542              sudoku.cellTab( sudoku.curCell, k );
0543              break;
0544  
0545            case KEY_BACKSPACE:
0546              xlib.eventCancelBubble( e );
0547              return( xlib.eventCancel( e ) );
0548  
0549            default:
0550              if ( k.code > 48 && k.code < 58 ) {
0551                  sudoku.cellSetNum( sudoku.curCell, 0, "" + ( k.code - 48 ), 0, k );
0552              }
0553              else if ( k.code > 96 && k.code < 106 )    {
0554                  // non-shifted num-lock
0555                  sudoku.cellSetNum( sudoku.curCell, 0, "" + ( k.code - 96 ), 0, k );
0556              }
0557          }
0558  
0559          if ( k.code == KEY_TAB ) {
0560              xlib.eventCancelBubble( e );
0561              return( xlib.eventCancel( e ) );
0562          }
0563      }
0564  }