aoc2024/day09.py
2024-12-09 10:08:53 +01:00

140 lines
3.9 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"),
(6346871685398, "input9"),
],
[
(2858, "input9_test"),
(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:
head, tail = self.parse_input()
index = head
while index is not None:
if index.file_id != -1:
index = index.right
continue
if tail.file_id == -1:
tail = tail.left
tail.right = None
if tail.file_length > index.file_length:
index.file_id = tail.file_id
tail.file_length -= index.file_length
elif tail.file_length < index.file_length:
space_left = index.file_length - tail.file_length
index.file_id = tail.file_id
index.file_length = tail.file_length
tail = tail.left
tail.right = None
new_space = Block(-1, space_left, index)
new_space.right = index.right
index.right = new_space
else:
index.file_id = tail.file_id
tail = tail.left
tail.right = None
index = index.right
return get_checksum(head)
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)