Skip to content

Instantly share code, notes, and snippets.

@Bejofo
Created March 12, 2023 18:47
Show Gist options
  • Save Bejofo/ab33638d889551613ca062fa7af22aaa to your computer and use it in GitHub Desktop.
Save Bejofo/ab33638d889551613ca062fa7af22aaa to your computer and use it in GitHub Desktop.
Nonogram solver.
import numpy as np
import math
import itertools
import pprint
BOARDSIZE = 10
def idx_to_cord(x):
return (x-1)//BOARDSIZE,(x-1)%BOARDSIZE
# return math.divmod(x-1,5)
def cord_to_idx(row,col):
return row*BOARDSIZE+col+1
def dnf_to_cnf(form):
pass
# rows = [[3,1],[1,1,1],[1],[3],[2]]
# cols = [[2,1],[1,2],[2,1],[2],[2]]
# rows = [eval("["+input()+"]") for _ in range(BOARDSIZE)]
# cols = [eval("["+input()+"]") for _ in range(BOARDSIZE)]
with open("./input.txt") as f:
lines = [eval("["+x+"]") for x in f.readlines()]
rows = lines[:BOARDSIZE]
cols = lines[BOARDSIZE:]
cnf = []
prod_of_dnf = []
set_vars = set()
def generate_possible_rowscols(hints,size):
b_vars = set(range(size))
for possible_row in itertools.combinations(b_vars,r=sum(hints)):
phints = []
streak = 0
for n in range(size):
if n in possible_row:
streak+=1
elif streak > 0:
phints.append(streak)
streak = 0
if streak > 0:
phints.append(streak)
if all( a==b for a,b in zip(phints,hints)):
yield possible_row
return
def process_hints(hints,row_or_col='r'):
ans = []
for i,hint in enumerate(hints):
dnf = []
if row_or_col == 'r':
all_bvars = set(cord_to_idx(i,x) for x in range(BOARDSIZE))
else:
all_bvars = set(cord_to_idx(x,i) for x in range(BOARDSIZE))
for combo in generate_possible_rowscols(hint,BOARDSIZE):
if row_or_col == 'r':
ccombo = set( cord_to_idx(i,x) for x in combo)
else :
ccombo = set( cord_to_idx(x,i) for x in combo )
neg = set(-x for x in (all_bvars) if x not in ccombo)
dnf.append( frozenset(neg | ccombo))
ans.append(dnf)
return ans
for x in process_hints(rows,'r'):
prod_of_dnf.append(x)
for x in process_hints(cols,'c'):
prod_of_dnf.append(x)
for dnf in prod_of_dnf:
print(f"dnf len {len(dnf)}")
print(f"{set_vars=}")
def contradict(clause):
return any(-x in clause for x in clause if x > 0)
def interleave(l):
ans = []
for i in range(0,len(l)//2):
ans.append(l[i])
ans.append(l[i+len(l)//2])
return ans
#iterleave to more quickly eliminate variables
prod_of_dnf = interleave(prod_of_dnf)
with open("./data.txt",'w+') as f:
for x in prod_of_dnf:
f.write(pprint.pformat(x,compact=True))
f.write("\n-----------\n")
import cProfile
def analyze(d,ass):
from collections import defaultdict
ans = defaultdict(lambda : [0,0])
for clause in d:
for v in clause:
if v > 0:
ans[abs(v)][0]+=1
else:
ans[abs(v)][1]+=1
for k in ans:
ans[k] = ans[k][0] / sum(ans[k])
for k in ass:
del ans[k]
return ans
def solve():
assumputions = []
while len(prod_of_dnf) > 1:
print(f"{len(prod_of_dnf)} hints left to merge")
a = prod_of_dnf.pop()
b = prod_of_dnf.pop()
print(f"{len(a)=} {len(b)=}")
if False and len(a) > 10000:
stats = analyze(a,assumputions)
minkey = min(stats,key=stats.get)
maxkey = max(stats,key=stats.get)
print(f"assuming {minkey} is false :{stats[minkey]}")
a = [x for x in a if minkey not in x]
b = [x for x in b if minkey not in x]
assumputions.append(minkey)
elif len(assumputions) >= 1:
for c in assumputions:
b = [x for x in b if c not in x]
d = []
for clause in a:
for other_clause in b:
combined = clause|other_clause
if not contradict(combined):
d.append(combined)
prod_of_dnf.append(frozenset(d))
# cProfile.run('solve()')
solve()
possible_outcomes = list(prod_of_dnf)[0]
mat = np.zeros((BOARDSIZE,BOARDSIZE),dtype=int)
for c in list(possible_outcomes)[0]:
if c > 0:
r,c = idx_to_cord(c)
mat[r,c]=1
print(mat)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment