Example #1
0
#!/usr/bin/python3.8

from aoc import Env
from collections import defaultdict

e = Env(24)
e.T(
    """sesenwnenenewseeswwswswwnenewsewsw
neeenesenwnwwswnenewnwwsewnenwseswesw
seswneswswsenwwnwse
nwnwneseeswswnenewneswwnewseswneseene
swweswneswnenwsewnwneneseenw
eesenwseswswnenwswnwnwsewwnwsene
sewnenenenesenwsewnenwwwse
wenwwweseeeweswwwnwwe
wsweesenenewnwwnwsenewsenwwsesesenwne
neeswseenwwswnwswswnw
nenwswwsewswnenenewsenwsenwnesesenew
enewnwewneswsewnwswenweswnenwsenwsw
sweneswneswneneenwnewenewwneswswnese
swwesenesewenwneswnwwneseswwne
enesenwswwswneneswsenwnewswseenwsese
wnwnesenesenenwwnenwsewesewsesesew
nenewswnwewswnenesenwnesewesw
eneswnwswnwsenenwnwnwwseeswneewsenese
neswnwewnwnwseenwseesewsenwsweewe
wseweeenwnesenwwwswnew""", 10, 2208)

move = {
    'se': (1, 1),
    'sw': (1, -1),
Example #2
0
#!/usr/bin/python3.8

from aoc import Env
from collections import deque

import re

e = Env(14)
e.T(
    """mask = XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X
mem[8] = 11
mem[7] = 101
mem[8] = 0""", 165, None)
e.T(
    """mask = 000000000000000000000000000000X1001X
mem[42] = 100
mask = 00000000000000000000000000000000X0XX
mem[26] = 1""", None, 208)


def parse_mask(maskstr):
    o = {}
    for i, c in enumerate(maskstr[::-1]):
        if c in '01':
            o[i] = int(c)
    return o


def apply_mask(mask, val):
    for p, v in mask.items():
        if v == 1:
Example #3
0
#!/usr/bin/python3.8

from aoc import Env, Modular

e = Env(13)
e.T("""939
7,13,x,x,59,x,31,19""", 295, 1068781)
e.T("""0
17,x,13,19""", None, 3417)
e.T("""0
67,7,59,61""", None, 754018)
e.T("""0
67,x,7,59,61""", None, 779210)
e.T("""0
67,7,x,59,61""", None, 1261476)
e.T("""0
1789,37,47,1889""", None, 1202161486)
e.T("""0
3,5""", None, 9)


def parse_input(inp):
    ln = inp.get_valid_lines()
    timestamp = int(ln[0])
    buses = [(int(bn), i) for i, bn in enumerate(ln[1].split(','))
             if bn != 'x']
    return timestamp, buses


def part1(input):
    timestamp, buses = parse_input(input)
Example #4
0
#!/usr/bin/env python3

from aoc import Env
import re

e = Env(4)
e.T(
    """[1518-11-01 00:00] Guard #10 begins shift
[1518-11-01 00:05] falls asleep
[1518-11-01 00:25] wakes up
[1518-11-01 00:30] falls asleep
[1518-11-01 00:55] wakes up
[1518-11-01 23:58] Guard #99 begins shift
[1518-11-02 00:40] falls asleep
[1518-11-02 00:50] wakes up
[1518-11-03 00:05] Guard #10 begins shift
[1518-11-03 00:24] falls asleep
[1518-11-03 00:29] wakes up
[1518-11-04 00:02] Guard #99 begins shift
[1518-11-04 00:36] falls asleep
[1518-11-04 00:46] wakes up
[1518-11-05 00:03] Guard #99 begins shift
[1518-11-05 00:45] falls asleep
[1518-11-05 00:55] wakes up""", 240, 4455)


def parse_event(event):
    m = re.match(r'^\[1518-(\d\d)-(\d\d) (\d\d):(\d\d)\] (.*)', event)
    assert m is not None, f"Cannot parse line {event}"
    _d, _m, _h, _mm, what = m.groups()
    # day = int(_d)
Example #5
0
#!/usr/bin/python3.8

# Note: https://oeis.org/A181391

from aoc import Env
import numpy

e = Env(15)
e.T("0,3,6", 436, 175594)


def van_eck(start, K):
    memory = numpy.zeros(K, dtype=int)

    for i, x in enumerate(start):
        memory[x] = i + 1

    last_said = 0
    # Assuming all numbers in start are unique
    next = 0
    turn = len(start) + 1

    while turn <= K:
        # elf says next
        last_said = next
        # when was that said last time
        next = memory[last_said]
        if next != 0:
            next = turn - next
        memory[last_said] = turn
        turn += 1
Example #6
0
#!/usr/bin/python3.8

from aoc import Env
from collections import defaultdict
import re

e = Env(16)
e.T("""departure class: 1-3 or 5-7
departure row: 6-11 or 33-44
seat: 13-40 or 45-50

your ticket:
7,1,14

nearby tickets:
7,3,47
40,4,50
55,2,20
38,6,12
""", 71, 1*7)
e.T("""departure class: 0-1 or 4-19
departure row: 0-5 or 8-19
seat: 0-13 or 16-19

your ticket:
11,12,13

nearby tickets:
3,9,18
15,1,5
5,14,9
Example #7
0
#!/usr/bin/python3.8

from aoc import Env
from collections import deque
import re

e = Env(19)
e.T(
    """0: 4 1 5
1: 2 3 | 3 2
2: 4 4 | 5 5
3: 4 5 | 5 4
4: "a"
5: "b"

ababbb
bababa
abbbab
aaabbb
aaaabbb
""", 2, None)
e.T(
    """42: 9 14 | 10 1
9: 14 27 | 1 26
10: 23 14 | 28 1
1: "a"
11: 42 31
5: 1 14 | 15 1
19: 14 1 | 14 14
12: 24 14 | 19 1
16: 15 1 | 14 14
Example #8
0
#!/usr/bin/python3.8

from aoc import Env
from collections import Counter

e = Env(2)
e.T("""abcdef
bababc
abbcde
abcccd
aabcdd
abcdee
ababab""", 12, None)
e.T("""abcde
fghij
klmno
pqrst
fguij
axcye
wvxyz""", None, 'fgij')


def part1(input):
    ids = input.get_valid_lines()
    twos = 0
    threes = 0
    for id in ids:
        counts = Counter(id)
        if 2 in counts.values():
            twos += 1
        if 3 in counts.values():
Example #9
0
#!/usr/bin/python3.8

from aoc import Env
from collections import deque

e = Env(22)
e.T("""Player 1:
9
2
6
3
1

Player 2:
5
8
4
7
10
""", 306, 291)


def play(decks):
    rounds = 0
    while True:
        if not decks[0] or not decks[1]:
            return rounds
        draw = [decks[0].popleft(), decks[1].popleft()]
        if draw[0] > draw[1]:
            decks[0].append(draw[0])
            decks[0].append(draw[1])
Example #10
0
#!/usr/bin/python3.8

from aoc import Env, Grid
from collections import defaultdict

e = Env(17)
e.T(""".#.
..#
###""", 112, 848)


def make_grid(input):
    ingrid = Grid(input.get_valid_lines())
    grid = defaultdict(bool)
    for row in range(ingrid.h):
        for col in range(ingrid.w):
            if ingrid.grid[row][col] == '#':
                grid[(col, row, 0)] = True
    return grid, ((0, ingrid.w), (0, ingrid.h), (0, 1))


def count_neighbors(x, y, z, grid):
    count = 0
    for a in [-1, 0, 1]:
        for b in [-1, 0, 1]:
            for c in [-1, 0, 1]:
                if a == 0 and b == 0 and c == 0:
                    continue
                if (x + a, y + b, z + c) in grid:
                    count += 1
    return count
Example #11
0
#!/usr/bin/python3.8

from aoc import Env
from collections import defaultdict
from functools import reduce
import math
import re

e = Env(20)
e.T("""Tile 2311:
..##.#..#.
##..#.....
#...##..#.
####.#...#
##.##.###.
##...#.###
.#.#.#..##
..#....#..
###...#.#.
..###..###

Tile 1951:
#.##...##.
#.####...#
.....#..##
#...######
.##.#....#
.###.#####
###.##.##.
.###....#.
..#.#..#.#
Example #12
0
#!/usr/bin/python3.8

from aoc import Env

e = Env(25)
e.T("""5764801
17807724""", 14897079, None)


def get_loop_number(key):
    v = 1
    for i in range(20201227):
        v = (v * 7) % 20201227
        if v == key:
            return i + 1
    assert False


def loop(start, loops):
    v = 1
    for _ in range(loops):
        v = (v * start) % 20201227
    return v


def part1(input):
    ln = input.get_valid_lines()
    A = int(ln[0])
    B = int(ln[1])
    # A = 7 ** n mod 20201227
    # B = 7 ** m mod 20201227
Example #13
0
#!/usr/bin/python3.8

from aoc import Env
from collections import defaultdict
from functools import reduce
import math
import re
import random

e = Env(20)

monster = [
    "..................#.",
    "#....##....##....###",
    ".#..#..#..#..#..#...",
]

frame_counter = 0

frame = []
for r in range(12 * 10):
    frame += [[' '] * 12 * 10]

palette = {
    ' ': '000000',  # blank space
    '.': '99d9ea',  # water - low
    '#': '00a2e8',  # water - high
    '-': 'ff7da8',  # picture border - low
    '@': 'ff3778',  # picture border - high
    ';': '9e9e9e',  # tile edge - low
    '*': '434343',  # tile edge - high
Example #14
0
#!/usr/bin/python3.8

from aoc import Env
from collections import namedtuple, defaultdict
import re

e = Env(3)
e.T("""#1 @ 1,3: 4x4
#2 @ 3,1: 4x4
#3 @ 5,5: 2x2""", 4, 3)


Claim = namedtuple('Claim', ['id', 'left', 'top', 'width', 'height'])


def parse_input(input):
    claims = []
    for ln in input.get_valid_lines():
        m = re.search(r'^#(\d+) @ (\d+),(\d+): (\d+)x(\d+)', ln)
        assert m is not None
        id, left, top, wid, hei = [int(m.group(i)) for i in range(1, 6)]
        claims += [Claim(id=id, left=left, top=top, width=wid, height=hei)]
    return claims


def draw_claims(claims):
    fabric = defaultdict(int)
    for claim in claims:
        for x in range(claim.left, claim.left + claim.width):
            for y in range(claim.top, claim.top + claim.height):
                fabric[(x, y)] += 1
Example #15
0
#!/usr/bin/python3.8

from aoc import Env
import re

e = Env(18)
e.T("1 + 2 * 3 + 4 * 5 + 6", 71, 231)
e.T("1 + (2 * 3) + (4 * (5 + 6))", 51, 51)
e.T("2 * 3 + (4 * 5)", None, 46)
e.T("5 + (8 * 3 + 9 + 3 * 4 * 3)", None, 1445)
e.T("5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))", None, 669060)
e.T("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2", None, 23340)


def evaluate_expr(ln):
    tokens = re.findall(r'(\d+|\+|\*|\(|\))', ln)
    stack = []
    for tok in tokens:
        if tok in '(+*':
            stack.append(tok)
            continue
        elif tok == ')':
            # assuming that parentheses are never empty
            val = stack.pop()
            _ = stack.pop()
        else:
            val = int(tok)

        if not stack or stack[-1] == '(':
            stack.append(val)
        else:
Example #16
0
#!/usr/bin/python3.8

from aoc import Env

e = Env(1)
e.T("""+1
+1
+1""", 3, None)
e.T("""+1
+1
-2""", 0, None)
e.T("""-1
-2
-3""", -6, None)
e.T("""+1
-2
+3
+1""", None, 2)


def part1(input):
    ints = [int(x) for x in input.get_valid_lines()]
    return sum(ints)


e.run_tests(1, part1)
e.run_main(1, part1)


def part2(input):
    ints = [int(x) for x in input.get_valid_lines()]
Example #17
0
#!/usr/bin/python3.8

from aoc import Env

e = Env(23)
e.T("389125467", 67384529, 149245887792)


class Node:
    def __init__(self, val):
        self.val = val
        self.prev = None
        self.next = None


def make_nodes(start, add_to_million):
    for v in start:
        yield Node(v)
    if add_to_million:
        for i in range(max(start) + 1, 1_000_001):
            yield Node(i)


def make_move(current, nodemap):
    maxnum = len(nodemap)
    current_node = nodemap[current]
    taken = [
        current_node.next, current_node.next.next, current_node.next.next.next
    ]
    taken_vals = [x.val for x in taken]
    current_node.next = current_node.next.next.next.next