65 views
``` python from itertools import product from collections import defaultdict from pickle import dump, load import sys polyminos_txt = [ ['##', '#.', '##'], ['###', '###'], ['####', '#...'], ['..#.', '####'], ['###', '##.'], ['###', '#..', '#..'], ['##.', '.#.', '.##'], ['.###', '##..'] ] colors = { 'A': (228, 192, 54), 'B': (246, 93, 88), 'C': (240, 131, 62), 'D': (223, 193, 157), 'E': (168, 85, 30), 'F': (107, 192, 73), 'G': (7, 110, 151), 'H': (197, 76, 121) } def poly2coord(polymino): w, h = len(polymino[0]), len(polymino) p = [] for x, y in product(range(w), range(h)): if polymino[y][x] == '#': p.append((x, y)) return p def valid(c): x, y = c if y in [0, 1]: return x in range(6) if y == 6: return x in range(3) if y in range(2, 6): return x in range(7) return False def rotate(polymino): w, h = len(polymino[0]), len(polymino) p = [] for x in range(w): s = '' for y in range(h): s = polymino[y][x] + s p.append(s) return p def translate(polymino, x, y): return [(x0+x, y0+y) for (x0, y0) in polymino] def polymino_to_mask(p): m = 0 for x, y in p: m |= 1 << (x + y * 7) return m def sym(p): return [l for l in reversed(p)] def generate_all_polyminos(): polyminos = [] for p0 in polyminos_txt: p1 = rotate(p0) p2 = rotate(p1) p3 = rotate(p2) p0s, p1s, p2s, p3s = map(sym, (p0, p1, p2, p3)) instanciations = set() for pb in [p0,p1,p2,p3,p0s,p1s,p2s,p3s]: p = poly2coord(pb) for (x, y) in product(range(7), repeat=2): pt = translate(p, x, y) if all(map(valid, pt)): instanciations.add(polymino_to_mask(pt)) polyminos.append(instanciations) return polyminos polyminos = generate_all_polyminos() def polymino_index(p): for i, l in enumerate(polyminos): if p in l: return chr(ord('A')+i) raise ValueError def pprint(sol): s = [' '] * 49 for y in range(7): for x in range(7): if valid((x, y)): s[7*y + x] = '.' for i, p in enumerate(sol): if p & (1 << (7 * y + x)) != 0: c = polymino_index(p) s[7*y + x] = c return s def freebits(board): free = [] for y in range(7): for x in range(7): if valid((x, y)) and board & (1 << (x + 7*y)) == 0: free.append((x, y)) return free months = ['Jan', 'Fev', 'Mar', 'Avr', 'Mai', 'Jui', 'Jul', 'Aou', 'Sep', 'Oct', 'Nov', 'Dec'] # J F M A M J # J A S O N D # 1 2 3 4 5 6 7 # 8 9 10 11 12 13 14 # 15 16 17 18 19 20 21 # 22 23 24 25 26 27 28 # 29 30 31 def cal(c): x, y = c if y < 2: m = x + 6 * y return months[m] d = x + 7 * (y - 2) + 1 return d def search(board, current, counter, sol=()): if current >= len(polyminos): cal1, cal2 = map(cal, freebits(board)) im = pprint(sol) print(cal1, cal2, freebits(board), ''.join(im)) counter[cal1, cal2].append(im) return for p in polyminos[current]: if p & board == 0: search(p | board, current+1, counter, sol + (p,)) if __name__ == "__main__": if 'search' in sys.argv: counter = defaultdict(list) search(0, 0, counter) dump(counter, open('laurent.pickle', 'wb')) else: counter = load(open('laurent.pickle', 'rb')) l = [(c1, c2) if c1 in months else (c2, c1) for c1, c2 in counter.keys() if (c1 in months and c2 not in months) or (c2 in months and c1 not in months)] l.sort() M = { 'Jan': 31, 'Fev': 29, 'Mar': 31, 'Avr': 30, 'Mai': 31, 'Jui': 30, 'Jul': 31, 'Aou': 31, 'Sep': 30, 'Oct': 31, 'Nov': 30, 'Dec': 31 } if 'image' not in sys.argv: sys.exit(0) from PIL import Image, ImageFont, ImageDraw font = ImageFont.load_default(8) ndays = 0 max_sol = 0 for month in months: for day in range(1, M[month]+1): ndays += 1 max_sol = max(max_sol, len(counter[month, day])) text_padding = 40 # each month is # +DDD------+ .... # | s s s s | # | s s s s | # | s s s s | # +---------+ border = 8 solution = 8 day_width = border * 2 + 16 * solution day_height = border * 2 + 14 * solution month_width = 7 * day_width month_height = 5 * day_height total_width = 4 * month_width total_height = 3 * month_height im = Image.new('RGB', (total_width, total_height), (64, 64, 64)) draw = ImageDraw.Draw(im) ndays = 0 for m, month in enumerate(months): mx, my = (m % 4) * month_width, (m // 4) * month_height mcol = (128, 128, 128) if (m % 4 + m // 4) % 2 == 0 else (150, 150, 150) for day in range(1, M[month]+1): dx, dy = ((day-1) % 7) * day_width, ((day-1) // 7) * day_height bx, by = mx + dx, my + dy draw.rectangle((bx+border//4, by+border//4, bx + day_width - border // 2, by + day_height - border // 2), fill=mcol) draw.text((bx + 8, by), str(day) + ' ' + month, font=font, fill=(0, 0, 0)) for i, ims in enumerate(counter[month, day] + counter[day, month]): sol_im = Image.new('RGB', (7, 7)) for x, y in product(range(7), repeat=2): c = ims[7*y + x] if c == ' ': continue if c == '.': col = (255, 255, 255) else: col = colors[c] sol_im.putpixel((x, y), col) im.paste(sol_im, (bx + border + 8 * (i % 16), by + border + 4 + 8 * (i // 16))) ndays += 1 im.save('solutions.png') ```