Sunday, May 29, 2011

DDTe2 hours 14 to 15 Fine Tuning

This is the second to last article for my series on the creation of Dozen Days of Tiles episode 2: Sudoku Generator. Earlier posts covered the creation and hiding of the puzzle. The final game is on Blazing Games and is located at http://blazinggames.com/table/dozenDays/tiles/sudokuGen.php.

To support multiple puzzles with the Sudoku Player, the URL has a data parameter that contains 81 characters that represent the puzzle data. The .php page has code that converts the letters into the initial board data statements that the player uses. This coding uses letters to represent the numbers with the letters being in a random order to make it really difficult for a human to look at the URL and figure out the solution to the puzzle. To generate this encoding, I wrote a simple function to convert the grid into a 81 character encoded string.

SudokuGen.ENCODE = "JBLAKIRNEFPSMCOGDTQH";
SudokuGen.Model.prototype.getEncoded = function()
{
   var encode = "";
   var value, cntrRow, cntrCol;

   for (cntrRow = 1; cntrRow < 10; ++cntrRow)
       for (cntrCol = 1; cntrCol < 10; ++cntrCol) {
           value = this.tileGrid[cntrRow][cntrCol];
           if (this.lockGrid[cntrRow][cntrCol] == true)
               value += 10;
           encode += SudokuGen.ENCODE.substr(value, 1);
       }
      
   return encode;
}

Just being able to use the player isn’t quite enough. I also want to make the puzzles printable so that they can be printed out on paper to be solved.  As the puzzle really is just nested tables, this can be done entirely with the HTML table tags. This requires working with the awful DOM classes, but really is fairly simple. Essentially, the puzzle is a 3x3 table with each table in the puzzle being a 3x3 table that contains the group data.

function writePuzzle(model)
{
   var puzzle = document.getElementById('puzzle');
   var cntrRow, cntrCol, cntrGroup, cntrSec;
   var groupTable, temp, grow, gcell;
  
   // top three groups
   for (cntrSec = 0; cntrSec < 3; ++cntrSec) {
       prow = puzzle.insertRow(cntrSec);
       for (cntrGroup = 0; cntrGroup < 3; ++cntrGroup) {
           pcell = prow.insertCell(cntrGroup);
           groupTable = document.createElement("table");
           groupTable.border = "1";
           groupTable.cellPadding = "5";
           for (var cntrRow = 0; cntrRow < 3; ++cntrRow) {
               grow = groupTable.insertRow(cntrRow);
               for (var cntrCol = 0; cntrCol < 3; ++cntrCol) {
                   gcell = grow.insertCell(cntrCol);
                   temp = model.getPuzzleValue(cntrRow+cntrSec*3+1, cntrCol+cntrGroup*3+1);
                   if (temp > 10)
                       gcell.innerHTML = "" + (temp - 10);
                   else
                       gcell.innerHTML += " ";
               }
           }
          
           pcell.appendChild(groupTable);           
       }
   }
  
   var msg = document.getElementById('waitText');
    msg.innerHTML = ""+ playerMessage + "";

}

As generating the puzzle can take some time, my final touch was a please wait message which is animated as the generation passes happen. When the generation is done, this gets replaced by the Sudoku Player URL.

Of course, this is the point when I discover a game-stopper bug. It seems that occasionally the puzzle generation locks up. If you have been following along with this series of articles, you already know that the problem was my next phase being prematurely set allowing an occasional invalid game to be treated as a valid puzzle. This was a very easy bug to fix but a bit harder to figure out. In fact, I had a working fix in a matter of minutes but it took me a couple of hours to actually figure out what the real problem was. That story will be told next week.

No comments: