aoc2024/day09.py

122 lines
3.4 KiB
Python

from __future__ import annotations
from tools.aoc import AOCDay
from typing import Any
class Block:
file_id: int
file_length: int
left: Block | None
right: Block | None
def __init__(self, file_id: int, file_length: int, left: Block | None = None):
self.file_id = file_id
self.file_length = file_length
self.left = left
self.right = None
def get_checksum(head: Block) -> int:
checksum = 0
index = head
count = 0
while index is not None:
if index.file_id > 0:
for _ in range(index.file_length):
checksum += index.file_id * count
count += 1
else:
count += index.file_length
index = index.right
return checksum
class Day(AOCDay):
inputs = [
[
(1928, "input9_test"),
(6154342787400, "input9_dennis"),
(6346871685398, "input9"),
],
[
(2858, "input9_test"),
(6183632723350, "input9_dennis"),
(6373055193464, "input9"),
],
]
def parse_input(self) -> tuple[Block, Block]:
head = Block(-1, 0)
tail = head
mode = False # False == file, True == free space
file_id = 0
for num in map(int, self.getInput()):
tail.right = Block(-1 if mode else file_id, num, tail)
tail = tail.right
if mode:
file_id += 1
mode = not mode
head = head.right
head.left = None
return head, tail
def part1(self) -> Any:
filesystem = [i // 2 if i % 2 == 0 else -1 for i, c in enumerate(map(int, self.getInput())) for _ in range(c)]
index = 0
while index < len(filesystem):
if filesystem[index] != -1:
index += 1
continue
filesystem[index] = filesystem.pop()
while filesystem[-1] == -1:
filesystem.pop()
return sum(i * c for i, c in enumerate(filesystem))
def part2(self) -> Any:
head, tail = self.parse_input()
index = tail
while index is not None:
while index.file_id == -1:
index = index.left
search = head
while search != index:
if search.file_id == -1 and search.file_length >= index.file_length:
new_free_space = Block(-1, index.file_length, index.left)
new_free_space.right = index.right
index.left.right = new_free_space
if index.right is not None:
index.right.left = new_free_space
search.file_id = index.file_id
if search.file_length > index.file_length:
space_left = search.file_length - index.file_length
search.file_length = index.file_length
new_space = Block(-1, space_left, search)
new_space.right = search.right
search.right.left = new_space
search.right = new_space
break
search = search.right
index = index.left
while tail.file_id == -1:
tail = tail.left
tail.right = None
return get_checksum(head)
if __name__ == "__main__":
day = Day(2024, 9)
day.run(verbose=True)