// Copyrighted, 2007, by Michael McElroy of MichaelMcElroy.NET. All rights are reserved. var scaffoldPredicate = false; var Square = function () { // Identity this . reference = null; this . ID = null; // Settings this . symbolQuantity = null; this . rowQuantity = null; this . columnQuantity = null; this . regionDivisor = null; this . squareHeight = null; this . squareWidth = null; this . hintQuantity = null; this . entryColor = null; this . puzzleColor = null; this . solutionColor = null; this . emptyColor = null; // Status this . solvedPredicate = null; this . puzzle = null; this . entries = null; // Graphics this . renderTarget = null; this . node = null; this . nodes = null; this . glass = null; // Delegates this . incrementValueDelegate = null; this . t_incrementValueDelegate = null; this . initialize = function (reference, ID) { this . initializeIdentity (reference, ID); this . initializeSettings (); this . initializeStatus (); this . initializeGraphics (); this . initializeDelegates (); this . render (); this . registerDelegates (); return; }; this . initializeIdentity = function (reference, ID) { this . reference = reference; this . ID = ID; return; }; this . initializeSettings = function () { this . symbolQuantity = 9; this . rowQuantity = 9; this . columnQuantity = 9; this . regionDivisor = 3; this . squareHeight = 48; this . squareWidth = 48; this . hintQuantity = 40; this . entryColor = "#003377"; this . puzzleColor = "#333333"; this . solutionColor = "#007733"; this . emptyColor = "#ffffff"; return; }; this . initializeStatus = function () { this . solvedPredicate = false; this . puzzle = new Array (); this . entries = new Array (); for (var rowIndex = 0; rowIndex < this . rowQuantity; rowIndex = rowIndex + 1) { this . puzzle [rowIndex] = new Array (); this . entries [rowIndex] = new Array (); } this . initializePuzzle (); this . initializeEntries (); return; }; this . initializeGraphics = function () { var node; var table; var tr; var td; var border; // Render Target this . renderTarget = null; // Node this . node = document . createElement ("div"); this . node . style . zIndex = "0"; this . node . style . position = "relative"; this . node . style . height = (this . squareHeight * this . rowQuantity) + "px"; this . node . style . width = (this . squareWidth * this . columnQuantity) + "px"; this . node . style . border = "#ecece2 0px solid"; // Cells this . nodes = new Array (); for (var rowIndex = 0; rowIndex < this . rowQuantity; rowIndex = rowIndex + 1) { this . nodes [rowIndex] = new Array (); for (var columnIndex = 0; columnIndex < this . columnQuantity; columnIndex = columnIndex + 1) { node = document . createElement ("div"); node . style . zIndex = "0"; node . style . position = "absolute"; node . style . top = (this . squareHeight * rowIndex) + "px"; node . style . left = (this . squareWidth * columnIndex) + "px"; node . style . height = (this . squareHeight) + "px"; node . style . width = (this . squareWidth) + "px"; table = document . createElement ("table"); table . style . height = "100%"; table . style . width = "100%"; tr = document . createElement ("tr"); td = document . createElement ("td"); td . style . height = "100%"; td . style . width = "100%"; td . style . backgroundColor = "#ffffff"; td . style . verticalAlign = "middle"; td . style . textAlign = "center"; td . style . fontSize = "24px"; td . style . color = "#ffffff"; td . cache = new Object (); td . cache . color = ""; td . cache . value = ""; this . node . appendChild (node); node . appendChild (table); table . appendChild (tr); tr . appendChild (td); this . nodes [rowIndex] [columnIndex] = td; } } // Minor Borders for (var rowIndex = 0; rowIndex < this . rowQuantity; rowIndex = rowIndex + 1) for (var columnIndex = 0; columnIndex < this . columnQuantity; columnIndex = columnIndex + 1) { border = document . createElement ("div"); border . style . zIndex = "1"; border . style . position = "absolute"; border . style . top = (this . squareHeight * rowIndex) + "px"; border . style . left = (this . squareHeight * columnIndex) + "px"; border . style . height = (this . squareHeight) + "px"; border . style . width = (this . squareWidth) + "px"; border . style . border = "#eeeeee 1px solid"; this . node . appendChild (border); } // Major Borders for (var rowIndex = 0; rowIndex < (this . rowQuantity / this . regionDivisor); rowIndex = rowIndex + 1) for (var columnIndex = 0; columnIndex < (this . columnQuantity / this . regionDivisor); columnIndex = columnIndex + 1) { border = document . createElement ("div"); border . style . zIndex = "2"; border . style . position = "absolute"; border . style . top = ((this . squareHeight * (this . rowQuantity / this . regionDivisor)) * rowIndex) + "px"; border . style . left = ((this . squareWidth * (this . columnQuantity / this . regionDivisor)) * columnIndex) + "px"; border . style . height = (this . squareHeight * (this . rowQuantity / this . regionDivisor)) + "px"; border . style . width = (this . squareWidth * (this . columnQuantity / this . regionDivisor)) + "px"; border . style . border = "#c3c0b8 1px solid"; this . node . appendChild (border); } // Outer Border border = document . createElement ("div"); border . style . zIndex = "2"; border . style . position = "absolute"; border . style . top = "1px"; border . style . left = "1px"; border . style . height = (this . squareHeight * this . rowQuantity - 2) + "px"; border . style . width = (this . squareWidth * this . columnQuantity - 2) + "px"; border . style . border = "#c3c0b8 1px solid"; this . node . appendChild (border); // Glass this . glass = document . createElement ("div"); this . glass . style . zIndex = "3"; this . glass . style . position = "absolute"; this . glass . style . top = "0px"; this . glass . style . left = "0px"; this . glass . style . height = (this . squareHeight * this . rowQuantity) + "px"; this . glass . style . width = (this . squareWidth * this . columnQuantity) + "px"; this . node . appendChild (this . glass); return; }; this . initializeDelegates = function () { this . incrementValueDelegate = new Delegate (); this . incrementValueDelegate . initialize (); this . incrementValueDelegate . setEntity (this); this . incrementValueDelegate . setMethod (this . incrementValue); this . t_incrementValueDelegate = new Delegate (); this . t_incrementValueDelegate . initialize (); this . t_incrementValueDelegate . setEntity (this); this . t_incrementValueDelegate . setMethod (this . t_incrementValue); return; }; this . initializePuzzle = function () { var puzzles; var randomNumber; var randomNumbers; var symbolMap; var symbol; puzzles = new Array (); // puzzles [ 0] = "690307041400000800102904000003009506500000070800501403020005018060103050701800902"; // puzzles [ 1] = "508003090900208004030901002003080010409005008701090240070640801045002700806010403"; // puzzles [ 2] = "008010400904070030030040702300800907090001008002007050203009000470060803000704001"; // puzzles [ 3] = "300050098009030400050900230030070000078024069920508007063095104205060983790803602"; // puzzles [ 4] = "709103006005060280040080107360910720000230091921078005402091063600802904890340502"; // puzzles [ 5] = "070106003001030520350204107465000032007302608830067090020400016003600009910070240"; // puzzles [ 6] = "302400507050070089070508000504090708960003140018700096000257901095030072700901450"; // puzzles [ 7] = "900710080060008407008690010059001268810059000200806109000185940091060023600902500"; // puzzles [ 8] = "010408060605090308000063040026109005050720896800006400032010084060802050907040103"; // puzzles [ 9] = "000400062130260490000009500254098013000500249091004800400350071000801620016070304"; // puzzles [10] = "003501009950040060041602503000000410605020087704308906030000090000239108089000702"; // puzzles [ 0] = "050900400900000200200003060000016700000407000003280000090100005006000004007002080"; puzzles [ 0] = "801200603070064000000090000602000805000000000403000201000030000000570020506001709"; puzzles [ 1] = "200700003001050009060080405006900000305000204000005300603070040400090700500008002"; puzzles [ 2] = "000090100030180045067005000640000003000000000800000029000500360410026050006070000"; puzzles [ 3] = "040090105006002094800000000500401000090000020000907006000000003620500800708060050"; randomNumber = Math . floor (Math . random () * puzzles . length); if (scaffoldPredicate) { puzzles [puzzles . length] = "023456789456789123789123456234567891567891234891234567345678912678912345912345678"; randomNumber = puzzles . length - 1; } for (var blockRowIndex = 0; blockRowIndex < (this . rowQuantity / 3); blockRowIndex = blockRowIndex + 1) for (var blockColumnIndex = 0; blockColumnIndex < (this . columnQuantity / 3); blockColumnIndex = blockColumnIndex + 1) { for (var rowIndex = 0; rowIndex < (this . rowQuantity / 3); rowIndex = rowIndex + 1) for (var columnIndex = 0; columnIndex < (this . columnQuantity / 3); columnIndex = columnIndex + 1) { this . puzzle [blockRowIndex * 3 + rowIndex] [blockColumnIndex * 3 + columnIndex] = puzzles [randomNumber] . substring (blockRowIndex * 27 + rowIndex * 9 + blockColumnIndex * 3 + columnIndex, blockRowIndex * 27 + rowIndex * 9 + blockColumnIndex * 3 + columnIndex + 1); } } symbolMap = new Array (1, 2, 3, 4, 5, 6, 7, 8, 9); randomNumber = Math . floor (Math . random () * 25) + 50; randomNumbers = new Array (); for (var index = 0; index < randomNumber; index = index + 1) { randomNumbers [0] = Math . floor (Math . random () * symbolMap . length); randomNumbers [1] = Math . floor (Math . random () * symbolMap . length); symbol = symbolMap [randomNumbers [0]]; symbolMap [randomNumbers [0]] = symbolMap [randomNumbers [1]]; symbolMap [randomNumbers [1]] = symbol; } for (var rowIndex = 0; rowIndex < this . rowQuantity; rowIndex = rowIndex + 1) for (var columnIndex = 0; columnIndex < this . columnQuantity; columnIndex = columnIndex + 1) { if (this . puzzle [rowIndex] [columnIndex] != 0) { this . puzzle [rowIndex] [columnIndex] = symbolMap [this . puzzle [rowIndex] [columnIndex] - 1]; } } return; }; this . initializeEntries = function () { for (var rowIndex = 0; rowIndex < this . rowQuantity; rowIndex = rowIndex + 1) for (var columnIndex = 0; columnIndex < this . columnQuantity; columnIndex = columnIndex + 1) { this . entries [rowIndex] [columnIndex] = this . puzzle [rowIndex] [columnIndex]; } return; }; this . reset = function () { this . initializeStatus (); this . render (); return; }; this . setRenderTarget = function (node) { this . renderTarget = node; this . renderTarget . appendChild (this . node); return; }; this . t_incrementValue = function (touch_events) { if (touch_events . touches . length == 1) { touch_events . preventDefault (); this . incrementValue (touch_events . touches [0]); } return; }; this . incrementValue = function (cursorEvent) { var rowCoordinate; var columnCoordinate; if (! this . solvedPredicate) { rowCoordinate = Math . floor (this . getRowCoordinate (cursorEvent) / this . squareHeight); columnCoordinate = Math . floor (this . getColumnCoordinate (cursorEvent) / this . squareWidth); if (this . puzzle [rowCoordinate] [columnCoordinate] == 0) { var value; value = this . entries [rowCoordinate] [columnCoordinate] + 1; value = value % 10; this . entries [rowCoordinate] [columnCoordinate] = value; } if (this . getValidSolutionPredicate (this . entries)) { this . solvedPredicate = true; this . unregisterDelegates (); } this . render (); } cursorEvent . stopPropagation (); cursorEvent . preventDefault (); return (false); }; this . getValidSolutionPredicate = function (solution) { var solvedPredicate; var rowPredicates; var columnPredicates; var regionPredicates; solvedPredicate = true; // Assume the puzzle is solved, and try to prove otherwise. rowPredicates = new Array (); columnPredicates = new Array (); regionPredicates = new Array (); for (var index = 0; index < this . symbolQuantity; index = index + 1) { rowPredicates [index] = new Array (); columnPredicates [index] = new Array (); regionPredicates [index] = new Array (); for (var symbolIndex = 0; symbolIndex < this . symbolQuantity; symbolIndex = symbolIndex + 1) { rowPredicates [index] [symbolIndex] = 0; columnPredicates [index] [symbolIndex] = 0; regionPredicates [index] [symbolIndex] = 0; } } for (var rowIndex = 0; rowIndex < this . rowQuantity; rowIndex = rowIndex + 1) for (var columnIndex = 0; columnIndex < this . columnQuantity; columnIndex = columnIndex + 1) { value = solution [rowIndex] [columnIndex] - 1; if (value >= 0) { rowPredicates [rowIndex] [value] = 1; columnPredicates [columnIndex] [value] = 1; regionPredicates [Math . floor (rowIndex / this . regionDivisor) * this . regionDivisor + Math . floor (columnIndex / this . regionDivisor)] [value] = 1; } } for (var index = 0; index < this . symbolQuantity; index = index + 1) for (var symbolIndex = 0; symbolIndex < this . symbolQuantity; symbolIndex = symbolIndex + 1) { if (rowPredicates [index] [symbolIndex] == 0) { solvedPredicate = false; } if (columnPredicates [index] [symbolIndex] == 0) { solvedPredicate = false; } if (regionPredicates [index] [symbolIndex] == 0) { solvedPredicate = false; } } return (solvedPredicate); }; this . render = function () { var color; var value; for (var rowIndex = 0; rowIndex < this . rowQuantity; rowIndex = rowIndex + 1) for (var columnIndex = 0; columnIndex < this . columnQuantity; columnIndex = columnIndex + 1) { if (this . puzzle [rowIndex] [columnIndex] != 0) { color = this . puzzleColor; value = this . puzzle [rowIndex] [columnIndex]; } else { if (this . getValidSolutionPredicate (this . entries)) // Render the solution. { color = this . solutionColor; value = this . entries [rowIndex] [columnIndex]; } else // Render the entry. { if (this . entries [rowIndex] [columnIndex] == 0) { color = this . emptyColor; value = ""; } else // Render the entry. { color = this . entryColor; value = this . entries [rowIndex] [columnIndex]; } } } // The color and value are cached in each node to prevent flickering. if ((this . nodes [rowIndex] [columnIndex] . cache . color != color) || ((this . nodes [rowIndex] [columnIndex] . cache . value != value))) { this . clearNodes (this . nodes [rowIndex] [columnIndex]); this . nodes [rowIndex] [columnIndex] . style . color = color; this . nodes [rowIndex] [columnIndex] . appendChild (document . createTextNode (value)); this . nodes [rowIndex] [columnIndex] . cache . color = color; this . nodes [rowIndex] [columnIndex] . cache . value = value; } } return; }; this . registerDelegates = function () { this . incrementValueDelegate . register (this . glass, "mousedown"); this . t_incrementValueDelegate . register (this . glass, "touchstart"); return; }; this . unregisterDelegates = function () { this . incrementValueDelegate . unregister (this . glass, "mousedown"); this . t_incrementValueDelegate . unregister (this . glass, "touchstart"); return; }; this . getRowCoordinate = function (cursorEvent) { var rowCoordinate; rowCoordinate = null; if (typeof (event) != "undefined") if (typeof (event . offsetY) != "undefined") { rowCoordinate = event . offsetY; } if (typeof (cursorEvent) != "undefined") if (typeof (cursorEvent . layerY) != "undefined") { rowCoordinate = cursorEvent . layerY; } return (rowCoordinate); }; this . getColumnCoordinate = function (cursorEvent) { var columnCoordinate; columnCoordinate = null; if (typeof (event) != "undefined") if (typeof (event . offsetX) != "undefined") { columnCoordinate = event . offsetX; } if (typeof (cursorEvent) != "undefined") if (typeof (cursorEvent . layerX) != "undefined") { columnCoordinate = cursorEvent . layerX; } return (columnCoordinate); }; this . clearNodes = function (node) { while (node . hasChildNodes ()) { node . removeChild (node . firstChild); } return; }; }; // Entity function Entity () {} Entity . prototype . superclass = null; // Methods Entity . prototype . initialize = function () { return; }; Entity . prototype . graft = function (that) { var property; // Copy each property from 'this' to 'that'. for (property in this) { if (typeof (that [property]) == "undefined") { that [property] = this [property]; } } // Assign a superclass to each function in 'that'. for (property in that) { if (typeof (that [property]) == "function") { that [property] . superclass = this; } } return; }; // Delegate function Delegate () {} Delegate . prototype . superclass = Entity . prototype; // Members Delegate . prototype . proxy = null; Delegate . prototype . entity = null; Delegate . prototype . method = null; // Methods Delegate . prototype . act = function () { return (this . proxy . apply (this, arguments)); }; Delegate . prototype . getProxy = function () { return (this . proxy); }; Delegate . prototype . setEntity = function (entity) { this . entity = entity; this . updateProxy (); return; }; Delegate . prototype . setMethod = function (method) { this . method = method; this . updateProxy (); return; }; Delegate . prototype . updateProxy = function () { var entity; var method; entity = this . entity; method = this . method; if ((entity != null) && (method != null)) { this . proxy = function () {return (method . apply (entity, arguments));}; } else { this . proxy = function () {return;}; } return; }; Delegate . prototype . register = function (entity, event) { if (entity . addEventListener) { entity . addEventListener (event, this . getProxy (), false); } else if (entity . attachEvent) { entity . attachEvent ("on" + event, this . getProxy ()); } else { entity ["on" + event] = this . getProxy (); } return; }; Delegate . prototype . unregister = function (entity, event) { if (entity . removeEventListener) { entity . removeEventListener (event, this . getProxy (), false); } else if (entity . detatchEvent) { entity . detachEvent ("on" + entity, this . getProxy ()); } else if (entity ["on" + event] == this . getProxy ()) { entity ["on" + event] = null; } return; }; Delegate . prototype . superclass . graft (Delegate . prototype);