sudoku-pro 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/license +20 -0
- package/package.json +47 -0
- package/sudoku-pro.js +185 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# sudoku-pro: Sudoku Generator and Sudoku Solver
|
|
2
|
+
|
|
3
|
+
sudoku-pro is a Node.js package that provides functionalities to generate, solve, and print Sudoku puzzles of varying difficulty levels using the backtracking algorithm. It offers an easy-to-use interface to create Sudoku puzzles for entertainment and educational purposes. The main idea behind this package was to test the potential of the backtracking algorithm for generating Sudoku puzzles of different difficulty levels, making it suitable for both recreational and educational purposes.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
You can install the package via npm:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm i sudoku-pro
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```npm
|
|
16
|
+
npm run easy
|
|
17
|
+
npm run medium
|
|
18
|
+
npm run hard
|
|
19
|
+
```
|
package/license
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2011-2016 Ashish Vashisht <concur.dev@gmail.com>
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sudoku-pro",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "sudoku-pro humbly presents itself as your go-to Node.js toolkit for generating, solving, and printing Sudoku puzzles spanning different difficulty levels. Powered by the reliable backtracking algorithm, it aspires to offer enthusiasts and learners alike a simple yet effective platform to engage with Sudoku puzzles. With Sudoku-Pro, embark on a journey of brain-teasing challenges or delve into educational endeavors with ease. Our humble interface aims to make Sudoku puzzle creation and enjoyment accessible to all, ensuring a delightful experience for users of varying skill levels. Join us in exploring the possibilities of Sudoku puzzles while we humbly accompany you on your puzzle-solving adventures.",
|
|
5
|
+
"main": "sudoku-pro.js",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+ssh://git@github.com/concurdev/sudoku-pro.git"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"easy": "node sudoku-pro e",
|
|
12
|
+
"medium": "node sudoku-pro m",
|
|
13
|
+
"hard": "node sudoku-pro h"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"sudoku-pro.js"
|
|
17
|
+
],
|
|
18
|
+
"keywords": [
|
|
19
|
+
"Sudoku",
|
|
20
|
+
"Puzzle",
|
|
21
|
+
"Game",
|
|
22
|
+
"Logic",
|
|
23
|
+
"Numbers",
|
|
24
|
+
"Board",
|
|
25
|
+
"Generator",
|
|
26
|
+
"Solver",
|
|
27
|
+
"Difficulty",
|
|
28
|
+
"Easy",
|
|
29
|
+
"Medium",
|
|
30
|
+
"Hard",
|
|
31
|
+
"Logic Game",
|
|
32
|
+
"Recreational Mathematics",
|
|
33
|
+
"Brain Teaser",
|
|
34
|
+
"Puzzle Game",
|
|
35
|
+
"Numbers Game"
|
|
36
|
+
],
|
|
37
|
+
"author": "Ashish Vashisht",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">= 10"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/concurdev/sudoku-pro/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/concurdev/sudoku-pro#readme",
|
|
46
|
+
"devDependencies": {}
|
|
47
|
+
}
|
package/sudoku-pro.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// Get the difficulty level
|
|
2
|
+
const args = process.argv.slice(2);
|
|
3
|
+
|
|
4
|
+
function shuffle(array) {
|
|
5
|
+
// Fisher-Yates shuffle algorithm
|
|
6
|
+
for (let i = array.length - 1; i > 0; i--) {
|
|
7
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
8
|
+
[array[i], array[j]] = [array[j], array[i]];
|
|
9
|
+
}
|
|
10
|
+
return array;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function generateSudoku(difficulty) {
|
|
14
|
+
const sudoku = Array.from({ length: 9 }, () => Array(9).fill(0));
|
|
15
|
+
|
|
16
|
+
// Fill the diagonal blocks (3x3 sub-grids) with valid numbers
|
|
17
|
+
for (let i = 0; i < 9; i += 3) {
|
|
18
|
+
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
19
|
+
shuffle(nums);
|
|
20
|
+
for (let j = 0; j < 3; j++) {
|
|
21
|
+
for (let k = 0; k < 3; k++) {
|
|
22
|
+
sudoku[i + j][i + k] = nums.pop();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Solve the puzzle
|
|
28
|
+
solveSudoku(sudoku);
|
|
29
|
+
|
|
30
|
+
// Determine the number of cells to remove based on difficulty level
|
|
31
|
+
let numToRemove;
|
|
32
|
+
if (difficulty === 'e') {
|
|
33
|
+
numToRemove = Math.floor(Math.random() * 20) + 20; // Easy difficulty
|
|
34
|
+
} else if (difficulty === 'm') {
|
|
35
|
+
numToRemove = Math.floor(Math.random() * 25) + 40; // Medium difficulty
|
|
36
|
+
} else if (difficulty === 'h') {
|
|
37
|
+
numToRemove = Math.floor(Math.random() * 30) + 55; // Hard difficulty
|
|
38
|
+
} else {
|
|
39
|
+
throw new Error('Invalid difficulty level. Please use "e" for easy, "m" for medium, or "h" for hard.');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Remove some numbers to create the puzzle
|
|
43
|
+
for (let i = 0; i < numToRemove; i++) {
|
|
44
|
+
const row = Math.floor(Math.random() * 9);
|
|
45
|
+
const col = Math.floor(Math.random() * 9);
|
|
46
|
+
if (sudoku[row][col] !== 0) {
|
|
47
|
+
sudoku[row][col] = 0;
|
|
48
|
+
} else {
|
|
49
|
+
i--; // Try again if the cell is already empty
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return sudoku;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function solveSudoku(sudoku) {
|
|
57
|
+
const emptyCell = findEmptyCell(sudoku);
|
|
58
|
+
if (!emptyCell) {
|
|
59
|
+
return true; // Puzzle solved successfully
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const [row, col] = emptyCell;
|
|
63
|
+
for (let num = 1; num <= 9; num++) {
|
|
64
|
+
if (isValidMove(sudoku, row, col, num)) {
|
|
65
|
+
sudoku[row][col] = num;
|
|
66
|
+
if (solveSudoku(sudoku)) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
sudoku[row][col] = 0; // Undo the assignment
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return false; // No solution found, backtrack
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function findEmptyCell(sudoku) {
|
|
77
|
+
// Function to find an empty cell in the Sudoku grid
|
|
78
|
+
for (let row = 0; row < 9; row++) {
|
|
79
|
+
for (let col = 0; col < 9; col++) {
|
|
80
|
+
if (sudoku[row][col] === 0) {
|
|
81
|
+
return [row, col];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return null; // No empty cell found
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function isValidMove(sudoku, row, col, num) {
|
|
89
|
+
// Check if assigning num to the cell at (row, col) is a valid move
|
|
90
|
+
// Check row
|
|
91
|
+
for (let i = 0; i < 9; i++) {
|
|
92
|
+
if (sudoku[row][i] === num) {
|
|
93
|
+
return false; // Number already exists in the row
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Check column
|
|
98
|
+
for (let i = 0; i < 9; i++) {
|
|
99
|
+
if (sudoku[i][col] === num) {
|
|
100
|
+
return false; // Number already exists in the column
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check 3x3 subgrid
|
|
105
|
+
const startRow = Math.floor(row / 3) * 3;
|
|
106
|
+
const startCol = Math.floor(col / 3) * 3;
|
|
107
|
+
for (let i = 0; i < 3; i++) {
|
|
108
|
+
for (let j = 0; j < 3; j++) {
|
|
109
|
+
if (sudoku[startRow + i][startCol + j] === num) {
|
|
110
|
+
return false; // Number already exists in the subgrid
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return true; // Valid move
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function printSudoku(sudoku) {
|
|
119
|
+
console.log("Sudoku Puzzle:");
|
|
120
|
+
console.log("-------------------------");
|
|
121
|
+
sudoku.forEach((row, rowIndex) => {
|
|
122
|
+
if (rowIndex % 3 === 0 && rowIndex !== 0) {
|
|
123
|
+
console.log("------|-------|-------");
|
|
124
|
+
}
|
|
125
|
+
row.forEach((cell, cellIndex) => {
|
|
126
|
+
if (cellIndex % 3 === 0 && cellIndex !== 0) {
|
|
127
|
+
process.stdout.write("| ");
|
|
128
|
+
}
|
|
129
|
+
process.stdout.write(String(cell || '.') + ' ');
|
|
130
|
+
if (cellIndex === 8) {
|
|
131
|
+
console.log();
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
console.log("-------------------------");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function printSudokuWithAnswers(sudoku) {
|
|
139
|
+
console.log("Sudoku Puzzle with Answers:");
|
|
140
|
+
console.log("-------------------------");
|
|
141
|
+
sudoku.forEach((row, rowIndex) => {
|
|
142
|
+
if (rowIndex % 3 === 0 && rowIndex !== 0) {
|
|
143
|
+
console.log("------|-------|-------");
|
|
144
|
+
}
|
|
145
|
+
row.forEach((cell, cellIndex) => {
|
|
146
|
+
if (cellIndex % 3 === 0 && cellIndex !== 0) {
|
|
147
|
+
process.stdout.write("| ");
|
|
148
|
+
}
|
|
149
|
+
process.stdout.write(String(cell) + ' ');
|
|
150
|
+
if (cellIndex === 8) {
|
|
151
|
+
console.log();
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
console.log("-------------------------");
|
|
156
|
+
// set flag to true and clear interval
|
|
157
|
+
sudokuPrinted = true;
|
|
158
|
+
clearInterval(intervalId);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const difficulty = args[0]; // Get the difficulty level from command line arguments
|
|
162
|
+
|
|
163
|
+
let sudokuPrinted = false;
|
|
164
|
+
|
|
165
|
+
// Set interval to run every 5 seconds
|
|
166
|
+
const intervalId = setInterval(() => {
|
|
167
|
+
// Check if sudokuPrinted is true
|
|
168
|
+
if (sudokuPrinted) {
|
|
169
|
+
// If sudokuPrinted is true, clear the interval
|
|
170
|
+
clearInterval(intervalId);
|
|
171
|
+
} else {
|
|
172
|
+
// If sudokuPrinted is false, continue executing
|
|
173
|
+
const sudoku = generateSudoku(difficulty);
|
|
174
|
+
printSudoku(sudoku);
|
|
175
|
+
solveSudoku(sudoku); // Solve the generated puzzle
|
|
176
|
+
printSudokuWithAnswers(sudoku);
|
|
177
|
+
}
|
|
178
|
+
}, 5000);
|
|
179
|
+
|
|
180
|
+
module.exports = {
|
|
181
|
+
generateSudoku,
|
|
182
|
+
printSudoku,
|
|
183
|
+
solveSudoku,
|
|
184
|
+
printSudokuWithAnswers
|
|
185
|
+
};
|