sudoku-pro 1.0.6 → 1.0.8

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.
Files changed (3) hide show
  1. package/README.md +13 -6
  2. package/package.json +6 -1
  3. package/sudoku-pro.js +187 -141
package/README.md CHANGED
@@ -22,7 +22,13 @@ npm run hard
22
22
 
23
23
  ```javascript
24
24
  // Import the module
25
- const { generateSudoku, printSudoku, solveSudoku } = require("sudoku-pro");
25
+ const {
26
+ generateSudoku,
27
+ printSudoku,
28
+ solveSudoku,
29
+ getHint,
30
+ waitForHint,
31
+ } = require("sudoku-pro");
26
32
 
27
33
  // Get the difficulty level
28
34
  const args = process.argv.slice(2);
@@ -30,16 +36,17 @@ const args = process.argv.slice(2);
30
36
  const difficulty = args[0]; // Get the difficulty level from command line arguments
31
37
 
32
38
  // Generate a Sudoku puzzle
33
- const sudoku = generateSudoku(difficulty);
39
+ const { sudoku, solvedSudoku } = generateSudoku(difficulty);
34
40
 
35
41
  // Print the puzzle
36
42
  printSudoku(sudoku);
37
43
 
38
- // Solve the puzzle
39
- solveSudoku(sudoku);
44
+ // Function to wait for user input for hint or complete solution
45
+ waitForHint(sudoku, solvedSudoku);
40
46
 
41
- // Print the solved puzzle
42
- printSudoku(sudoku);
47
+ // This script will continue running until the user chooses to exit
43
48
 
44
49
  process.exit();
45
50
  ```
51
+
52
+ Now, in addition to generating and solving Sudoku puzzles, users can also request hints or print the complete solution while the script is running.
package/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "sudoku-pro",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "sudoku-pro humbly presents itself as your go-to 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. This 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
+ "changelog": {
6
+ "1.0.6": "generateSudoku, printSudoku, solveSudoku",
7
+ "1.0.7": "getHint function added",
8
+ "1.0.7": "fixed the bug which cause issue while generating hard sudoku"
9
+ },
5
10
  "main": "sudoku-pro.js",
6
11
  "repository": {
7
12
  "type": "git",
package/sudoku-pro.js CHANGED
@@ -1,185 +1,231 @@
1
+ const readline = require("readline");
2
+
1
3
  // Get the difficulty level
2
4
  const args = process.argv.slice(2);
3
5
 
4
6
  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;
7
+ // Fisher-Yates shuffle algorithm
8
+ for (let i = array.length - 1; i > 0; i--) {
9
+ const j = Math.floor(Math.random() * (i + 1));
10
+ [array[i], array[j]] = [array[j], array[i]];
11
+ }
12
+ return array;
11
13
  }
12
14
 
13
15
  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
- }
16
+ const sudoku = Array.from({ length: 9 }, () => Array(9).fill(0));
17
+
18
+ // Fill the diagonal blocks (3x3 sub-grids) with valid numbers
19
+ for (let i = 0; i < 9; i += 3) {
20
+ const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9];
21
+ shuffle(nums);
22
+ for (let j = 0; j < 3; j++) {
23
+ for (let k = 0; k < 3; k++) {
24
+ sudoku[i + j][i + k] = nums.pop();
25
+ }
25
26
  }
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
27
+ }
28
+
29
+ // Solve the puzzle
30
+ const solvedSudoku = JSON.parse(JSON.stringify(sudoku)); // Create a deep copy for later use
31
+ solveSudoku(solvedSudoku);
32
+
33
+ // Determine the number of cells to remove based on difficulty level
34
+ let numToRemove;
35
+ if (difficulty === "e") {
36
+ numToRemove = Math.floor(Math.random() * 20) + 20; // Easy difficulty
37
+ } else if (difficulty === "m") {
38
+ numToRemove = Math.floor(Math.random() * 25) + 40; // Medium difficulty
39
+ } else if (difficulty === "h") {
40
+ do {
41
+ numToRemove = Math.floor(Math.random() * 30) + 70; // Hard difficulty
42
+ } while (numToRemove > 81); // Keep recalculating until numToRemove <= 81
43
+ } else {
44
+ throw new Error(
45
+ 'Invalid difficulty level. Please use "e" for easy, "m" for medium, or "h" for hard.'
46
+ );
47
+ }
48
+
49
+ // Create a copy of the solved Sudoku to remove cells from
50
+ const sudokuCopy = JSON.parse(JSON.stringify(solvedSudoku));
51
+
52
+ // Remove some numbers to create the puzzle
53
+ for (let i = 0; i < numToRemove; i++) {
54
+ const row = Math.floor(Math.random() * 9);
55
+ const col = Math.floor(Math.random() * 9);
56
+ if (sudokuCopy[row][col] !== 0) {
57
+ sudokuCopy[row][col] = 0;
38
58
  } 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
- }
59
+ i--; // Try again if the cell is already empty
51
60
  }
