-
Notifications
You must be signed in to change notification settings - Fork 0
/
solve_sudoku_x.py
96 lines (83 loc) · 2.94 KB
/
solve_sudoku_x.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
#!/usr/bin/python3
# coding: utf-8
'''
Solving Sudoku-X puzzles and checking their results
Copyright (C) 2018 Zettsu Tatsuya
usage:
$ python3 solve_sudoku_x.py puzzleFilename (1 or more)
or
$ python3 --log text_solutions (solution per line)
'''
import re
import sys
import subprocess
from optparse import OptionParser
EXECUTABLE_FILENAME='bin/sudokusse_diagonal'
def check_solution(lines):
status_code = 0
rows = lines[-9:]
columns = [''.join(i) for i in zip(*rows)]
boxes = []
for y in range(0, 9, 3):
for x in range(0, 9, 3):
cells = ''
for z in range(0, 3):
cells += rows[y + z][x:x + 3]
boxes.append(cells)
bars = []
bars.append(''.join([(rows[i][i]) for i in range(0, 9)]))
bars.append(''.join([(rows[8 - i][i]) for i in range(0, 9)]))
cells = []
for cellset in [rows, columns, boxes, bars]:
cells.extend(cellset)
for ninecells in cells:
if ''.join(sorted(ninecells)) != '123456789':
print('Unexpected cells')
status_code = 1
return status_code
def parse_solution(line):
status_code = 0
matched = re.match(r'^\d{81}', line)
if matched is None:
return status_code
lines = list(filter(bool, re.split(r'(\d{9})', line)))
return check_solution(lines)
def solve_puzzle(stdout_data):
status_code = 0
lines = []
for line in re.split(r'\r?\n', stdout_data.decode('utf-8')):
matched = re.match(r'^\d:\d:\d:\d:\d:\d:\d:\d:\d:', line)
if matched is not None:
lines.append(''.join(line.split(':')))
return check_solution(lines)
def main():
exit_status_code = 0
parser = OptionParser()
parser.add_option("-l", "--log", dest="log_filename",
help="parse solutions in a file instead of solving")
(options, args) = parser.parse_args()
if options.log_filename is not None:
count = 0
with open(options.log_filename, 'r') as infile:
line = infile.readline()
while line:
count += 1
status_code = parse_solution(line.strip())
if status_code:
exit_status_code = status_code
line = infile.readline()
if exit_status_code == 0:
print('All {0} cases passed'.format(count))
else:
for filename in sys.argv[1:]:
with open(filename, 'r') as infile:
proc = subprocess.Popen([EXECUTABLE_FILENAME, '-1'], stdin=infile, stdout=subprocess.PIPE)
stdout_data = proc.communicate()[0]
status_code = solve_puzzle(stdout_data)
if status_code == 0:
print('{0} solved'.format(filename))
else:
exit_status_code = status_code
sys.exit(exit_status_code)
if __name__ == "__main__":
main()