jazelevator.com

How to Validate Sudoku Solutions in JavaScript Efficiently

Written on

Chapter 1: Introduction to Sudoku Validation

The problem at hand is quite intriguing, particularly for those of us keen on mastering it. We are delving into the domain of JavaScript, working with two-dimensional arrays, and engaging with puzzles. In essence, our task is to check a grid filled with numbers and confirm that every row, column, and 3x3 block includes each digit from 1 to 9 exactly once. This means no duplicates or omissions are allowed. Given the vast possibilities, a rapid algorithm is essential for solving the problem efficiently.

The Challenge: Validating Sudoku Solutions

Sudoku grid example

Understanding Sudoku

Sudoku is typically played on a 9x9 grid, where the objective is to fill every cell with digits from 1 to 9. Each column, row, and the nine 3x3 sub-grids (or blocks) must contain all digits from 1 to 9 without repetition. For more details, you can refer to the Wikipedia page on Sudoku.

The Validation Function

To determine if a Sudoku board is a valid solution, we need to create a function called validSolution(). This function will take a 2D array representing a Sudoku board and return true if the solution is valid, and false if it isn't. It’s important to note that the board may contain zeros, which signify empty cells; any board with one or more zeroes is deemed invalid.

Example Inputs

validSolution([

[5, 3, 4, 6, 7, 8, 9, 1, 2],

[6, 7, 2, 1, 9, 5, 3, 4, 8],

[1, 9, 8, 3, 4, 2, 5, 6, 7],

[8, 5, 9, 7, 6, 1, 4, 2, 3],

[4, 2, 6, 8, 5, 3, 7, 9, 1],

[7, 1, 3, 9, 2, 4, 8, 5, 6],

[9, 6, 1, 5, 3, 7, 2, 8, 4],

[2, 8, 7, 4, 1, 9, 6, 3, 5],

[3, 4, 5, 2, 8, 6, 1, 7, 9],

]); // => true

validSolution([

[5, 3, 4, 6, 7, 8, 9, 1, 2],

[6, 7, 2, 1, 9, 0, 3, 4, 8],

[1, 0, 0, 3, 4, 2, 5, 6, 0],

[8, 5, 9, 7, 6, 1, 0, 2, 0],

[4, 2, 6, 8, 5, 3, 7, 9, 1],

[7, 1, 3, 9, 2, 4, 8, 5, 6],

[9, 0, 1, 5, 3, 7, 2, 1, 4],

[2, 8, 7, 4, 1, 9, 6, 3, 5],

[3, 0, 0, 4, 8, 1, 1, 7, 9],

]); // => false

Chapter 2: Crafting the Solution

In this section, I will share my approach to solving the Sudoku validation problem. While it may not be the most efficient solution on platforms like CodeWars, it prioritizes readability.

The Core Functions

To begin, we need a check function that verifies two conditions:

  1. Each section of the Sudoku board should not contain the number zero.
  2. Each section must have all digits from 1 to 9.

We can utilize the Array.includes() method to check for the presence of zero:

const checkZero = (arr) => !arr.includes(0);

To ascertain the presence of all required numbers, we have two methods:

  1. Remove duplicates using a Set() and check if the new array has 9 elements.
  2. Verify that the sum of the elements in the array equals 45, which is the sum of numbers from 1 to 9.

const checkSum = (arr) => arr.reduce((r, x) => r + x, 0) === 45;

Next, we need to identify the sections of the Sudoku that require validation. This includes checking all rows in the original configuration:

const listSolutions = (arr) => [...arr];

To get the columns, we can rotate the matrix by 90 degrees, turning columns into arrays:

const rotate = (arr) => arr[0].map((_, i) => arr.map((_, j) => arr[j][i]));

const listSolutions = (arr) => [...arr, ...rotate(arr)];

Determining the different quadrants of the Sudoku requires a unique approach, which can be handled with a loop:

const blocks = (arr) =>

arr.map((_, x) =>

arr.map((_, y) => arr[~~(x / 3) * 3 + ~~(y / 3)][(x % 3) * 3 + (y % 3)])

);

Ultimately, we can compile all the rows that need checking:

const listSolutions = (arr) => [...arr, ...rotate(arr), ...blocks(arr)];

const validSolution = (board) =>

listSolutions(board).every((x) => validateRow(x.flat()));

Refining the Code

Although this solution works, it can be streamlined further. For instance, we can simplify the blocks function:

const blocks = (arr) =>

divide(rotate(divide(arr)))

.map((x) => x.map((y) => y.flat()))

.flat();

We can also enhance the validSolution function:

const validSolution = (board) =>

!listSolutions(board)

.map((x) => checkZero(x) && checkSum(x))

.includes(false);

With closer inspection, we can eliminate any unnecessary checks for negative numbers:

const checkZero = (arr) => arr.every((x) => x > 0 && x <= 9);

Finally, let's simplify the overall checking process:

const validSolution = (board) =>

listSolutions(board).every((x) => validateRow(x.flat()));

This approach keeps the code clean and easy to follow, ensuring that the validations are thorough and efficient.

For further insights, check out the video titled "leetCode 36 Valid Sudoku | JSer - algorithm and JavaScript" which details the algorithm used for Sudoku validation.

Additionally, you might find the video "How to Code a Sudoku Solver in Javascript" helpful for understanding the coding techniques in depth.

In conclusion, this method not only validates Sudoku solutions effectively but also emphasizes code readability for future reference. Thank you for reading! Stay tuned for more insightful articles.

Don't forget to subscribe to my Medium email list for updates. More content is available at PlainEnglish.io. Connect with us on Twitter, LinkedIn, YouTube, and Discord to stay informed.