61
+ }
52
62
 
53
- return sudoku;
63
+ return { sudoku: sudokuCopy, solvedSudoku };
54
64
  }
55
65
 
56
66
  function solveSudoku(sudoku) {
57
- const emptyCell = findEmptyCell(sudoku);
58
- if (!emptyCell) {
59
- return true; // Puzzle solved successfully
67
+ const emptyCell = findEmptyCell(sudoku);
68
+ if (!emptyCell) {
69
+ return true; // Puzzle solved successfully
70
+ }
71
+
72
+ const [row, col] = emptyCell;
73
+ for (let num = 1; num <= 9; num++) {
74
+ if (isValidMove(sudoku, row, col, num)) {
75
+ sudoku[row][col] = num;
76
+ if (solveSudoku(sudoku)) {
77
+ return true;
78
+ }
79
+ sudoku[row][col] = 0; // Undo the assignment
60
80
  }
81
+ }
61
82
 
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
83
+ return false; // No solution found, backtrack
74
84
  }
75
85
 
76
86
  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
- }
87
+ // Function to find an empty cell in the Sudoku grid
88
+ for (let row = 0; row < 9; row++) {
89
+ for (let col = 0; col < 9; col++) {
90
+ if (sudoku[row][col] === 0) {
91
+ return [row, col];
92
+ }
84
93
  }
85
- return null; // No empty cell found
94
+ }
95
+ return null; // No empty cell found
86
96
  }
87
97
 
88
98
  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
- }
99
+ // Check if assigning num to the cell at (row, col) is a valid move
100
+ // Check row
101
+ for (let i = 0; i < 9; i++) {
102
+ if (sudoku[row][i] === num) {
103
+ return false; // Number already exists in the row
95
104
  }
105
+ }
96
106
 
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
- }
107
+ // Check column
108
+ for (let i = 0; i < 9; i++) {
109
+ if (sudoku[i][col] === num) {
110
+ return false; // Number already exists in the column
102
111
  }
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
- }
112
+ }
113
+
114
+ // Check 3x3 subgrid
115
+ const startRow = Math.floor(row / 3) * 3;
116
+ const startCol = Math.floor(col / 3) * 3;
117
+ for (let i = 0; i < 3; i++) {
118
+ for (let j = 0; j < 3; j++) {
119
+ if (sudoku[startRow + i][startCol + j] === num) {
120
+ return false; // Number already exists in the subgrid
121
+ }
113
122
  }
123
+ }
114
124
 
115
- return true; // Valid move
125
+ return true; // Valid move
116
126
  }
117
127
 
118
128
  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
- });
129
+ console.log("Sudoku Puzzle:");
130
+ console.log("-------------------------");
131
+ sudoku.forEach((row, rowIndex) => {
132
+ if (rowIndex % 3 === 0 && rowIndex !== 0) {
133
+ console.log("------|-------|-------");
134
+ }
135
+ row.forEach((cell, cellIndex) => {
136
+ if (cellIndex % 3 === 0 && cellIndex !== 0) {
137
+ process.stdout.write("| ");
138
+ }
139
+ process.stdout.write(String(cell || ".") + " ");
140
+ if (cellIndex === 8) {
141
+ console.log();
142
+ }
134
143
  });
135
- console.log("-------------------------");
144
+ });
145
+ console.log("-------------------------");
136
146
  }
