nonograms/main.py

72 lines
2.1 KiB
Python
Executable File

#!/usr/bin/env python3
from itertools import combinations_with_replacement
def row_solutions(width, pattern):
"""
This yields a tuple for each possible layout of
pattern inside the row. The tuple elements are the
amount of cells that must be inserted before each
block in pattern. The tuple doesn't include the
number of cells at the end of the row since that's
just: width - sum(sol) - sum(pattern)
"""
spaces = width - (sum(pattern) + len(pattern) - 1)
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)))
yield sol
def expand_solution(solution, width, pattern):
"""
expands a solution to a tuple of 1 (ON) and 0 (OFF)
"""
r = []
for s,p in zip(solution, pattern):
r.extend([0] * s)
r.extend([1] * p)
r.extend([0] * (width - sum(solution) - sum(pattern)))
return tuple(r)
def matches(expanded_solution, constraints):
"""
solution is a tuple of spaces, the output of row_solutions
constraints is a tuple of values from 1, 0 and -1, that
mean:
0 -> OFF
1 -> ON
-1 -> not constrained
"""
for s,c in zip(expanded_solution, constraints):
if c == -1:
continue
if c != s:
return False
return True
if __name__ == "__main__":
import sys
def draw(solution, width, pattern):
for s,p in zip(solution, pattern):
print('.' * s, end="")
print('\N{FULL BLOCK}' * p, end="")
print('.' * (width - sum(solution) - sum(pattern)))
width = int(sys.argv[1])
pattern = tuple(int(x) for x in sys.argv[2].split())
constraints = [-1] * width
try:
for i,c in enumerate(sys.argv[3]):
constraints[i]= {'1':1, '0':0, '?':-1}[c]
except:
print(sys.exc_info())
constraints = [-1] * width
for solution in row_solutions(width, pattern):
e = expand_solution(solution, width, pattern)
if matches(e, constraints):
draw(solution, width, pattern)