13.4 Completing Sudoku Puzzle Helper
Professor: I hope you still h ave energy to finish Sudoku, which is our last project in
this course. Before doing it, let’s briefly refre sh our memory of what we produced so
far. We wrote two objects, Cell and Sudoku, and this is the list of things we need to
know to be able to continue the work:
The Sudoku() constructor creates a Sudoku object instance.
The setClues() me thod of the Sudoku object takes as an argument a 9 × 9
array of initial clues for the cells. Each clue can be either a numeric value
between on e and nine, or the null value if the cell is empty.
The setNumber() method of the Sudoku object accepts three arguments: a
number that is to be written into the puzzle, and the row and column index of
the cell into which the numb er is to be written. The method returns false if the
same number already exists in the same row, column, or 3 × 3 box. Otherwise,
it inserts the number into the puzzle grid and returns t rue.
The board property of the Sudoku object is a 9 × 9 array of references to Cell
object instances.
The getNumber() method of the Cel l object returns the number that is cur-
rently written in the cell. If the cell is empty, then the method re turns null.
The isWritable( ) method of the Cell obje ct returns true if you ca n write
numbers into the cell, and false otherwise.
Now, let’s get the job do ne. We are g oing to generate the HTML part of the p uzzle
dynamic ally, of course. Nevertheless, here is static HTML code for the puzzle grid to
get an impression of how the final document should look:
<form>
<table class="sudoku-table">
<tr>
<td><input type="text"></td>
<td><input type="text"></td>
<!-- ... -->
</tr>
<tr>
<td><input type="text"></td>
<td><input type="text"></td>
<!-- ... -->
</tr>
<!-- ... -->
</table>
</form>
The comments containing ellipses hint that parts of the code are o mitted. Everyth ing in
fact repeats verbatim nine times and the whole puzzle is simply a 9×9 table containing
text boxes inside its cells.
This is the actua l HTML that were going to use for our Sudoku:
13.4. Completing Sudoku Puzzle H elper 255
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Sudoku</title>
<link href="/styles/sudoku.css" rel="stylesheet">
<script src="/scripts/sudoku.js"></script>
</head>
<body>
<div id="sudoku-puzzle"></div>
</body>
</html>
Notice that th e code is practically the same as it was for the math worksheet generator,
and you will pro bably have guessed that the whole Sudoku puzzle goes into the only
<div> element in sid e the document body. That said, the style part is a little more
intriguing. The
sudoku.css file, to which th e above HTML refers, starts with the
following rule:
.sudoku-table {
border: 2px solid;
border-collapse: collapse;
}
This rule simply sets a border around the puzzle and eliminates space between cells.
Now comes the interesting part: we n eed to draw two additional vertical and horizontal
lines to visually separate the 3 × 3 boxes. We can do this using the :nth-child()
selector:
.sudoku-table td:nth-child(3n) {
border-right: 2px solid;
}
.sudoku-table tr:nth-child(3n) {
border-bottom: 2px solid;
}
The first of the above rules selects every third <td> child element that is a descendant
of an element whose class attribute is set to sudoku-t able, and makes its right
border solid and two pixels thick. Similarly, the second rule selects every third < tr>
child element and m akes its bottom bo rder thicker.
Mike: How exactly does the :nth-chi ld() selector work?
Professor: The :nth-child() selector accepts as an argume nt an expression of the
form a n+b , which reads: “Select every a th child starting with the b th child. For
example, suppose you want to select every secon d child, starting with the first one.
You can do that with the following selector:
256 Meeting 13. User Interface
:nth-child(2n+1)
Or, if you just want to select every second child, yo u can drop the +1 pa rt:
:nth-child(2n)
Incidenta lly, you can achieve the same ee ct using the keywords odd and even instead
of 2n+1 and 2n.
When y ou place another selector directly before this selector—without any space, that
is—then yo u limit the :nt h-child() selector only to children that match that other
selector as well. Therefore, the expression td:nth-child(3n) only selects every
third child that is at th e same time a <td> elem ent.
Maria: But <td> is a child of a row, not a child of a table.
Professor: Wha t do you mean?
Maria: I don’t understand this rule:
.sudoku-table td:nth-child(3n) {
border-right: 2px solid;
}
A < td> element cannot be a child of a table.
Professor: Oh, I see your point. Th e above rule u ses a d escendant selector, all
right. However, :nth-chi ld() itself does not imply children of any specific ele-
ment. When used alone, it simply refers to any children. You should read the above
rule as: “Selec t every third child that is a <td> element, and is at the same time a de-
scendant of an element with the c lass attribute set to sudoku-table. You should
not understand it as: “Select every third child of the element with the class attribute
set to sudoku- table. This is a big dierence.
The
sudoku.css file continues with the fo llowing two rules, which format th e <td>
and < input> elements w ithin a Sudoku table:
.sudoku-table td {
width: 2em;
height: 2em;
}
.sudoku-table input {
width: inherit;
height: inherit;
text-align: center;
font-size: 2em;
}
13.4. Completing Sudoku Puzzle H elper 257
Note that, by default, the properties width a nd height are not inherited. That’s
why I used the inherit keyword to force the <input> element to inherit these two
properties from its parent, which is <td> in our case.
Mike: Why didn’t you simply set the size of the <input> element?
Professor: If I did that, then it wouldn’t be po ssible to set font size of th e <input>
element without also aecting the size of the <input> element itself. Remember
that the em unit is relative to the size of the font of the element itself, rather than its
containing bloc k. I could have, o f course, used other units but then the cell wouldn’t
resize accordingly if the base fo nt would change.
Mike: I still don’t see the p roblem.
Professor: If font size were the same for all <input> elements then this indeed
wouldn’t be a problem. However, we will later set smaller f ont size for the elements
displaying solution candida te s.
Mike: Oh, I see.
The last four rules take care of the appearance of numbers to reflect th eir meaning.
The numbers that represent the initial clue will be shown as black and in bold, the
numbers entered by the user as answers will be shown gray, the numbers en te red by
the user tha t are not placed accord ing to the rules will be colored red , a nd the solution
candidates will be rendered smaller than normal numbers:
.sudoku-table .clue {
color: black;
font-weight: bold;
}
.sudoku-table .answer {
color: gray;
}
.sudoku-table .wrong {
color: red;
}
.sudoku-table .candidate {
font-size: .7em;
}
This com pletes the styling portion of our project and we’re ready for the JavaScript
part. We are g oing to add another method to the Sudoku class called start(), whose
job will be twofold: to build the appropriate document structure an d to con nect the
oninput handlers of all the <input> elements to the event-ha ndler function that
we’re going to write later. The inpu t event is triggered every time when the value
of the <inp ut> elem ent changes, which is just perfect for us because we’ll be able to
react upon every change inside the puzzle gr id. These are the first lines of the start()
method:
258 Meeting 13. User Interface
Sudoku.prototype.start = function(id) {
var row, cell, text, number;
var puzzleContainer = document.getElementById(id);
var form = document.createElement("form");
var puzzle = document.createElement("table");
puzzle.className = "sudoku-table";
puzzleContainer.appendChild(form);
form.appendChild(puzzle)
//...
The method accepts a single argument, which is the ID of the HTML element that
will contain the wh ole puzzle. The code begins with som e local variable declarations,
followed by getting the puzzle co ntainer. The last five lines create Element objects
representin g a form and table, and insert the created elements into the document tree.
We can now create rows and table cells and appen d them to the table object puzzle.
The following two nested for loops do this:
//...
for (i = 0; i < 9; i++) {
row = document.createElement("tr");
puzzle.appendChild(row);
for (j = 0; j < 9; j++) {
cell = document.createElement("td");
row.appendChild(cell);
text = document.createElement("input");
text.type = "text";
text.className = "answer";
cell.appendChild(text);
//...
The code is nothin g special, really. It creates nin e table rows and appends them to
puzzle. Before going back to create the next row, the current row is filled with nine
table cells, each co ntaining a text box.
After each of the text boxes has been created and put in plac e, it’s time to write a
number into it. The next code fragment puts a clue into a corresponding text box if
the cell is read-only and he nce includes an initial clue. Of course, it also sets the
appropriate value for the class attribute and prevents the user from changing the
contents of the text box by spe cifying the readonl y attribute:
//...
if (!this.board[i][j].isWritable()) {
text.value = this.board[i][j].getNumber();
text.className = "clue";
text.readOnly = true;
}
//...
13.4. Completing Sudoku Puzzle H elper 259
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.201.47