137
147
 
138
148
  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
- });
149
+ console.log("Sudoku Puzzle with Answers:");
150
+ console.log("-------------------------");
151
+ sudoku.forEach((row, rowIndex) => {
152
+ if (rowIndex % 3 === 0 && rowIndex !== 0) {
153
+ console.log("------|-------|-------");
154
+ }
155
+ row.forEach((cell, cellIndex) => {
156
+ if (cellIndex % 3 === 0 && cellIndex !== 0) {
157
+ process.stdout.write("| ");
158
+ }
159
+ process.stdout.write(String(cell) + " ");
160
+ if (cellIndex === 8) {
161
+ console.log();
162
+ }
154
163
  });
155
- console.log("-------------------------");
156
- // set flag to true and clear interval
157
- sudokuPrinted = true;
158
- clearInterval(intervalId);
164
+ });
165
+ console.log("-------------------------");
159
166
  }
160
167
 
161
- const difficulty = args[0]; // Get the difficulty level from command line arguments
162
-
163
- let sudokuPrinted = false;
168
+ function getHint(sudoku, solvedSudoku) {
169
+ const emptyCells = [];
170
+ for (let i = 0; i < 9; i++) {
171
+ for (let j = 0; j < 9; j++) {
172
+ if (sudoku[i][j] === 0) {
173
+ emptyCells.push([i, j]);
174
+ }
175
+ }
176
+ }
177
+ if (emptyCells.length === 0) {
178
+ console.log("No empty cells left to provide a hint.");
179
+ return;
180
+ }
181
+ const randomIndex = Math.floor(Math.random() * emptyCells.length);
182
+ const [row, col] = emptyCells[randomIndex];
183
+ sudoku[row][col] = solvedSudoku[row][col];
184
+ console.log(
185
+ `Hint: The number at row ${row + 1}, column ${col + 1} is ${
186
+ solvedSudoku[row][col]
187
+ }`
188
+ );
189
+ }
164
190
 
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);
191
+ function waitForHint(sudoku, solvedSudoku) {
192
+ const rl = readline.createInterface({
193
+ input: process.stdin,
194
+ output: process.stdout,
195
+ });
196
+
197
+ rl.question(
198
+ "Press 'h' for a hint or 'c' for the complete solution: ",
199
+ (answer) => {
200
+ if (answer.trim().toLowerCase() === "h") {
201
+ getHint(sudoku, solvedSudoku);
174
202
  printSudoku(sudoku);
175
- solveSudoku(sudoku); // Solve the generated puzzle
176
- printSudokuWithAnswers(sudoku);
203
+ } else if (answer.trim().toLowerCase() === "c") {
204
+ printSudokuWithAnswers(solvedSudoku);
205
+ process.exit();
206
+ } else {
207
+ console.log(
208
+ "Invalid input. Please press 'h' for a hint or 'c' for the complete solution."
209
+ );
210
+ }
211
+ rl.close();
212
+ waitForHint(sudoku, solvedSudoku); // Ask again for hint or complete solution
177
213
  }
178
- }, 5000);
214
+ );
215
+ }
216
+
217
+ const difficulty = args[0]; // Get the difficulty level from command line arguments
218
+
219
+ const { sudoku, solvedSudoku } = generateSudoku(difficulty);
220
+ printSudoku(sudoku);
221
+
222
+ waitForHint(sudoku, solvedSudoku);
179
223
 
180
224
  module.exports = {
181
- generateSudoku,
182
- printSudoku,
183
- solveSudoku,
184
- printSudokuWithAnswers
225
+ generateSudoku,
226
+ printSudoku,
227
+ solveSudoku,
228
+ printSudokuWithAnswers,
229
+ getHint,
230
+ waitForHint,
185
231
  };