Finished. Now comes extensive testing.

This commit is contained in:
Andy Teijelo Pérez 2016-11-22 07:44:11 -05:00
parent a2fa29ab4b
commit 19a4a5cc6a

196
main.py
View file

@ -89,18 +89,21 @@ def invariants(width, pattern, constraints=None):
invs = [] invs = []
for sol in solve2(width, pattern, constraints): for sol in solve2(width, pattern, constraints):
exp = list(expand_solution(sol, width, pattern)) exp = list(expand_solution(sol, width, pattern))
count += 1
if len(invs) == 0: if len(invs) == 0:
invs = exp invs = exp
else: else:
for i, e in enumerate(exp): for i, e in enumerate(exp):
if invs[i] != e: if invs[i] != e:
invs[i] = -1 invs[i] = -1
return count, invs return invs
def visual(constraints): def visual(constraints):
"returns a visual representation of constraints" "returns a visual representation of constraints"
return "".join({1:'\N{LEFT SEVEN EIGHTHS BLOCK}', 0:'.', -1:'?'}[x] for x in constraints) return "".join({
1:'\N{FULL BLOCK}\N{LEFT SEVEN EIGHTHS BLOCK}',
0:'__',
-1:'??'
}[x] for x in constraints)
class Board: class Board:
"""Board """Board
@ -119,17 +122,17 @@ class Board:
for i in range(self.height): for i in range(self.height):
self.rows[i] = [-1] * self.width self.rows[i] = [-1] * self.width
print("rows:") # print("rows:")
for y in range(self.height): # for y in range(self.height):
n, c = invariants(self.width, self.row_patterns[y]) # n, c = invariants(self.width, self.row_patterns[y])
print(n, self.row_patterns[y], visual(c)) # print(n, self.row_patterns[y], visual(c))
print("cols:") # print("cols:")
for x in range(self.height): # for x in range(self.height):
n, c = invariants(self.width, self.col_patterns[x]) # n, c = invariants(self.width, self.col_patterns[x])
print(n, self.col_patterns[x], visual(c)) # print(n, self.col_patterns[x], visual(c))
print(self.row(0)) # print(self.row(0))
def col(self, i): def col(self, i):
"""a column""" """a column"""
@ -139,37 +142,121 @@ class Board:
"""a row""" """a row"""
return self.rows[i] return self.rows[i]
def solve(self): def replace_row(self, i, row):
min_row_index = 0 self.rows[i] = row
min_row_count = 0
def replace_col(self, i , col):
for y in range(self.height): for y in range(self.height):
count = 0 self.rows[y][i] = col[y]
def compute_invariants(self):
while True:
changed = False
row_sols = [0] * self.height
col_sols = [0] * self.width
# rows
for y in range(self.height):
invs = None; count = 0
for sol in solve2(self.width, self.row_patterns[y], self.row(y)): for sol in solve2(self.width, self.row_patterns[y], self.row(y)):
count += 1 count += 1
if count < min_row_count: exp = list(expand_solution(sol, self.width, self.row_patterns[y]))
min_row_count = count if invs == None:
min_row_index = y invs = exp
for i, e in enumerate(exp):
if invs[i] != e:
invs[i] = -1
if invs != None and self.row(y) != invs:
self.replace_row(y, invs)
changed = True
row_sols[y] = count
# columns
for x in range(self.width):
invs = None; count = 0
for sol in solve2(self.height, self.col_patterns[x], self.col(x)):
count += 1
exp = list(expand_solution(sol, self.height, self.col_patterns[x]))
if invs == None:
invs = exp
for i, e in enumerate(exp):
if invs[i] != e:
invs[i] = -1
if invs != None and self.col(x) != invs:
self.replace_col(x, invs)
changed = True
col_sols[x] = count
if not changed:
break
return row_sols, col_sols
def solve(self, solved=lambda x: None, depth=0):
row_sols, col_sols = self.compute_invariants()
# if depth < 2:
# print("depth:", depth)
# print(self)
# print("row_sols:", row_sols)
# print("col_sols:", col_sols)
if min(row_sols) == 0 or min(col_sols) == 0:
return False
if max(row_sols) == 1:
print("solved")
solved(self)
return True
min_row, y = min((a,b) for b,a in enumerate(row_sols) if a > 1)
min_col, x = min((a,b) for b,a in enumerate(col_sols) if a > 1)
if min_row < min_col:
for sol in solve2(self.width, self.row_patterns[y], self.row(y)):
b = self.copy()
b.replace_row(y, expand_solution(sol, self.width, self.row_patterns[y]))
if b.solve(solved, depth + 1):
return True
else:
for sol in solve2(self.height, self.col_patterns[x], self.col(x)):
b = self.copy()
b.replace_col(x, expand_solution(sol, self.height, self.col_patterns[x]))
if b.solve(solved, depth + 1):
return True
pass def copy(self):
newboard = Board((self.col_patterns, self.row_patterns))
for i in range(self.height):
newboard.rows[i] = self.rows[i][:]
return newboard
def __str__(self):
s = ""
for y in range(self.height):
s += visual(self.rows[y])
s += "\n"
return s
if __name__ == "__main__": if __name__ == "__main__":
def draw(solution, width, pattern): def draw(solution, width, pattern):
"draws a solution" "draws a solution"
for s, p in zip(solution, pattern): for s, p in zip(solution, pattern):
print('.' * s, end="") print('__' * s, end="")
print('\N{LEFT SEVEN EIGHTHS BLOCK}' * p, end="") print('\N{FULL BLOCK}\N{LEFT SEVEN EIGHTHS BLOCK}' * p, end="")
print('.' * (width - sum(solution) - sum(pattern))) print('.' * (width - sum(solution) - sum(pattern)))
width = int(sys.argv[1]) # width = int(sys.argv[1])
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
# for solution in solve1(width, pattern): # for solution in solve1(width, pattern):
# e = expand_solution(solution, width, pattern) # e = expand_solution(solution, width, pattern)
@ -182,18 +269,45 @@ if __name__ == "__main__":
rows = [[int(y) for y in x.strip().split()] for x in rows] rows = [[int(y) for y in x.strip().split()] for x in rows]
return rows return rows
def parse_constraints(s, width):
constraints = [-1] * width
for i, c in enumerate(s):
constraints[i] = {'1':1, '0':0, '?':-1, '.':0, '\N{LEFT SEVEN EIGHTHS BLOCK}': 1}[c]
return constraints
b = Board(( # width = 15
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, # pattern = (1, 1, 1, 2)
3 1, 1 1, 1 2 6 1, 2 1, 2 3 1, 1 1, 1 1 3 1, 2 1 1"""), # constraints = parse_constraints('????????010?', width)
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, # for sol in solve2(width, pattern, constraints):
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""") # draw(sol, width, pattern)
))
# c = Board(( # b = 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, # parse("1 1 1, 1 1 1, 1 1 1, 1 1 1, 1 1 1, 1 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 1 1, 1 1 1, 1 1 1, 1 1 1, 1 1 1, 1 1 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""")
# )) # ))
# b.solve(print)
# b = Board((
# 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,
# 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""")
# ))
# b.solve(print)
# b = Board((
# parse("""2 4, 1 1 3 1, 6, 3 3, 3 4, 1 3 2, 3 4 1, 3 5 1 1, 12,
# 5 3 3, 6 4, 2 3, 1 2 2, 3 4, 3 5"""),
# parse("""1 6, 2 2 4 2, 3 5 2, 11, 1 6 1, 4 1 5, 5 3 3, 10 2, 1 7 1 1, 5 1 1 1,
# 1 3 1, 3, 3, 1 1, 3"""),
# ))
# b.solve()
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""")
))
c.solve(print)