Sudoku is a fascinating puzzle that challenges our logic and problem-solving skills. Building a Sudoku checker can be an exciting project for developers looking to sharpen their JavaScript abilities and enhance their understanding of algorithms. In this tutorial, we’ll walk through the process of creating a simple yet effective Sudoku checker using JavaScript.
Understanding the Sudoku Puzzle
Before diving into coding, it’s essential to understand the structure of a Sudoku puzzle. A standard Sudoku grid consists of a 9×9 board, divided into nine 3×3 subgrids, known as boxes. The objective of the game is to fill in the grid with numbers from 1 to 9, ensuring that each number appears exactly once in each row, column, and box. This makes it a great candidate for using arrays and nested loops in JavaScript.
To create our Sudoku checker, we need a way to represent the board in our code. We can use a two-dimensional array (an array of arrays) for this purpose. Each inner array will represent a row on the Sudoku board, and the values will be the numbers filled in by the player or zero for empty cells. With this in mind, let’s outline the logic we’ll implement in our checker.
Our Sudoku checker will perform the following tasks:
- Validate numbers in each row
- Validate numbers in each column
- Validate numbers in each 3×3 box
By ensuring each of these conditions is met, we can ascertain whether the Sudoku board is valid or not.
Setting Up the Project
For this project, we’ll create a simple HTML file with a JavaScript section. You can use any code editor, such as VS Code or WebStorm, and follow along. Here’s a basic outline for our HTML setup:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sudoku Checker</title>
</head>
<body>
<h1>Sudoku Checker</h1>
<script>
// JavaScript code will go here
</script>
</body>
</html>
This HTML structure sets up a foundation for our Sudoku checker. Next, we will implement the JavaScript logic to validate the Sudoku board.
Implementing the Sudoku Checker Logic
We’ll create a function called `isValidSudoku(board)` that takes a 9×9 array as an input and returns true or false based on whether the board is valid. Here’s how we can structure our code:
function isValidSudoku(board) {
// Check rows, columns, and boxes
}
Now, we need to loop through each row, column, and box to verify that each number from 1 to 9 appears only once. Here’s how we can achieve that:
We’ll start with validating the rows. We’ll create a helper function, `isUnique`, that checks if numbers in a given array are unique and not equal to zero:
function isUnique(array) {
const seen = new Set();
for (let number of array) {
if (number !== 0) { // Ignore empty cells
if (seen.has(number)) {
return false;
}
seen.add(number);
}
}
return true;
}
With the `isUnique` function, we can check each row by iterating through the board:
for (let row of board) {
if (!isUnique(row)) {
return false;
}
}
After ensuring rows are valid, we’ll validate the columns similarly. We can extract each column by iterating over the index values of rows:
for (let col = 0; col < 9; col++) {
const column = board.map(row => row[col]);
if (!isUnique(column)) {
return false;
}
}
Lastly, we will check the 3×3 boxes. The 3×3 boxes can be iterated through nested loops. Here’s how it looks:
for (let boxRow = 0; boxRow < 3; boxRow++) {
for (let boxCol = 0; boxCol < 3; boxCol++) {
const box = [];
for (let row = 0; row < 3; row++) {
for (let col = 0; col < 3; col++) {
box.push(board[boxRow * 3 + row][boxCol * 3 + col]);
}
}
if (!isUnique(box)) {
return false;
}
}
}
With this complete, our `isValidSudoku` function should look like this:
function isValidSudoku(board) {
for (let row of board) {
if (!isUnique(row)) {
return false;
}
}
for (let col = 0; col < 9; col++) {
const column = board.map(row => row[col]);
if (!isUnique(column)) {
return false;
}
}
for (let boxRow = 0; boxRow < 3; boxRow++) {
for (let boxCol = 0; boxCol < 3; boxCol++) {
const box = [];
for (let row = 0; row < 3; row++) {
for (let col = 0; col < 3; col++) {
box.push(board[boxRow * 3 + row][boxCol * 3 + col]);
}
}
if (!isUnique(box)) {
return false;
}
}
}
return true;
}
This function will now check the board and return whether it’s a valid Sudoku configuration. Let’s now see how to use this function in practice.
Testing the Sudoku Checker
Now that we have our Sudoku checking logic implemented, we need to test it with different board configurations. Let’s set up a few test cases:
const validBoard = [
[5, 3, 0, 0, 7, 0, 0, 0, 0],
[6, 0, 0, 1, 9, 5, 0, 0, 0],
[0, 9, 8, 0, 0, 0, 0, 6, 0],
[8, 0, 0, 0, 6, 0, 0, 0, 3],
[4, 0, 0, 8, 0, 3, 0, 0, 1],
[7, 0, 0, 0, 2, 0, 0, 0, 6],
[0, 6, 0, 0, 0, 0, 2, 8, 0],
[0, 0, 0, 4, 1, 9, 0, 0, 5],
[0, 0, 0, 0, 8, 0, 0, 7, 9]
];
console.log(isValidSudoku(validBoard)); // Output: true
const invalidBoard = [
[5, 3, 0, 0, 7, 0, 0, 0, 0],
[6, 5, 0, 1, 9, 5, 0, 0, 0],
[0, 9, 8, 0, 0, 0, 0, 6, 0],
[8, 0, 0, 0, 6, 0, 0, 0, 3],
[4, 0, 0, 8, 0, 3, 0, 0, 1],
[7, 0, 0, 0, 2, 0, 0, 0, 6],
[0, 6, 0, 0, 0, 0, 2, 8, 0],
[0, 0, 0, 4, 1, 9, 0, 0, 5],
[0, 0, 0, 0, 8, 0, 0, 7, 9]
];
console.log(isValidSudoku(invalidBoard)); // Output: false
Here we have defined a valid Sudoku board and an invalid one. When running this code, you should see the correct validation results in your console, confirming that our checker works as intended.
Improving the User Experience
Now that we have a functional Sudoku checker, we can enhance the user experience by creating a simple user interface (UI) that allows users to submit their Sudoku boards and receive feedback on their validity. This can be done using HTML forms and JavaScript event listeners.
Below is a basic example of how we can structure the UI:
<form id="sudoku-form">
<table>
<tbody>
<tr>
<td><input type="number" min="0" max="9"></td>
<td><input type="number" min="0" max="9"></td>
...
<td><input type="number" min="0" max="9"></td>
</tr>
</tbody>
</table>
<button type="submit">Check Sudoku