# パッケージ %matplotlib inline import numpy as np import cv2 as cv # opencv import matplotlib import matplotlib.pyplot as plt # matplotlibの描画系 from matplotlib import cm from collections import OrderedDict import os import math import re import glob import time def split(string): re_list = re.split('[ X#@,()\t\n]',string) while '' in re_list: re_list.remove('') return re_list def readQ(filename): Q = {'BLOCK':{}} max_l = 0 with open(filename, 'r') as file: while True: str_line = file.readline() if not str_line: break result = split(str_line) if result == []: continue if result[0] == 'SIZE': Q['w'] = int(result[1]) Q['h'] = int(result[2]) elif result[0] == 'BLOCK_NUM': Q['num_b'] = int(result[1]) Q['n'] = Q['num_b'] elif result[0] == 'BLOCK': index = int(result[1]) w = int(result[2]) h = int(result[3]) bs = Q['BLOCK'] cells = {} bs[index] = {'index':index,'w':w,'h':h,'cells':cells} for i in range(h): subline = file.readline() subr = split(subline) for j in range(w): if subr[j] != '0': cells[(j,i)] = subr[j] if subr[j] != '+': num = int(subr[j]) if num > max_l: max_l = num Q['num_l'] = max_l return Q def readA(filename): A = {'BLOCK':{}} with open(filename, 'r') as file: i = 0 while True: str_line = file.readline() if not str_line: break result = split(str_line) if result == []: continue if result[0] == 'SIZE': A['w'] = int(result[1]) A['h'] = int(result[2]) A['map'] = np.zeros((A['h'],A['w']), dtype=int) elif result[0] == 'BLOCK': index = int(result[1]) x = int(result[2]) y = int(result[3]) bs = A['BLOCK'] cells = {} bs[index] = {'index':index,'x':x,'y':y} else: for j in range(A['w']): A['map'][i,j] = int(result[j]) i += 1 return A def index2color(index, mode='cell'): if mode == 'cell': if index == -1: R,G,B,Alpha = 1,1,1,1 else: R,G,B,Alpha = cm.tab20((index*2)%20) else: R,G,B,Alpha = cm.tab20((index*2+1)%20) return np.array([R,G,B]) def QA2img(Q,A): w_grid = 5 w_line = 25 len_cell = 50 margin = (len_cell + w_grid - w_line)//2 white = [1,1,1] black = [0,0,0] red = [1,0,0] w_max, h_max = Q['w'],Q['h'] w,h,n = A['w'],A['h'],Q['n'] map_A = A['map'] bs_q = Q['BLOCK'] bs_a = A['BLOCK'] img = np.zeros((h_max*len_cell+w_grid,w_max*len_cell+w_grid,3)) img[:,:] = white img[[i for i in range(h_max*len_cell+w_grid) if (i%len_cell)0: TF[num] = True else: TF[-num] = False w = Q['w'] h = Q['h'] A = {'BLOCK':{}} A['w'] = w A['h'] = h A['map'] = np.zeros((h,w), dtype=int) num_b = len(Q['BLOCK']) num_l = Q['num_l'] for i in range(1, num_b+1): A['BLOCK'][i] = {'index':i,'x':0,'y':0} for i in range(h): for j in range(w): for b in range(1,num_b+1): key = f'b{b}_{j}_{i}' if key not in nodes.keys(): break index = nodes[key] if TF[index]: A['BLOCK'][b]['x'] = j A['BLOCK'][b]['y'] = i for l in range(1,num_l+1): key = f'l{l}_{j}_{i}' if key not in nodes.keys(): break index = nodes[key] if TF[index]: A['map'][i][j] = l return A def debug_satA(filename, Q, nodes, TF=None): TF = [False] * (len(nodes)+1) A = read_satA(filename, Q, nodes, TF) w = Q['w'] h = Q['h'] num_b = len(Q['BLOCK']) num_l = Q['num_l'] for b in range(1,num_b+1): b_board = np.zeros((w,h),dtype=bool) for i in range(h): for j in range(w): key = f'b{b}_{j}_{i}' index = nodes[key] b_board[j,i] = TF[index] print(f'b{b}=') print(b_board) for l in range(1,num_l+1): l_board = np.zeros((w,h),dtype=bool) for i in range(h): for j in range(w): key = f'l{l}_{j}_{i}' index = nodes[key] l_board[j,i] = TF[index] print(f'l{l}=') print(l_board) return A def generate_sat(Q): nodes = {} cnfs = [] num_b = len(Q['BLOCK']) num_l = Q['num_l'] w = Q['w'] = 20 h = Q['h'] = 20 # ラインからブロック番号, 位置を逆引き l2b = [[] for _ in range(num_l+1)] for b in range(1, num_b+1): cells = Q['BLOCK'][b]['cells'] for dx,dy in cells.keys(): v = cells[(dx,dy)] if v == '+' or v == '0': l2b[0].append((b,-dx,-dy)) else: index = int(v) l2b[index].append((b,-dx,-dy)) for b in range(1,num_b+1): for i in range(h): for j in range(w): nodes[f'b{b}_{j}_{i}'] = len(nodes) + 1 for l in range(1, num_l+1): for i in range(h): for j in range(w): nodes[f'l{l}_{j}_{i}'] = len(nodes) + 1 # b one-hot for b in range(1,num_b+1): cnf = {} cnfs.append(cnf) for i in range(h): for j in range(w): cnf[f'b{b}_{j}_{i}'] = '1' for i in range(h): for j in range(w): for i2 in range(i, h): for j2 in range(w): if i < i2 or j < j2: cnf = {} cnfs.append(cnf) cnf[f'b{b}_{j}_{i}'] = '-1' cnf[f'b{b}_{j2}_{i2}'] = '-1' # line 0 or 1 for i in range(h): for j in range(w): for l in range(1, num_l): for l2 in range(l+1, num_l+1): cnf = {} cnfs.append(cnf) cnf[f'l{l}_{j}_{i}'] = '-1' cnf[f'l{l2}_{j}_{i}'] = '-1' # line孤立禁止 for i in range(h): for j in range(w): for l in range(1, num_l+1): around = [(1,0),(-1,0),(0,1),(0,-1)] cnf = {} cnfs.append(cnf) cnf[f'l{l}_{j}_{i}'] = '-1' for dx,dy in around: if j+dx < 0 or j+dx >= w or i+dy < 0 or i+dy >= h: continue cnf[f'l{l}_{j+dx}_{i+dy}'] = '1' # line三叉禁止 for i in range(h): for j in range(w): for l in range(1, num_l+1): around = [(1,0),(-1,0),(0,1),(0,-1)] new_around = [] for dx,dy in around: if j+dx < 0 or j+dx >= w or i+dy < 0 or i+dy >= h: continue new_around.append((dx,dy)) if len(new_around) <= 2: continue elif len(new_around) <= 3: cnf = {} cnfs.append(cnf) cnf[f'l{l}_{j}_{i}'] = '-1' for dx,dy in new_around: cnf[f'l{l}_{j+dx}_{i+dy}'] = '-1' elif len(new_around) <= 4: for dx,dy in new_around: for dx2,dy2 in new_around: if dx*3+dy >= dx2*3+dy2: continue for dx3,dy3 in new_around: if dx2*3+dy2 >= dx3*3+dy3: continue cnf = {} cnfs.append(cnf) cnf[f'l{l}_{j}_{i}'] = '-1' cnf[f'l{l}_{j+dx}_{i+dy}'] = '-1' cnf[f'l{l}_{j+dx2}_{i+dy2}'] = '-1' cnf[f'l{l}_{j+dx3}_{i+dy3}'] = '-1' # blockがはみ出る位置には置けない for i in range(h): for j in range(w): for b in range(1, num_b+1): cells = Q['BLOCK'][b]['cells'] for dx,dy in cells: if j+dx < 0 or j+dx >= w or i+dy < 0 or i+dy >= h: cnf = {} cnfs.append(cnf) cnf[f'b{b}_{j}_{i}'] = '-1' break # block位置に対してライン位置が決定 for i in range(h): for j in range(w): for b in range(1, num_b+1): cells = Q['BLOCK'][b]['cells'] flag = False for dx,dy in cells: if j+dx < 0 or j+dx >= w or i+dy < 0 or i+dy >= h: break l_str = cells[(dx,dy)] if l_str == '+': for l in range(1,num_l+1): cnf = {} cnfs.append(cnf) cnf[f'b{b}_{j}_{i}'] = '-1' cnf[f'l{l}_{j+dx}_{i+dy}'] = '-1' elif l_str != '0': for l in range(1,num_l+1): cnf = {} cnfs.append(cnf) cnf[f'b{b}_{j}_{i}'] = '-1' if l == int(l_str): cnf[f'l{l}_{j+dx}_{i+dy}'] = '1' else: cnf[f'l{l}_{j+dx}_{i+dy}'] = '-1' # block同士の衝突禁止 for i in range(h): for j in range(w): for b in range(1, num_b+1): cells = Q['BLOCK'][b]['cells'] for i2 in range(i-4,i+5): if i2 < 0 or i2 >= h: continue for j2 in range(j-4,j+5): if j2 < 0 or j2 >= w: continue for b2 in range(b+1, num_b+1): cells2 = Q['BLOCK'][b2]['cells'] flag = False for dx,dy in cells.keys(): if flag: break if j+dx < 0 or j+dx >= w or i+dy < 0 or i+dy >= h: continue for dx2,dy2 in cells2.keys(): if j2+dx2 < 0 or j2+dx2 >= w or i2+dy2 < 0 or i2+dy2 >= h: continue if i+dy == i2+dy2 and j+dx == j2+dx2: if not flag: flag = True cnf = {} cnfs.append(cnf) cnf[f'b{b}_{j}_{i}'] = '-1' cnf[f'b{b2}_{j2}_{i2}'] = '-1' # block上にないlineは周囲2マスに接続 for i in range(h): for j in range(w): for l in range(1, num_l+1): around = [(1,0),(-1,0),(0,1),(0,-1)] new_around = [] for dx,dy in around: if j+dx < 0 or j+dx >= w or i+dy < 0 or i+dy >= h: continue new_around.append((dx,dy)) bdxdylist = l2b[l] if len(new_around) <= 2: for dx,dy in new_around: cnf = {} cnfs.append(cnf) for b,mdx,mdy in bdxdylist: if i+mdy < 0 or i+mdy >= h or j+mdx < 0 or j+mdx >= w: continue cnf[f'b{b}_{j+mdx}_{i+mdy}'] = '1' cnf[f'l{l}_{j}_{i}'] = '-1' cnf[f'l{l}_{j+dx}_{i+dy}'] = '1' elif len(new_around) <= 3: for dx,dy in new_around: for dx2,dy2 in new_around: if dx*3+dy <= dx2*3+dy2: continue cnf = {} cnfs.append(cnf) for b,mdx,mdy in bdxdylist: if i+mdy < 0 or i+mdy >= h or j+mdx < 0 or j+mdx >= w: continue cnf[f'b{b}_{j+mdx}_{i+mdy}'] = '1' cnf[f'l{l}_{j}_{i}'] = '-1' cnf[f'l{l}_{j+dx}_{i+dy}'] = '1' cnf[f'l{l}_{j+dx2}_{i+dy2}'] = '1' elif len(new_around) == 4: for dx,dy in new_around: for dx2,dy2 in new_around: if dx*3+dy >= dx2*3+dy2: continue for dx3,dy3 in new_around: if dx2*3+dy2 >= dx3*3+dy3: continue cnf = {} cnfs.append(cnf) for b,mdx,mdy in bdxdylist: if i+mdy < 0 or i+mdy >= h or j+mdx < 0 or j+mdx >= w: continue cnf[f'b{b}_{j+mdx}_{i+mdy}'] = '1' cnf[f'l{l}_{j}_{i}'] = '-1' cnf[f'l{l}_{j+dx}_{i+dy}'] = '1' cnf[f'l{l}_{j+dx2}_{i+dy2}'] = '1' cnf[f'l{l}_{j+dx3}_{i+dy3}'] = '1' # block上にあるlineは周囲2マスに接続禁止 for i in range(h): for j in range(w): for l in range(1, num_l+1): around = [(1,0),(-1,0),(0,1),(0,-1)] new_around = [] for dx,dy in around: if j+dx < 0 or j+dx >= w or i+dy < 0 or i+dy >= h: continue new_around.append((dx,dy)) bdxdylist = l2b[l] if len(new_around) <= 2: dx,dy = new_around[0] dx2,dy2 = new_around[1] for b,mdx,mdy in bdxdylist: if i+mdy < 0 or i+mdy >= h or j+mdx < 0 or j+mdx >= w: continue cnf = {} cnfs.append(cnf) cnf[f'b{b}_{j+mdx}_{i+mdy}'] = '-1' cnf[f'l{l}_{j}_{i}'] = '-1' cnf[f'l{l}_{j+dx}_{i+dy}'] = '-1' cnf[f'l{l}_{j+dx2}_{i+dy2}'] = '-1' elif len(new_around) <= 3: for dx,dy in new_around: for dx2,dy2 in new_around: if dx*3+dy >= dx2*3+dy2: continue for b,mdx,mdy in bdxdylist: if i+mdy < 0 or i+mdy >= h or j+mdx < 0 or j+mdx >= w: continue cnf = {} cnfs.append(cnf) cnf[f'b{b}_{j+mdx}_{i+mdy}'] = '-1' cnf[f'l{l}_{j}_{i}'] = '-1' cnf[f'l{l}_{j+dx}_{i+dy}'] = '-1' cnf[f'l{l}_{j+dx2}_{i+dy2}'] = '-1' elif len(new_around) == 4: for dx,dy in new_around: for dx2,dy2 in new_around: if dx*3+dy >= dx2*3+dy2: continue for b,mdx,mdy in bdxdylist: if i+mdy < 0 or i+mdy >= h or j+mdx < 0 or j+mdx >= w: continue cnf = {} cnfs.append(cnf) cnf[f'b{b}_{j+mdx}_{i+mdy}'] = '-1' cnf[f'l{l}_{j}_{i}'] = '-1' cnf[f'l{l}_{j+dx}_{i+dy}'] = '-1' cnf[f'l{l}_{j+dx2}_{i+dy2}'] = '-1' return nodes,cnfs def main(): Q = readQ('./adc2019problem/Q001_10X10_b8_l11.txt') #Q = readQ('./adc2019problem/Q002_10X10_b8_l9.txt') #Q = readQ('./adc2019problem/Q003_10X10_b5_l5.txt') #Q = readQ('./adc2019problem/Q004_10X10_b8_l9.txt') #Q = readQ('./adc2019problem/Q005_10X10_b7_l6.txt') #Q = readQ('./adc2019problem/Q006_10X10_b8_l9.txt') #Q = readQ('./adc2019problem/Q007_10X10_b7_l8.txt') #Q = readQ('./adc2019problem/Q008_10X10_b10_l0.txt') #Q = readQ('./adc2019problem/Q009_10X10_b7_l9.txt') #Q = readQ('./adc2019problem/Q010_10X10_b20_l24.txt') #Q = readQ('./adc2019problem/Q013_10X10_b8_l9.txt') #Q = readQ('./adc2019problem/Q014_10X10_b9_l9.txt') #Q = readQ('./adc2019problem/Q015_10X10_b8_l9.txt') start_time = time.time() nodes,cnfs = generate_sat(Q) print_cnf(nodes, cnfs) os.system('minisat p.txt a.txt') A = read_satA('a.txt', Q, nodes) #A = debug_satA('a.txt', Q, nodes) end_time= time.time() print(f"経過時間:{end_time - start_time}") img = QA2img(Q,A) plt.imshow(img) main()