Skip to content

Commit 265fbcf

Browse files
committed
Add gitignore and structure for handling sudoku
1 parent e6ded9f commit 265fbcf

File tree

6 files changed

+124
-5
lines changed

6 files changed

+124
-5
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.vscode/extensions.json
2+
SudokuSolver/__pycache__/sudoku.cpython-38.pyc

SudokuSolver/examples/ex1.csv

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
a,b,c,d,e,f,g,h,i
2+
0,1,0,0,5,0,0,0,0
3+
0,1,0,0,5,0,0,0,0
4+
0,1,0,0,5,0,0,0,0
5+
0,1,0,0,5,0,0,0,0
6+
0,1,0,0,5,0,0,0,0
7+
0,1,0,0,5,0,0,0,0
8+
0,1,0,0,5,0,0,0,0
9+
0,1,0,0,5,0,0,0,0
10+
0,1,0,0,5,0,0,0,0

SudokuSolver/move.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Move:
2+
3+
def __init__(self, number: int, row: int, column: int) -> None:
4+
5+
self.number = number
6+
self.row = row
7+
self.column = column

SudokuSolver/read_sudoku.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import numpy as np
2+
import pandas as pd
3+
from sudoku import Sudoku
4+
5+
MINIMUM_NUMBERS_FOR_UNIQUE_SOLUTION = 17
6+
NUMBER_REGIONS = 9
7+
8+
def import_sudoku() -> Sudoku:
9+
10+
filename = input('Enter the filename\'s path of the sudoku to be solved: ') + '.csv'
11+
12+
read_sudoku = pd.read_csv(filename).to_numpy()
13+
14+
sudoku = Sudoku(read_sudoku)
15+
16+
if is_solvable(sudoku):
17+
return sudoku
18+
19+
def is_solvable(sudoku: Sudoku) -> bool:
20+
21+
# Check there are at least 17 non 0 numbers for unique solution
22+
23+
if sudoku[sudoku.grid != 0].size < MINIMUM_NUMBERS_FOR_UNIQUE_SOLUTION:
24+
return False
25+
26+
# Check rows' legality
27+
for row in sudoku.grid:
28+
row = row[row != 0]
29+
if np.unique(row).size != row.size:
30+
return False
31+
32+
# Check columns' legality
33+
for column in np.nditer(sudoku, flags = ['external_loop'], order='C'):
34+
column = column[column != 0]
35+
if np.unique(column).size != column.size:
36+
return False
37+
38+
# Check regions' legality
39+
for region_number in range(NUMBER_REGIONS):
40+
region = getattr(sudoku, 'region'+(region_number+1))
41+
region = region[region != 0]
42+
if np.unique(region).size != region.size:
43+
return False
44+
45+
return True

SudokuSolver/sudoku.py

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,62 @@
11
import numpy as np
2+
from move import Move
23

34
class Sudoku:
45

5-
def __init__(self) -> None:
6+
def __init__(self, grid: np.ndarray) -> None:
67

7-
self.grid = np.zeros((9,9))
8+
self.grid = grid
9+
self.region1 = self.grid[:3, :3]
10+
self.region2 = self.grid[:3, 3:6]
11+
self.region3 = self.grid[:3, 6:9]
12+
self.region4 = self.grid[3:6, :3]
13+
self.region5 = self.grid[3:6, 3:6]
14+
self.region6 = self.grid[3:6, 6:9]
15+
self.region7 = self.grid[6:9, :3]
16+
self.region8 = self.grid[6:9, 3:6]
17+
self.region9 = self.grid[6:9, 6:9]
818

9-
def put_number(self, number, row, column) -> None:
19+
def put_number(self, move: Move) -> None:
1020

11-
self.grid[row, column] = number
21+
self.grid[move.row, move.column] = move.number
22+
23+
def check_legal_state(self, previous_move: Move) -> bool:
24+
25+
row_to_check = self.grid[previous_move.row, :].copy()
26+
column_to_check = self.grid[:, previous_move.column].copy()
27+
region_to_check = self.get_region_from_move(previous_move)
28+
29+
# Remove 0's from the areas to be checked
30+
31+
row_to_check = row_to_check[row_to_check != 0]
32+
column_to_check = column_to_check[column_to_check != 0]
33+
region_to_check = region_to_check[region_to_check != 0]
34+
35+
# Check if there are repeated numbers after the move
36+
37+
row_check = np.unique(row_to_check).size == row_to_check.size
38+
column_check = np.unique(column_to_check).size == column_to_check.size
39+
region_check = np.unique(region_to_check).size == region_to_check.size
40+
41+
return row_check and column_check and region_check
42+
43+
def get_region_from_move(self, move: Move) -> np.ndarray :
44+
45+
if move.row <= 2 and move.column <= 2:
46+
return self.region1
47+
elif move.row <= 2 and move.column <= 5 and move.column > 2:
48+
return self.region2
49+
elif move.row <= 2 and move.column <= 9 and move.column > 5:
50+
return self.region3
51+
elif move.row <= 5 and move.row > 2 and move.column <= 2:
52+
return self.region4
53+
elif move.row <= 5 and move.row > 2 and move.column <= 5 and move.column > 2:
54+
return self.region5
55+
elif move.row <= 5 and move.row > 2 and move.column <= 9 and move.column > 5:
56+
return self.region6
57+
elif move.row <= 9 and move.row > 5 and move.column <= 2:
58+
return self.region7
59+
elif move.row <= 9 and move.row > 5 and move.column <= 5 and move.column > 2:
60+
return self.region8
61+
else:
62+
return self.region9

SudokuSolver/sudoku_solver.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
from sudoku import Sudoku
22

3-
s = Sudoku()
3+
LEGIT_NUMBERS = list(range(1,10))
4+
5+
def solve_sudoku(sudoku: Sudoku) -> Sudoku:
6+
7+
return sudoku

0 commit comments

Comments
 (0)