-
Notifications
You must be signed in to change notification settings - Fork 0
/
quadmarks.py
executable file
·102 lines (79 loc) · 3.19 KB
/
quadmarks.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
#!/usr/bin/env python3
import argparse
from base import Puzzle
def _main(filename):
puzzle = QuadMarksPuzzle(filename)
puzzle.solve()
class QuadMark():
def __init__(self, coords, values):
self.coords = coords
self.possible_values = values
self.original_values = values
class QuadMarksPuzzle(Puzzle):
"""
Twisted Sudoku puzzle that starts with no values. A set of four digits are
shown on the intersection between some sets of squares. These digits must
be placed in the four adjoining squares.
"""
def __init__(self, filename):
self.board, self.marks = self._parse_puzzle(filename)
def _parse_puzzle(self, filename):
with open(filename) as f:
data = f.readlines()
board = self.parse_board(data[:9])
marks = self.parse_marks(data[10:])
return board, marks
def parse_marks(self, data):
""" Each row looks like this 03,04,13,14,2349 """
marks = {}
for line in data:
coords = []
for s in line.strip().split(','):
if len(s) == 2:
coords.append((int(s[0]), int(s[1])))
else:
values = [int(v) for v in s]
for coord in coords:
if coord not in marks:
marks[coord] = QuadMark(coords, values)
else:
new_vals = []
for v in marks[coord].possible_values:
if v in values:
new_vals.append(v)
marks[coord].possible_values = new_vals
return marks
def get_possible_vals(self, i, j):
possible_vals = list(range(1, 10))
if (i, j) in self.marks:
possible_vals = self.get_quadmark_vals(i, j)
row_vals = self.get_row_vals(i)
col_vals = self.get_column_vals(j)
group_vals = self.get_group_vals(i, j)
non_quadmark_vals = self.get_non_quadmark_vals(i, j)
for val in row_vals + col_vals + group_vals + non_quadmark_vals:
if val in possible_vals:
possible_vals.remove(val)
return possible_vals
def get_quadmark_vals(self, row, col):
vals = []
if (row, col) in self.marks:
vals += self.marks[(row, col)].possible_values
for (i, j) in self.marks[(row, col)].coords:
if (i, j) != (row, col) and self.board[i][j] != 0:
if self.board[i][j] in vals:
vals.remove(self.board[i][j])
return vals
def get_non_quadmark_vals(self, row, col):
""" if a quad exists in this group but this cell is not affected, return the non quadmark values """
vals = []
group_center = ((row // 3 * 3) + 1, (col // 3 * 3) + 1)
if group_center in self.marks:
if (row, col) not in self.marks[group_center].coords:
vals += self.marks[group_center].original_values
return vals
if __name__=='__main__':
parser = argparse.ArgumentParser(description='Solve a Twisted Sudoku Puzzle.')
parser.add_argument('filename')
args = parser.parse_args()
_main(args.filename)