aoc-2020/d24/main2.py

137 lines
3.3 KiB
Python
Executable File

#! /usr/bin/env python3
from typing import Iterable
# from typing import Tuple
from typing import Set
from typing import Dict
# from typing import Optional
import itertools
from collections import Counter
from collections import namedtuple
Point = namedtuple("Point", "x y")
D2P = {
"se": Point(1, -1),
"sw": Point(-1, -1),
"ne": Point(1, 1),
"nw": Point(-1, 1),
"w": Point(-2, 0),
"e": Point(2, 0),
}
def directions_to_point(s: str) -> Point:
point = Point(0, 0)
direction = ""
for c in s:
direction += c
if direction in D2P:
point = add_points(point, D2P[direction])
direction = ""
if direction != "":
raise ValueError("Something left over unexpectedly")
return point
def add_points(p1, p2) -> Point:
return Point(
p1.x + p2.x,
p1.y + p2.y,
)
def neighbors(point: Point) -> Iterable[Point]:
for diff in D2P.values():
yield add_points(point, diff)
def neighbor_counts(points: Set[Point]) -> Dict[Point, int]:
# return {
# p: sum(map(lambda x: 1 if x in points else 0, neighbors(p)))
# for p in points
# }
return Counter(itertools.chain.from_iterable(map(neighbors, points)))
def next_generation(points: Set[Point]):
counts = neighbor_counts(points)
return (
{p for p in points if counts[p] in (1, 2)} |
{p for p in counts if p not in points and counts[p] == 2}
)
def point_deltas() -> Iterable[Point]:
return D2P.values()
def life(points: Set[Point], n: int) -> Set[Point]:
for r in range(n):
points = next_generation(points)
return points
def sample():
black: Set[Point] = set()
for line in (
"sesenwnenenewseeswwswswwnenewsewsw",
"neeenesenwnwwswnenewnwwsewnenwseswesw",
"seswneswswsenwwnwse",
"nwnwneseeswswnenewneswwnewseswneseene",
"swweswneswnenwsewnwneneseenw",
"eesenwseswswnenwswnwnwsewwnwsene",
"sewnenenenesenwsewnenwwwse",
"wenwwweseeeweswwwnwwe",
"wsweesenenewnwwnwsenewsenwwsesesenwne",
"neeswseenwwswnwswswnw",
"nenwswwsewswnenenewsenwsenwnesesenew",
"enewnwewneswsewnwswenweswnenwsenwsw",
"sweneswneswneneenwnewenewwneswswnese",
"swwesenesewenwneswnwwneseswwne",
"enesenwswwswneneswsenwnewswseenwsese",
"wnwnesenesenenwwnenwsewesewsesesew",
"nenewswnwewswnenesenwnesewesw",
"eneswnwswnwsenenwnwnwwseeswneewsenese",
"neswnwewnwnwseenwseesewsenwsweewe",
"wseweeenwnesenwwwswnew",
):
p = directions_to_point(line)
if p in black:
black.remove(p)
else:
black.add(p)
print(f"Num black is {len(black)}")
rounds = 100
black = life(black, rounds)
print(f"Num black after {rounds} is {len(black)}")
def part2():
black: Set[Point] = set()
with open("input.txt") as f:
for line in f:
line = line.strip()
p = directions_to_point(line)
if p in black:
black.remove(p)
else:
black.add(p)
print(f"Num black is {len(black)}")
rounds = 100
black = life(black, rounds)
print(f"Num black after {rounds} is {len(black)}")
if __name__ == "__main__":
# sample()
part2()