-
Notifications
You must be signed in to change notification settings - Fork 0
/
backtracking_with_waterfall.py
88 lines (65 loc) · 2.35 KB
/
backtracking_with_waterfall.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
import copy
from sudoku import Sudoku
def _run_waterfall(waterfall, sudoku, domains):
while True:
changed = False
for inference in waterfall:
domains, domains_changed = inference(sudoku, domains)
if domains is None:
return
if domains_changed:
changed = True
if not changed:
break
return domains
def _initialize_domains(sudoku: Sudoku):
domains = {}
for variable in sudoku.assigned_variables:
i, j = variable
domains[variable] = {sudoku.data[i][j]}
for variable in sudoku.unassigned_variables:
domains[variable] = set(range(1, 10))
return domains
def backtracking_with_waterfall(sudoku, waterfall=None):
domains = _initialize_domains(sudoku)
_run_waterfall(waterfall, sudoku, domains)
success, statistics = _backtracking(sudoku, domains, waterfall, {'n': 0})
return statistics
def _backtracking(sudoku: Sudoku,
domains: dict,
waterfall,
statistics: dict = None) -> (bool, dict):
if sudoku.is_complete():
return True, statistics
min_variable = None
min_n = None
for variable in domains:
if variable in sudoku.unassigned_variables:
n = len(domains[variable])
if n == 1:
min_variable = variable
break
elif min_n is None or n < min_n:
min_variable = variable
min_n = n
variable = min_variable
domain = domains[variable]
if not domain:
return False, statistics
statistics['n'] += len(domain) - 1
for value in domain:
if not sudoku.has_conflict(variable, value):
sudoku.assign(variable, value)
updated_domains = copy.deepcopy(domains)
updated_domains[variable] = {value}
updated_domains = _run_waterfall(waterfall, sudoku, updated_domains)
if updated_domains is None:
sudoku.undo(variable)
else:
success, statistics = _backtracking(sudoku, updated_domains,
waterfall, statistics)
if success:
return success, statistics
else:
sudoku.undo(variable)
return False, statistics