``` 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')
```