day05 finished
This commit is contained in:
parent
543d0823c3
commit
380b825929
6 changed files with 706 additions and 0 deletions
105
advent/days/day05/solution.py
Normal file
105
advent/days/day05/solution.py
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
|
||||
from typing import Iterator
|
||||
|
||||
from advent.parser.parser import P
|
||||
|
||||
day_num = 5
|
||||
|
||||
|
||||
def part1(lines: Iterator[str]) -> str:
|
||||
state = State.parse(lines)
|
||||
crates = state.all_moves9000()
|
||||
return State.top(crates)
|
||||
|
||||
|
||||
def part2(lines: Iterator[str]) -> str:
|
||||
state = State.parse(lines)
|
||||
crates = state.all_moves9001()
|
||||
return State.top(crates)
|
||||
|
||||
|
||||
crate_parser: P[str | None] = P.either(P.any_char().in_brackets(), P.string(" ").replace(None))
|
||||
crate_row_parser = crate_parser.sep_by(P.is_char(' '))
|
||||
amount_parser = P.snd(P.string("move "), P.unsigned())
|
||||
from_parser = P.snd(P.string(" from "), P.unsigned())
|
||||
to_parser = P.snd(P.string(" to "), P.unsigned())
|
||||
move_parser = P.seq(amount_parser, from_parser, to_parser)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class State:
|
||||
crates: list[str]
|
||||
moves: list[tuple[int, int, int]]
|
||||
|
||||
@staticmethod
|
||||
def parse_crate_line(line: str) -> list[None | str] | None:
|
||||
return crate_row_parser.parse(line).get_or(None)
|
||||
|
||||
@staticmethod
|
||||
def parse_drawing(lines: Iterator[str]) -> list[str]:
|
||||
result: list[str] = []
|
||||
for line in lines:
|
||||
crates = State.parse_crate_line(line)
|
||||
if crates is None:
|
||||
return result
|
||||
|
||||
if len(result) < len(crates):
|
||||
result += [""] * (len(crates) - len(result))
|
||||
for stack, crate in enumerate(crates):
|
||||
if crate is not None:
|
||||
result[stack] = crate + result[stack]
|
||||
|
||||
raise Exception("Can never happen")
|
||||
|
||||
@staticmethod
|
||||
def parse_move(line: str) -> tuple[int, int, int]:
|
||||
amount, frm, to = move_parser.parse(line).get()
|
||||
return amount, frm - 1, to - 1
|
||||
|
||||
@staticmethod
|
||||
def parse(lines: Iterator[str]) -> State:
|
||||
drawing = State.parse_drawing(lines)
|
||||
next(lines)
|
||||
moves = [State.parse_move(line) for line in lines]
|
||||
return State(drawing, moves)
|
||||
|
||||
@staticmethod
|
||||
def do_move9000(crates: list[str], move: tuple[int, int, int]) -> list[str]:
|
||||
"""
|
||||
Moves the given crates by the provided move. Will fail if there are not enough crates
|
||||
in the from stack
|
||||
"""
|
||||
for _ in range(move[0]):
|
||||
crates[move[2]] += crates[move[1]][-1]
|
||||
crates[move[1]] = crates[move[1]][:-1]
|
||||
|
||||
return crates
|
||||
|
||||
def all_moves9000(self) -> list[str]:
|
||||
crates = self.crates
|
||||
for move in self.moves:
|
||||
crates = State.do_move9000(crates, move)
|
||||
return crates
|
||||
|
||||
@staticmethod
|
||||
def do_move9001(crates: list[str], move: tuple[int, int, int]) -> list[str]:
|
||||
"""
|
||||
Moves the given crates by the provided move. Will fail if there are not enough crates
|
||||
in the from stack
|
||||
"""
|
||||
crates[move[2]] += crates[move[1]][-move[0]:]
|
||||
crates[move[1]] = crates[move[1]][:-move[0]]
|
||||
return crates
|
||||
|
||||
def all_moves9001(self) -> list[str]:
|
||||
crates = self.crates
|
||||
for move in self.moves:
|
||||
crates = State.do_move9001(crates, move)
|
||||
return crates
|
||||
|
||||
@staticmethod
|
||||
def top(crates: list[str]) -> str:
|
||||
""" Lists the last item in the given stacks. Fails if any stack is empty """
|
||||
return ''.join(stack[-1] for stack in crates)
|
||||
Loading…
Add table
Add a link
Reference in a new issue