initial commit
This commit is contained in:
146
README.md
Normal file
146
README.md
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
# PDP-10 simple solver for Sudokus
|
||||||
|
|
||||||
|
## What is a sudoku?
|
||||||
|
|
||||||
|
[Sudoku](https://en.wikipedia.org/wiki/Sudoku) is a logic based number-placement
|
||||||
|
puzzle game originally from Japan. The word *sudoku* literally means
|
||||||
|
*digit-single*. The objecttive is to fill a 9x9 grid with numbers between 1 and
|
||||||
|
9, without having a number repeat in a row, column or a 3x3 subgrid. Normally,
|
||||||
|
there are a few numbers preset. In a regular sudoku, the pre-filled numbers make
|
||||||
|
sure, that exactly one solution for the puzzle exists.
|
||||||
|
|
||||||
|
The number of possible valid solutions to a sudoku is finite. In a classical
|
||||||
|
Sudoku, there are 6,670,903,752,021,072,936,960 possible valid grids. A number
|
||||||
|
that reduces to 5,472,730,538 essentially different solutions. The Sudokus you
|
||||||
|
will find in a modern day puzzle book, are always one of those roughly 5
|
||||||
|
billion, in order to guarantee a solution.
|
||||||
|
|
||||||
|
### Rules
|
||||||
|
|
||||||
|
A Sudoku is presented in a 9x9-grid:
|
||||||
|
|
||||||
|
```
|
||||||
|
||===|===|===||===|===|===||===|===|===||
|
||||||
|
|| | | 2 || 9 | | 3 || 8 | | ||
|
||||||
|
||---|---|---||---|---|---||---|---|---||
|
||||||
|
|| | | || 4 | 6 | 8 || | | ||
|
||||||
|
||---|---|---||---|---|---||---|---|---||
|
||||||
|
|| 4 | | || | | || | | 1 ||
|
||||||
|
||===|===|===||===|===|===||===|===|===||
|
||||||
|
|| 5 | 6 | || | | || | 4 | 9 ||
|
||||||
|
||---|---|---||---|---|---||---|---|---||
|
||||||
|
|| | 2 | || | 5 | || | 7 | ||
|
||||||
|
||---|---|---||---|---|---||---|---|---||
|
||||||
|
|| 7 | 8 | || | | || | 1 | 3 ||
|
||||||
|
||===|===|===||===|===|===||===|===|===||
|
||||||
|
|| 2 | | || | | || | | 7 ||
|
||||||
|
||---|---|---||---|---|---||---|---|---||
|
||||||
|
|| | | || 3 | 8 | 4 || | | ||
|
||||||
|
||---|---|---||---|---|---||---|---|---||
|
||||||
|
|| | | 6 || 2 | | 1 || 3 | | ||
|
||||||
|
||===|===|===||===|===|===||===|===|===||
|
||||||
|
```
|
||||||
|
|
||||||
|
The rules are the following:
|
||||||
|
|
||||||
|
- Every row must contain every number between 1 and 9 exactly once.
|
||||||
|
- Every vertical column must contain all the numbers between 1 and 9 exactly
|
||||||
|
once.
|
||||||
|
- Every 3x3 sub-grid must contain every number between 1 and 9 exactly once.
|
||||||
|
|
||||||
|
## Solving Sudokus programatically
|
||||||
|
|
||||||
|
### Backtracking (naïve approach)
|
||||||
|
|
||||||
|
Solving a Sudoku can be achieved in serveral ways. The most simple algorithm, is
|
||||||
|
a backtracking algorithm. With this a sudoku can be resolved basically by
|
||||||
|
brute-forcing it. In this case, we walk through each cell of the grid
|
||||||
|
recurseivly, and add a number. Then we check, if the grid is still valid. If it
|
||||||
|
is, we recursivly move on to the next column. If we find a number that doesn't
|
||||||
|
match, we return to the previous incarnation, and try another number. In order
|
||||||
|
to check, if our grid is still valid, we can use simple function:
|
||||||
|
|
||||||
|
```C
|
||||||
|
// Function to check, if it is save to place num at mat[row][col]
|
||||||
|
int isSafe(int[][] *mat, int row, int col, int num) {
|
||||||
|
// Check if num exists in the row
|
||||||
|
for (int x = 0; x <= 8; x++) {
|
||||||
|
if (*mat[row][x] == num) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check, if num exists in column
|
||||||
|
for (int x = 0; x < 8; x++) {
|
||||||
|
if (*mat[x][col]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if num exists in the 3x3 sub matrix
|
||||||
|
int startRow = row - (row % 3);
|
||||||
|
int startCol = col - (col % 3);
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
for (int j = 0; j < 3; j++ {
|
||||||
|
if (*mat[i + startRow][j + startCol] == num) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The only bit in this code, not straight forward, is the last part. By taking the
|
||||||
|
modulus of the current row and column, we can find the top left element in each
|
||||||
|
sub-grid, and adding the according number to it, we can then walk through.
|
||||||
|
|
||||||
|
The solving algorithm itself, is surprisingly simple:
|
||||||
|
|
||||||
|
```C
|
||||||
|
// Function to solve the sudoku problem by backtracking.
|
||||||
|
int solveSudokuRec(int[][] *mat, int row, int col) {
|
||||||
|
int n = sizeof(*mat);
|
||||||
|
|
||||||
|
// base case: Reached the nth column of the last row. We're done.
|
||||||
|
if (row == n - 1 && col == n) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if last column of a row, go to next row
|
||||||
|
if (col == n) {
|
||||||
|
row++;
|
||||||
|
col=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if cell is already occupied, move on
|
||||||
|
if (*mat[row][col] != 0) {
|
||||||
|
return solveSudokuRec(mat, row, col + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int num = 1; num <= n; num++) {
|
||||||
|
|
||||||
|
// if it is safe to place num at current position, do so.
|
||||||
|
if (isSafe(mat, row, col, num)) {
|
||||||
|
*mat[row][col] = num;
|
||||||
|
if (solveSudokuRec(mat, row, col + 1)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*mat[row][col] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And that's it.
|
||||||
|
|
||||||
|
## Using the PDP-10 to solve the Sudoku
|
||||||
|
|
||||||
|
The PDP-10 should be able to solve the sudoku using backtracking. The above
|
||||||
|
algorithm will be implemented directly in PDP-10 assembly, using the MIDAS
|
||||||
|
assembler, of the ITS operating system.
|
||||||
Reference in New Issue
Block a user