solve.py (4504B)
1import sys 2sys.path.append("../common") 3import aoc 4 5def parse_line(l): 6 s = l.split(", ") 7 if s[0].startswith("y="): 8 s = s[::-1] 9 10 res = [[int(x) for x in v.split("=")[1].split("..")] for v in s] 11 return res 12 13constraints = [parse_line(l) for l in aoc.data.split("\n")] 14 15xmin = min(c[0][0] for c in constraints)-1 16xmax = max(c[0][-1] for c in constraints)+1 17ymin = min(c[1][0] for c in constraints) 18ymax = max(c[1][-1] for c in constraints) 19xdif = xmax - xmin + 1 20ydif = ymax - ymin + 1 21 22vmap = [[0 for x in range(xdif)] for y in range(ydif)] 23 24def set_map(x, y, v): 25 global vmap 26 if y < ymin or y > ymax or x < xmin or x > xmax: 27 return 28 vmap[y-ymin][x-xmin] = v 29 30def get_map(x, y): 31 global vmap 32 if x > xmax or x < xmin: 33 return 1 34 elif y > ymax: 35 return 0 36 return vmap[y-ymin][x-xmin] 37 38def drawWall(c): 39 if len(c[0]) == 1: 40 for y in range(c[1][0], c[1][1] + 1): 41 set_map(c[0][0], y, 1) 42 else: 43 for x in range(c[0][0], c[0][1] + 1): 44 set_map(x, c[1][0], 1) 45 46for c in constraints: 47 drawWall(c) 48 49spring = (500, 0) 50 51 52### SETUP END 53 54 55def interpretChar(v): 56 chars = [".", "#", "|", "~"] 57 return chars[v] 58 59def drawMap(): 60 for y in range(ydif): 61 aoc.debug("".join([interpretChar(v) for v in vmap[y]])) 62 63def fwriteMap(): 64 f = open("output","w+") 65 for y in range(ydif): 66 f.write("".join([interpretChar(v) for v in vmap[y]])+"\n") 67 f.close() 68 69def isstatic(p): 70 return get_map(p[0], p[1]) in (1, 3) 71 72def isfree(p): 73 return get_map(p[0], p[1]) == 0 74 75def move(p): 76 x = p[0] 77 y = p[1] 78 if isfree((x, y+1)): 79 return (x, y+1) 80 onblock = isstatic((x, y+1)) 81 if not onblock: 82 return (x,y) 83 npos = [(x + dir, y) for dir in [-1, 1]] 84 npos = [np for np in npos if isfree(np) and onblock] 85 if len(npos) > 1: 86 return npos 87 elif len(npos) == 1: 88 return npos[0] 89 return (x, y) 90 91def fillfloor(p): 92 onblock = True 93 isblock = False 94 x = p[0] 95 while onblock and not isblock and x >= xmin: 96 x -= 1 97 isblock = isstatic((x, p[1])) 98 onblock = isstatic((x, p[1]+1)) 99 if not isblock: 100 return None # edge 101 lx = x+1 102 103 onblock = True 104 isblock = False 105 x = p[0] 106 while onblock and not isblock and x <= xmax: 107 x += 1 108 isblock = isstatic((x, p[1])) 109 onblock = isstatic((x, p[1]+1)) 110 if not isblock: 111 return None 112 rx = x-1 113 114 return [(i, p[1]) for i in range(lx, rx+1)] 115 116def count_w_flowing(): 117 water = 0 118 for y in range(ymin, ymax+1): 119 for x in range(xmin, xmax+1): 120 if get_map(x,y) == 2: 121 water += 1 122 return water 123 124def count_w_static(): 125 water = 0 126 for y in range(ymin, ymax+1): 127 for x in range(xmin, xmax+1): 128 if get_map(x,y) == 3: 129 water += 1 130 return water 131 132def simulate(): 133 heads = [spring] 134 while len(heads) > 0: 135 cp = heads[-1] 136 if isstatic((cp[0], cp[1]+1)): 137 # solid below => expand 138 res = fillfloor(cp) 139 if res: 140 for p in res: 141 set_map(p[0], p[1], 3) 142 nhead = None 143 for x in range(res[0][0], res[-1][0]+1): 144 np = (x, res[0][1]-1) 145 if get_map(np[0], np[1]) == 2: 146 nhead = np 147 break 148 if nhead == None: # head got trapped 149 heads.pop() 150 else: 151 heads[-1] = nhead 152 continue 153 154 res = move(cp) 155 if type(res[0]) == tuple: 156 heads.pop() 157 heads += res 158 for p in res: 159 set_map(p[0], p[1], 2) 160 else: 161 if res != cp: 162 if res[1] <= ymax: 163 set_map(res[0], res[1], 2) 164 heads[-1] = res 165 else: 166 heads.pop() 167 else: 168 heads.pop() 169 170 if aoc.debug_lvl: 171 aoc.debug(heads) 172 input() 173 fwriteMap() 174 175def solve1(args): 176 simulate() 177 return count_w_flowing() + count_w_static() 178 179def solve2(args): 180 simulate() 181 return count_w_static() 182 183aoc.run(solve1, solve2, sols=[39557, 32984])