#!/usr/bin/env python3 # import numpy as np from functools import reduce from re import findall from copy import deepcopy from collections import defaultdict import sys # filename = "in/day23.ref" # filename = 'in/day23_2.ref' filename = "in/day23.pzl" data = open(filename).read() lines = [line for line in data.rstrip('\n').split('\n')] print(lines) res1 = 0 res2 = 0 def check_N(E, y, x): if all( [(y+dy, x+dx) not in E for dy,dx in [[-1,0], [-1,1], [-1,-1]]] ): return y-1, x else: return None def check_S(E, y, x): if all( [(y+dy, x+dx) not in E for dy,dx in [[1,0], [1,1], [1,-1]]] ): return y+1, x else: return None def check_W(E, y, x): if all( [(y+dy, x+dx) not in E for dy,dx in [[0,-1], [1,-1], [-1,-1]]] ): return y, x-1 else: return None def check_E(E, y, x): if all( [(y+dy, x+dx) not in E for dy,dx in [[0,1], [1,1], [-1,1]]] ): return y, x+1 else: return None E = set() N = list() for y,line in enumerate(lines): for x,val in enumerate(line): if val == '#': E.add((y,x)) N.append( (y,x, [check_N, check_S, check_W, check_E]) ) # print(E) # print(N) def get_max(E): min_y = 1000 max_y = 0 min_x = 1000 max_x = 0 for y,x in E: min_y = min(min_y, y) max_y = max(max_y, y) min_x = min(min_x, x) max_x = max(max_x, x) return min_y, max_y, min_x, max_x def print_elfs(E): min_y, max_y, min_x, max_x = get_max(E) for y in range(min_y - 5, max_y + 5): for x in range(min_x - 5, max_x + 5): if y == 0 and x == 0: print('o', end='') elif (y,x) in E: print('#', end='') else: print('.', end='') print() print() print() def get_new_pos(E, y, x, checks): checks = checks[:] move = False for dy,dx in [0,1], [0,-1], [1,0], [-1,0], [1,1], [1,-1], [-1,-1], [-1,1]: if (y+dy, x+dx) in E: move = True break if move == False: checks.append(checks.pop(0)) return y, x, checks for i,check in enumerate(checks): ret = check(E,y,x) if ret != None: y, x = ret break else: checks.append(checks.pop(0)) return y,x, checks # print('changing order', y, x, i, checks) # checks.append(checks.pop(i)) checks.append(checks.pop(0)) return y,x, checks print_elfs(E) for round_n in range(1,1000+1): # for round_n in range(1,10+1): print(round_n) Ec = E.copy() dest = defaultdict(list) for y,x in E: for i, (yy,xx,_) in enumerate(N): if yy == y and xx == x: break else: assert False checks = N[i][2] ny,nx,checks = get_new_pos(E,y,x,checks) dest[(ny,nx)].append((y,x)) N[i] = (y,x, checks) # print(dest) for ey,ex in dest: if len(dest[(ey,ex)]) > 1: continue sy,sx = dest[(ey,ex)][0] # print(sy,sx, ey,ex) E.remove((sy,sx)) E.add((ey,ex)) for i, (yy,xx,checks) in enumerate(N): if yy == sy and xx == sx: break else: assert False N[i] = (ey,ex,checks) # print(E) # print(N) print_elfs(E) if E == Ec: break res1 = 0 min_y, max_y, min_x, max_x = get_max(E) for y in range(min_y, max_y+1): for x in range(min_x, max_x+1): if (y,x) not in E: res1 += 1 print('res1:', res1) print('res2:', res2)