-
Notifications
You must be signed in to change notification settings - Fork 0
/
sudoku_solver.py
128 lines (89 loc) · 3.68 KB
/
sudoku_solver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# Assessment 2 @ Noroff University College
_author_ = "Thomas Thaulow"
_copyright = "Thomas Thaulow"
_email_ = "[email protected]"
import time
class sudoku_solver:
def __init__(self, field):
self.field = field
print("The provided grid is: ")
self.print_grid(field)
print("\n")
# STYLE BOARD IN TERMINAL
def print_grid(self, field):
for row in range(len(field)):
if row % 2 == 0:
print("-------+-------")
for column in range(len(field[0])):
if column % 3 == 0 and column != 0:
print(" | ", end="")
if column == 5:
print(field[row][column])
else:
print(str(field[row][column]) + " ", end="")
# FIND NEXT EMPTY FIELD
""" This function will return the position of the next empty field """
""" or if there is none, it will return empty, meaning the Sudoku is completed """
def find_next(self, field):
for row in range(len(field)):
for col in range(len(field[row])):
if field[row][col] == 0:
return row, col
return None
def row_match(self, field, num, pos):
empty_cell_row_position = pos[0]
for col in range(len(field[0])):
if field[empty_cell_row_position][col] == num:
return False
return True
def col_match(self, field, num, pos):
empty_cell_col_position = pos[1]
for row in range(len(field)):
if field[row][empty_cell_col_position] == num:
return False
return True
def sector_match(self, field, num, pos):
row_position = pos[0]
col_position = pos[1]
row_position_of_box = row_position // 2 # will always return 0, 1, or 2
col_position_of_box = col_position // 3 # will always return 0 or 1
""" Multiplying with 2 and 3 may takes the number larger then 6.
Due to our loop, the excess range will be truncated """
for row in range(row_position_of_box * 2, row_position_of_box * 2 + 2):
for col in range(col_position_of_box * 3, col_position_of_box * 3 + 3):
print(f"I am currently checking (row, col): {(row, col)}")
if field[row][col] == num:
return False
return True
# OUTER/MAPPED FUNCTION VALIDATING IF NUMBERS EXIST
def is_position_valid(self, field, num, pos):
if self.row_match(field, num, pos):
if self.col_match(field, num , pos):
if self.sector_match(field, num, pos):
return True
return False
return False
return False
def solve(self):
start = time.time()
field = self.field
# if it does not find an empty field, the Sudoku is solved,
# and it will return True and end the function
find = self.find_next(field)
if not find:
print("The solved grid is:\n")
self.print_grid(field)
print("Sudoku solved in", time.time() - start, "seconds")
return True
else:
row, column = find
for number_to_insert in range(1, 7):
if self.is_position_valid(field, number_to_insert, (row, column)):
# if the number is valid, it is added
field[row][column] = number_to_insert
# This is recursion, calling the same function.
# But this time, the field changes because we added a new number.
if self.solve():
return True
field[row][column] = 0
return False