generated from public/aoc_template
122 lines
3.4 KiB
Python
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)
|