#!/usr/bin/python3 # -*- coding: utf-8 -*- import sys from z3 import * # cell type, angle, (pseudo)graphical representation symbols={("0", 0): " ", ("2a", 0): "┃", ("2a", 90): "━", ("2b", 0): "┏", ("2b", 90): "┓", ("2b",180): "┛", ("2b",270): "┗", ("3", 0): "┣", ("3", 90): "┳", ("3", 180): "┫", ("3", 270): "┻", ("4", 0): "╋"} def print_model(m): # print angles: for r in range(HEIGHT): for c in range(WIDTH): t=cells_type[r][c] angle=int(str(m[A[r][c]])) sys.stdout.write("%3d " % angle) print ("") # print pipes: for r in range(HEIGHT): for c in range(WIDTH): t=cells_type[r][c] angle=int(str(m[A[r][c]])) sys.stdout.write(symbols[(t, angle)]+" ") print ("") print ("") s=Solver() HEIGHT=8 WIDTH=16 T=[[Bool('cell_%d_%d_top' % (r, c)) for c in range(WIDTH)] for r in range(HEIGHT)] B=[[Bool('cell_%d_%d_bottom' % (r, c)) for c in range(WIDTH)] for r in range(HEIGHT)] R=[[Bool('cell_%d_%d_right' % (r, c)) for c in range(WIDTH)] for r in range(HEIGHT)] L=[[Bool('cell_%d_%d_left' % (r, c)) for c in range(WIDTH)] for r in range(HEIGHT)] A=[[Int('cell_%d_%d_angle' % (r, c)) for c in range(WIDTH)] for r in range(HEIGHT)] # initial configuration cells_type=[ ["0", "0", "2b", "3", "2a", "2a", "2a", "3", "3", "2a", "3", "2b", "2b", "2b", "0", "0"], ["2b", "2b", "3", "2b", "0", "0", "2b", "3", "3", "3", "3", "3", "4", "2b", "0", "0"], ["3", "4", "2b", "0", "0", "0", "3", "2b", "2b", "4", "2b", "3", "4", "2b", "2b", "2b"], ["2b", "4", "3", "2a", "3", "3", "3", "2b", "2b", "3", "3", "3", "2a", "2b", "4", "3"], ["0", "2b", "3", "2b", "3", "4", "2b", "3", "3", "2b", "3", "3", "3", "0", "2a", "2a"], ["0", "0", "2b", "2b", "0", "3", "3", "4", "3", "4", "3", "3", "3", "2b", "3", "3"], ["0", "2b", "3", "2b", "0", "3", "3", "4", "3", "4", "4", "3", "0", "3", "4", "3"], ["0", "2b", "3", "3", "2a", "3", "2b", "2b", "3", "3", "3", "3", "2a", "3", "3", "2b"]] # shorthand variables for True and False: t=True f=False # "top" of each cell must be equal to "bottom" of the cell above # "bottom" of each cell must be equal to "top" of the cell below # "left" of each cell must be equal to "right" of the cell at left # "right" of each cell must be equal to "left" of the cell at right for r in range(HEIGHT): for c in range(WIDTH): if r!=0: s.add(T[r][c]==B[r-1][c]) if r!=HEIGHT-1: s.add(B[r][c]==T[r+1][c]) if c!=0: s.add(L[r][c]==R[r][c-1]) if c!=WIDTH-1: s.add(R[r][c]==L[r][c+1]) # "left" of each cell of first column shouldn't have any connection # so is "right" of each cell of the last column for r in range(HEIGHT): s.add(L[r][0]==f) s.add(R[r][WIDTH-1]==f) # "top" of each cell of the first row shouldn't have any connection # so is "bottom" of each cell of the last row for c in range(WIDTH): s.add(T[0][c]==f) s.add(B[HEIGHT-1][c]==f) for r in range(HEIGHT): for c in range(WIDTH): ty=cells_type[r][c] if ty=="0": s.add(A[r][c]==f) s.add(T[r][c]==f, B[r][c]==f, L[r][c]==f, R[r][c]==f) if ty=="2a": s.add(Or(And(A[r][c]==0, L[r][c]==f, R[r][c]==f, T[r][c]==t, B[r][c]==t), # ┃ And(A[r][c]==90, L[r][c]==t, R[r][c]==t, T[r][c]==f, B[r][c]==f))) # ━ if ty=="2b": s.add(Or(And(A[r][c]==0, L[r][c]==f, R[r][c]==t, T[r][c]==f, B[r][c]==t), # ┏ And(A[r][c]==90, L[r][c]==t, R[r][c]==f, T[r][c]==f, B[r][c]==t), # ┓ And(A[r][c]==180, L[r][c]==t, R[r][c]==f, T[r][c]==t, B[r][c]==f), # ┛ And(A[r][c]==270, L[r][c]==f, R[r][c]==t, T[r][c]==t, B[r][c]==f))) # ┗ if ty=="3": s.add(Or(And(A[r][c]==0, L[r][c]==f, R[r][c]==t, T[r][c]==t, B[r][c]==t), # ┣ And(A[r][c]==90, L[r][c]==t, R[r][c]==t, T[r][c]==f, B[r][c]==t), # ┳ And(A[r][c]==180, L[r][c]==t, R[r][c]==f, T[r][c]==t, B[r][c]==t), # ┫ And(A[r][c]==270, L[r][c]==t, R[r][c]==t, T[r][c]==t, B[r][c]==f))) # ┻ if ty=="4": s.add(A[r][c]==0) s.add(T[r][c]==t, B[r][c]==t, L[r][c]==t, R[r][c]==t) # ╉ print (s.check()) print_model (s.model())