diff options
-rw-r--r-- | 14.py | 91 |
1 files changed, 91 insertions, 0 deletions
@@ -0,0 +1,91 @@ +from utils import open_day, Point2D, sliding_window, inbounds +from enum import Enum, auto +from itertools import count + +def display(sandbox, minx, miny, maxx, maxy): + for y in range(miny, maxy + 1): + line = [] + for x in range(minx, maxx + 1): + p = Point2D(x, y) + if p in sandbox: + if sandbox[p] == Tile.WALL: + line.append('#') + else: + line.append('o') + else: + line.append('.') + if x == 500 and y == 0: + line[-1] = '+' + print(''.join(line)) + +def point_from_str(s): + return Point2D(*(int(d) for d in s.split(','))) + +class Tile(Enum): + WALL = auto() + SAND = auto() + +class Sandbox: + def __init__(self, source=Point2D(500, 0)): + self.tiles = dict() + self.source = source + self.minx, self.maxx = source.x, source.x + self.miny, self.maxy = source.y, source.y + def __setitem__(self, key, value): + if key.x < self.minx: self.minx = key.x + elif key.x > self.maxx: self.maxx = key.x + if key.y < self.miny: self.miny = key.y + elif key.y > self.maxy: self.maxy = key.y + self.tiles[key] = value + def __getitem__(self, key): + return self.tiles[key] + def __str__(self): + lines = [] + for y in range(self.miny, self.maxy + 1): + line = [] + for x in range(self.minx, self.maxx + 1): + p = Point2D(x, y) + match self.tiles.get(p): + case Tile.WALL: line.append('#') + case Tile.SAND: line.append('o') + case None: line.append('.') + if x == self.source.x and y == self.source.y: + line[-1] = '+' + lines.append(''.join(line)) + return '\n'.join(lines) + def simulate(self): + bounds = (Point2D(self.minx, self.miny), Point2D(self.maxx, self.maxy)) + for units in count(): + sandpos = self.source + while self.source not in self.tiles and inbounds(sandpos, *bounds): + for d in (Point2D( 0, 1), Point2D(-1, 1), Point2D( 1, 1)): + if sandpos + d not in self.tiles: + sandpos += d + break + else: + self.tiles[sandpos] = Tile.SAND + break + else: + break + return units + +sandbox = Sandbox() + +with open_day(14) as f: + for line in f: + for b, e in sliding_window(map(point_from_str, line.rstrip().split(' -> ')), 2): + minlx, maxlx = min(b.x, e.x), max(b.x, e.x) + minly, maxly = min(b.y, e.y), max(b.y, e.y) + for x in range(minlx, maxlx + 1): + for y in range(minly, maxly + 1): + sandbox[Point2D(x, y)] = Tile.WALL + +p1 = sandbox.simulate() +print(p1) + +floory = sandbox.maxy + 2 +height = floory - sandbox.source.y +for x in range(500 - height, 500 + height + 1): + sandbox[Point2D(x, floory)] = Tile.WALL + +print(p1 + sandbox.simulate()) |