-
Notifications
You must be signed in to change notification settings - Fork 1
/
utils.py
134 lines (108 loc) · 3.84 KB
/
utils.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
128
129
130
131
132
133
134
rows = 'ABCDEFGHI'
cols = '123456789'
history = {} # history must be declared here so that it exists in the assign_values scope
def cross(a, b):
return [s+t for s in a for t in b]
boxes = cross(rows, cols)
row_units = [cross(r, cols) for r in rows]
col_units = [cross(rows, c) for c in cols]
square_units = [cross(rs, cs) for rs in ('ABC', 'DEF', 'GHI') for cs in ('123', '456', '789')]
unitlist = row_units + col_units + square_units
diagonal_units = [[x+y for x, y in zip(rows, cols)], [x+y for x, y in zip(rows[::-1], cols)]]
unitlist = unitlist + diagonal_units
units = dict((s, [u for u in unitlist if s in u]) for s in boxes)
peers = dict((s, set(sum(units[s],[]))-set([s])) for s in boxes)
def assign_value(values, box, value):
"""You must use this function to update your values dictionary if you want to
try using the provided visualization tool. This function records each assignment
(in order) for later reconstruction.
Parameters
----------
values(dict)
a dictionary of the form {'box_name': '123456789', ...}
Returns
-------
dict
The values dictionary with the naked twins eliminated from peers
"""
# Don't waste memory appending actions that don't actually change any values
if values[box] == value:
return values
prev = values2grid(values)
values[box] = value
if len(value) == 1:
history[values2grid(values)] = (prev, (box, value))
return values
def values2grid(values):
"""Convert the dictionary board representation to as string
Parameters
----------
values(dict)
a dictionary of the form {'box_name': '123456789', ...}
Returns
-------
a string representing a sudoku grid.
Ex. '2.............62....1....7...6..8...3...9...7...6..4...4....8....52.............3'
"""
res = []
for r in rows:
for c in cols:
v = values[r + c]
res.append(v if len(v) == 1 else '.')
return ''.join(res)
def grid2values(grid):
"""Convert grid into a dict of {square: char} with '123456789' for empties.
Parameters
----------
grid(string)
a string representing a sudoku grid.
Ex. '2.............62....1....7...6..8...3...9...7...6..4...4....8....52.............3'
Returns
-------
A grid in dictionary form
Keys: The boxes, e.g., 'A1'
Values: The value in each box, e.g., '8'. If the box has no value,
then the value will be '123456789'.
"""
sudoku_grid = {}
for val, key in zip(grid, boxes):
if val == '.':
sudoku_grid[key] = '123456789'
else:
sudoku_grid[key] = val
return sudoku_grid
def display(values):
"""
Display the values as a 2-D grid.
Input: The sudoku in dictionary form
Output: None
"""
width = 1+max(len(values[s]) for s in boxes)
line = '+'.join(['-'*(width*3)]*3)
for r in rows:
print(''.join(values[r+c].center(width)+('|' if c in '36' else '')
for c in cols))
if r in 'CF': print(line)
return
def reconstruct(values, history):
"""Returns the solution as a sequence of value assignments
Parameters
----------
values(dict)
a dictionary of the form {'box_name': '123456789', ...}
history(dict)
a dictionary of the form {key: (key, (box, value))} encoding a linked
list where each element points to the parent and identifies the value
assignment that connects from the parent to the current state
Returns
-------
list
a list of (box, value) assignments that can be applied in order to the
starting Sudoku puzzle to reach the solution
"""
path = []
prev = values2grid(values)
while prev in history:
prev, step = history[prev]
path.append(step)
return path[::-1]