2018 day 3
This commit is contained in:
parent
50eee15a8a
commit
057d99fcea
59
2018/day3.py
Normal file
59
2018/day3.py
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
from grid import Grid
|
||||||
|
|
||||||
|
|
||||||
|
EX = [
|
||||||
|
"#1 @ 1,3: 4x4",
|
||||||
|
"#2 @ 3,1: 4x4",
|
||||||
|
"#3 @ 5,5: 2x2",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with open("day3.txt", "rt") as f:
|
||||||
|
lines = [line.rstrip() for line in f.readlines()]
|
||||||
|
|
||||||
|
# Part 1
|
||||||
|
g = Grid()
|
||||||
|
for line in lines:
|
||||||
|
ident, left, top, width, height = parse_line(line)
|
||||||
|
for i in range(int(width)):
|
||||||
|
for j in range(int(height)):
|
||||||
|
x = int(left) + i
|
||||||
|
y = int(top) + j
|
||||||
|
g.setv(x, y, g.getv(x, y) + 1)
|
||||||
|
n = get_overlaps(g)
|
||||||
|
print(n)
|
||||||
|
|
||||||
|
# Part 2
|
||||||
|
g = Grid()
|
||||||
|
over = []
|
||||||
|
for line in lines:
|
||||||
|
ident, left, top, width, height = parse_line(line)
|
||||||
|
for i in range(int(width)):
|
||||||
|
for j in range(int(height)):
|
||||||
|
x = int(left) + i
|
||||||
|
y = int(top) + j
|
||||||
|
current_v = g.getv(x, y)
|
||||||
|
if current_v == None:
|
||||||
|
over.append(int(ident))
|
||||||
|
continue
|
||||||
|
elif current_v == 0:
|
||||||
|
g.setv(x, y, int(ident))
|
||||||
|
else:
|
||||||
|
over += [int(ident), current_v]
|
||||||
|
g.setv(x, y, None)
|
||||||
|
print(set(v for _, _, v in g.values_gen()).difference(set(over)))
|
||||||
|
|
||||||
|
LINE_RE = re.compile(r"#(\d+) @ (\d+),(\d+): (\d+)x(\d+)")
|
||||||
|
|
||||||
|
def parse_line(line):
|
||||||
|
match = LINE_RE.match(line)
|
||||||
|
return match.groups()
|
||||||
|
|
||||||
|
def get_overlaps(grid):
|
||||||
|
return sum([v > 1 for _, _, v in grid.values_gen()])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
55
2018/grid.py
Normal file
55
2018/grid.py
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
"""Generic 2D grid with a few helpers."""
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
|
||||||
|
class Grid:
|
||||||
|
|
||||||
|
def __init__(self, value_factory=int, lines=None):
|
||||||
|
self.g = defaultdict(lambda: defaultdict(value_factory))
|
||||||
|
if lines:
|
||||||
|
self.load(lines)
|
||||||
|
|
||||||
|
def getv(self, x, y):
|
||||||
|
return self.g[y][x]
|
||||||
|
|
||||||
|
def setv(self, x, y, value):
|
||||||
|
self.g[y][x] = value
|
||||||
|
|
||||||
|
def load(self, lines, f=lambda v: v):
|
||||||
|
for y, line in enumerate(lines):
|
||||||
|
for x, c in enumerate(line.rstrip()):
|
||||||
|
self.g[y][x] = f(c)
|
||||||
|
|
||||||
|
def values_gen(self):
|
||||||
|
for y, row in self.g.items():
|
||||||
|
for x, v in row.items():
|
||||||
|
yield (x, y, v)
|
||||||
|
|
||||||
|
def near_objects(self, p):
|
||||||
|
"""Return a dict of neighbor positions to values (U, L, D, R)."""
|
||||||
|
return {q: self.g[q[1]][q[0]] for q in Grid.near(p)}
|
||||||
|
|
||||||
|
def dumb_print(self, f=lambda v: v):
|
||||||
|
for row in self.g.values():
|
||||||
|
for x in row.values():
|
||||||
|
print(f(x), end="")
|
||||||
|
print()
|
||||||
|
|
||||||
|
def print_near(self, p, view_size=2):
|
||||||
|
"""Print near values in an area of view_size. Works iff keys support addition."""
|
||||||
|
for dy in range(-view_size, view_size + 1):
|
||||||
|
print("".join([
|
||||||
|
self.g[p[1] + dy][p[0] + dx]
|
||||||
|
for dx in range(-view_size, view_size + 1)
|
||||||
|
]))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def near(p):
|
||||||
|
"""Return a tuple of neighbor positions (up, left, down, right)."""
|
||||||
|
return (
|
||||||
|
(p[0] , p[1] - 1),
|
||||||
|
(p[0] + 1, p[1] ),
|
||||||
|
(p[0] , p[1] + 1),
|
||||||
|
(p[0] - 1, p[1] ),
|
||||||
|
)
|
Loading…
Reference in a new issue