Prologue
Today I was picking up a previously abandoned LeetCode problem, the Sudoku Solver, and decided to try solving it using JavaScript since I had been writing Node.JS recently.
In my previous solution with Java, I was able to quickly get through the starting stage:
3x3 block respectively). It is worth noting that each slot also has places for holding _key-value pairs_ denoting the existence of 1 to 9.where I used two sets of nested for loop in Java to do the job: one set for initializing the 9 values inside each slot to 0 s, and another set for filling in the slots based on the given Sudoku matrix.
When trying to complete a similar task in JavaScript today, however, I introduced a seemingly clever trick, which eventually turned out to be a stupid mistake, and kept me from proceeding for over an hour.
The story began with Array.prototype.fill()
As has been mentioned, the input of this Sudoku problem was a 2D array (9 x 9), and as a normal thought, I attempted to categorize its pre-filled values into their respective rows, columns, and 3 x 3 blocks.
First things first, I declared my variables:
let slots = [new Array(9), new Array(9), new Array(9)];
So far so good.
Next, initialize slots. Normally you would (and should) use the oldschool (yet proven to be ALWAYS reliable) for loop approach for initializatoin. Contrary to this, I tried to be smart, and decided to give a shot on Array.prototype.fill(), a built-in function similar to the Arrays.fill() static method in Java’s Arrays class which fills repeating values into an array, for filling in the slots (each {} object to be assigned properties named '1' - '9' and '.' respectively):
slots[0].fill({});
slots[1].fill({});
slots[2].fill({});
My actions immediately brought a disaster whose cause I had not figured out until more than an hour later.
After having initialized my slots, I went ahead to do the categorizing of the given Sudoku matrix:
for (i = 0; i < 9; i++) {
for (j = 0; j < 9; j++) {
slots[0][i][board[i][j]] = true;
slots[1][j][board[i][j]] = true;
slots[2][3 * Math.floor(i / 3) + Math.floor(j / 3)][board[i][j]] = true;
}
}
Just to make sure it worked as I was expecting (which did not), I used console.log() to test my freshly filled-in slots on the example input
[["5","3",".",".","7",".",".",".","."],
["6",".",".","1","9","5",".",".","."],
[".","9","8",".",".",".",".","6","."],
["8",".",".",".","6",".",".",".","3"],
["4",".",".","8",".","3",".",".","1"],
["7",".",".",".","2",".",".",".","6"],
[".","6",".",".",".",".","2","8","."],
[".",".",".","4","1","9",".",".","5"],
[".",".",".",".","8",".",".","7","9"]]
and, to my astonishment, got the following output, every slot was already full with properties naming '1' - '9' and '.':
Having completely no idea why this happened, I stared at my code, modifying the categorizing for loop effortlessly, with the puzzling result remaining as ever. Here is what I was actually expecting:
It was after a relentless fight that I finally looked into the way I initialized my slots. I went to check the documentation of Array.prototype.fill() on Mozilla’s website, and in the Description section, there is this sentence:
When
fillgets passed an object, it will copy the reference and fill the array with references to that object.
So that was what caused this aftermath!
Basically, the “clever” way I initialized my slots was assigning references to the same empty object ({}) within each row, so my categorization process was not actually separating the pre-filled values into 27 different slots, but rather putting them into three single slots (one slot each row). How stupid.
For loop sweet for loop
In the end, I swithced my slots initialization process back to using a for loop, and everything went smoothly onwards as expected:
for (i = 0; i < 3; i++) {
for (j = 0; j < 9; j++) {
slots[i][j] = {};
}
}
As it turned out, for loop rocks!
Analogy to Java’s Arrays.fill()
I deemed it worth noting that this scenario also applies to Java’s Arrays.fill() and similar functionalities of other pass-by-reference programming languages, as they would also be passing unchanging references to given variables between their parentheses of fill().