Solving the board...

master
Andy Teijelo Pérez 2016-11-22 05:14:32 -05:00
parent 70ac0f773f
commit 354e05db14
1 changed files with 105 additions and 27 deletions

132
main.py
View File

@ -1,6 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"This module does something"
from itertools import combinations_with_replacement from itertools import combinations_with_replacement
import sys
def solve1(width, pattern): def solve1(width, pattern):
@ -9,19 +12,19 @@ def solve1(width, pattern):
pattern inside the row. The tuple elements are the pattern inside the row. The tuple elements are the
gaps before each block in pattern. gaps before each block in pattern.
The tuple doesn't include the last gap, since that's The tuple doesn't include the last gap, since that's
just: width - sum(sol) - sum(pattern) just: width - sum(sol) - sum(pattern)
""" """
spaces = width - (sum(pattern) + len(pattern) - 1) spaces = width - (sum(pattern) + len(pattern) - 1)
for sol in combinations_with_replacement(range(spaces + 1), len(pattern)): for sol in combinations_with_replacement(range(spaces + 1), len(pattern)):
sol = sol[0:1] + tuple((sol[i] - sol[i-1] + 1) for i in range(1,len(sol))) sol = sol[0:1] + tuple((sol[i] - sol[i-1] + 1) for i in range(1, len(sol)))
yield sol yield sol
def expand_solution(solution, width, pattern): def expand_solution(solution, width, pattern):
""" """
expands a solution to a tuple of 1 (ON) and 0 (OFF) expands a solution to a tuple of 1 (ON) and 0 (OFF)
""" """
r = [] r = []
for s,p in zip(solution, pattern): for s, p in zip(solution, pattern):
r.extend([0] * s) r.extend([0] * s)
r.extend([1] * p) r.extend([1] * p)
r.extend([0] * (width - sum(solution) - sum(pattern))) r.extend([0] * (width - sum(solution) - sum(pattern)))
@ -37,7 +40,7 @@ def matches(expanded_solution, constraints):
1 -> ON 1 -> ON
-1 -> not constrained -1 -> not constrained
""" """
for s,c in zip(expanded_solution, constraints): for s, c in zip(expanded_solution, constraints):
if c == -1: if c == -1:
continue continue
if c != s: if c != s:
@ -52,15 +55,15 @@ def solve2(width, pattern, constraints=None):
@constraints: optional list of length width containing 1,0,-1 as elements @constraints: optional list of length width containing 1,0,-1 as elements
Does the same as solve1, but takes constraints Does the same as solve1, but takes constraints
in consideration to be faster than solve1 + matches in consideration to be faster than solve1 + matches
""" """
if len(pattern) == 0: if len(pattern) == 0:
return tuple() return tuple()
if constraints is None: if constraints is None:
constraints = [-1] * width constraints = [-1] * width
p = pattern[0] p = pattern[0]
# the first gap can go from 0 to the following, inclusive # the first gap can go from 0 to the following, inclusive
@ -75,17 +78,84 @@ def solve2(width, pattern, constraints=None):
continue continue
subwidth = width - gap - p - 1 subwidth = width - gap - p - 1
subpattern = pattern[1:] subpattern = pattern[1:]
subconstraints = constraints[-subwidth:] subconstraints = constraints[-subwidth:]
for s in solve2(subwidth, subpattern, subconstraints): for s in solve2(subwidth, subpattern, subconstraints):
yield (gap,s[0]+1) + s[1:] yield (gap, s[0]+1) + s[1:]
def invariants(width, pattern, constraints=None):
"compute invariants"
invs = []
for sol in solve2(width, pattern, constraints):
exp = list(expand_solution(sol, width, pattern))
count += 1
if len(invs) == 0:
invs = exp
else:
for i, e in enumerate(exp):
if invs[i] != e:
invs[i] = -1
return count, invs
def visual(constraints):
"returns a visual representation of constraints"
return "".join({1:'\N{LEFT SEVEN EIGHTHS BLOCK}', 0:'.', -1:'?'}[x] for x in constraints)
class Board:
"""Board
A board is actually a list of constraints.
A cell with 1 or 0 is fixed. A cell with -1
doesn't have a known value yet.
"""
def __init__(self, patterns):
self.col_patterns = patterns[0]
self.row_patterns = patterns[1]
self.width = len(patterns[0])
self.height = len(patterns[1])
self.rows = [None] * self.height
for i in range(self.height):
self.rows[i] = [-1] * self.width
print("rows:")
for y in range(self.height):
n, c = invariants(self.width, self.row_patterns[y])
print(n, self.row_patterns[y], visual(c))
print("cols:")
for x in range(self.height):
n, c = invariants(self.width, self.col_patterns[x])
print(n, self.col_patterns[x], visual(c))
print(self.row(0))
def col(self, i):
"""a column"""
return [self.rows[x][i] for x in range(self.height)]
def row(self, i):
"""a row"""
return self.rows[i]
def solve(self):
min_row_index = 0
min_row_count = 0
for y in range(self.height):
count = 0
for sol in solve2(self.width, self.row_patterns[y], self.row(y)):
count += 1
if count < min_row_count:
min_row_count = count
min_row_index = y
pass
if __name__ == "__main__": if __name__ == "__main__":
import sys
def draw(solution, width, pattern): def draw(solution, width, pattern):
for s,p in zip(solution, pattern): "draws a solution"
for s, p in zip(solution, pattern):
print('.' * s, end="") print('.' * s, end="")
print('\N{LEFT SEVEN EIGHTHS BLOCK}' * p, end="") print('\N{LEFT SEVEN EIGHTHS BLOCK}' * p, end="")
print('.' * (width - sum(solution) - sum(pattern))) print('.' * (width - sum(solution) - sum(pattern)))
@ -94,8 +164,8 @@ if __name__ == "__main__":
pattern = tuple(int(x) for x in sys.argv[2].split()) pattern = tuple(int(x) for x in sys.argv[2].split())
constraints = [-1] * width constraints = [-1] * width
try: try:
for i,c in enumerate(sys.argv[3]): for i, c in enumerate(sys.argv[3]):
constraints[i]= {'1':1, '0':0, '?':-1}[c] constraints[i] = {'1':1, '0':0, '?':-1}[c]
except: except:
constraints = [-1] * width constraints = [-1] * width
@ -104,16 +174,24 @@ if __name__ == "__main__":
# if matches(e, constraints): # if matches(e, constraints):
# draw(solution, width, pattern) # draw(solution, width, pattern)
fixed = [] def parse(rows):
for sol in solve2(width, pattern, constraints): "parses '1 1, 1 2 3' into [[1, 1], [1, 2, 3]]"
exp = list(expand_solution(sol, width, pattern)) rows = rows.split(",")
if len(fixed) == 0: rows = [[int(y) for y in x.strip().split()] for x in rows]
fixed = exp return rows
else:
for i,e in enumerate(exp):
if fixed[i] != e: b = Board((
fixed[i] = -1 parse("""1 1 1 1 1, 1 1 1, 1 1 1 1, 1 2, 1 1 1 1, 1 1 1, 1 1 1,
draw(sol, width, pattern) 3 1, 1 1, 1 2 6 1, 2 1, 2 3 1, 1 1, 1 1 3 1, 2 1 1"""),
parse("""1 2, 1 1 2, 2 1 1 1 1, 3 1, 1 1 1 1, 1 2 1, 1, 1 1 1 2,
2 2 1 1, 1 1 1 1 1, 1 2 2, 2 2, 1 1 1 1 1, 1 1 1 1, 1 1""")
))
# c = Board((
# parse("""1 5 2, 1 1 2, 1 1 2 1 2, 2 2, 2 1 1 1, 1 1 1, 1 1, 1 1 1, 2 3 1 1,
# 1 2 3 1 1, 1 3 1 1, 2 1 1 1, 1 1 1 2 1, 1 1 1 2 1, 2 1"""),
# parse("""1 2 1 1, 1 1 4, 2 1, 1 1 1 1 2, 1 3 1 1, 1 2, 1 1 1 1 1 1,
# 1 1 1 1 1 2, 1 1 2, 1 2 1 1, 3 1 4, 1 4 1, 3, 3 1 1, 1 2 1""")
# ))
print("invariants:")
print("".join({1:'\N{LEFT SEVEN EIGHTHS BLOCK}',0:'.',-1:'?'}[x] for x in fixed))