2024.09
This commit is contained in:
parent
0e233c02cc
commit
4800b07880
6 changed files with 152 additions and 1 deletions
5
challenges/2024/09-diskFragmenter/README.md
Normal file
5
challenges/2024/09-diskFragmenter/README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# [Day 9: Disk Fragmenter](https://adventofcode.com/2024/day/9)
|
||||||
|
|
||||||
|
Part 2 is:
|
||||||
|
* less than 6277851188082
|
||||||
|
6272188244509
|
129
challenges/2024/09-diskFragmenter/main.py
Normal file
129
challenges/2024/09-diskFragmenter/main.py
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
import sys
|
||||||
|
from collections import namedtuple, defaultdict
|
||||||
|
|
||||||
|
|
||||||
|
Segment = namedtuple("Segment", ["id", "len"])
|
||||||
|
|
||||||
|
|
||||||
|
def parse(instr: str) -> list[Segment]:
|
||||||
|
res = []
|
||||||
|
next_id = 0
|
||||||
|
|
||||||
|
for i, v in enumerate(instr):
|
||||||
|
v = int(v)
|
||||||
|
if i % 2 == 0:
|
||||||
|
# this is a file
|
||||||
|
res.append(Segment(next_id, v))
|
||||||
|
next_id += 1
|
||||||
|
else:
|
||||||
|
# this is a gap
|
||||||
|
res.append(Segment(None, v))
|
||||||
|
|
||||||
|
if res[-1].id is None:
|
||||||
|
# random gap at the end? no thanks
|
||||||
|
res = res[:-1]
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def calc_checksum(files: list[Segment]) -> int:
|
||||||
|
acc = 0
|
||||||
|
pos = 0
|
||||||
|
for file in files:
|
||||||
|
if file.id is not None:
|
||||||
|
# sum of sequence of n consecutive integers is (n / 2)(first + last)
|
||||||
|
acc += int((file.len / 2) * ((pos * 2) + file.len - 1) * file.id)
|
||||||
|
pos += file.len
|
||||||
|
return acc
|
||||||
|
|
||||||
|
|
||||||
|
def one(instr: str):
|
||||||
|
files = parse(instr)
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while i < len(files) - 1:
|
||||||
|
f = files[i]
|
||||||
|
last_file = files[-1]
|
||||||
|
|
||||||
|
if last_file.id is None:
|
||||||
|
files = files[:-1]
|
||||||
|
continue
|
||||||
|
|
||||||
|
if f.id is None:
|
||||||
|
# _debug(i, files[i])
|
||||||
|
last_file = files[-1]
|
||||||
|
|
||||||
|
assert last_file.id is not None
|
||||||
|
if last_file.len > f.len:
|
||||||
|
files[-1] = Segment(last_file.id, last_file.len - f.len)
|
||||||
|
files[i] = Segment(last_file.id, f.len)
|
||||||
|
elif last_file.len == f.len:
|
||||||
|
# we're gonna move all of this so just delete it
|
||||||
|
files = files[:-1]
|
||||||
|
files[i] = last_file
|
||||||
|
else:
|
||||||
|
# TODO: when we haven't got enough in this last file so we need to split f into two
|
||||||
|
files = files[:-1]
|
||||||
|
files[i] = last_file
|
||||||
|
assert f.len - last_file.len != 0
|
||||||
|
files.insert(i+1, Segment(None, f.len - last_file.len))
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return calc_checksum(files)
|
||||||
|
|
||||||
|
|
||||||
|
def two(instr: str):
|
||||||
|
files = parse(instr)
|
||||||
|
|
||||||
|
gaps = defaultdict(list)
|
||||||
|
|
||||||
|
for i, file in enumerate(files):
|
||||||
|
if file.id is None and file.len != 0:
|
||||||
|
gaps[file.len].append(i)
|
||||||
|
|
||||||
|
moved = set()
|
||||||
|
|
||||||
|
i = len(files) - 1
|
||||||
|
while i > 0:
|
||||||
|
f = files[i]
|
||||||
|
|
||||||
|
if f.id is not None and f.id not in moved:
|
||||||
|
gap_loc = None
|
||||||
|
for j, v in enumerate(files):
|
||||||
|
if j >= i:
|
||||||
|
break
|
||||||
|
|
||||||
|
if v.id is None and v.len >= f.len:
|
||||||
|
gap_loc = j
|
||||||
|
break
|
||||||
|
|
||||||
|
if gap_loc is not None:
|
||||||
|
v = files[gap_loc]
|
||||||
|
if v.len == f.len:
|
||||||
|
files[i], files[gap_loc] = files[gap_loc], files[i]
|
||||||
|
else:
|
||||||
|
files[i] = Segment(None, f.len)
|
||||||
|
files[gap_loc] = f
|
||||||
|
files.insert(gap_loc + 1, Segment(None, v.len - f.len))
|
||||||
|
moved.add(f.id)
|
||||||
|
|
||||||
|
i -= 1
|
||||||
|
|
||||||
|
return calc_checksum(files)
|
||||||
|
|
||||||
|
|
||||||
|
def _debug(*args, **kwargs):
|
||||||
|
kwargs["file"] = sys.stderr
|
||||||
|
print(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) < 2 or sys.argv[1] not in ["1", "2"]:
|
||||||
|
print("Missing day argument", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
inp = sys.stdin.read().strip()
|
||||||
|
if sys.argv[1] == "1":
|
||||||
|
print(one(inp))
|
||||||
|
else:
|
||||||
|
print(two(inp))
|
14
challenges/2024/09-diskFragmenter/tests.json
Normal file
14
challenges/2024/09-diskFragmenter/tests.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"1": [
|
||||||
|
{
|
||||||
|
"is": "1928",
|
||||||
|
"input": "2333133121414131402\n"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
{
|
||||||
|
"is": "2858",
|
||||||
|
"input": "2333133121414131402\n"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -21,4 +21,5 @@ A day denoted with an asterisk means it has a visualisation.
|
||||||
| 05 - Print Queue | ★ ★ | Python | Before you dismiss and idea as being "too simple", make sure you check that it doesn't work. |
|
| 05 - Print Queue | ★ ★ | Python | Before you dismiss and idea as being "too simple", make sure you check that it doesn't work. |
|
||||||
| 06 - Guard Gallivant | ★ ★ | Python | oh dear runtime (also I knew what I wanted to do for so long it just took me 3 hours to implement it properly) |
|
| 06 - Guard Gallivant | ★ ★ | Python | oh dear runtime (also I knew what I wanted to do for so long it just took me 3 hours to implement it properly) |
|
||||||
| 07 - Bridge Repair | ★ ★ | Python | Maths? Backwards?? |
|
| 07 - Bridge Repair | ★ ★ | Python | Maths? Backwards?? |
|
||||||
| 08* - Resonant Collinearity | ★ ★ | Python | `Fraction` saving us all from the curse of a computer's inability to do floating point arithmetic |
|
| 08* - Resonant Collinearity | ★ ★ | Python | `Fraction` saving us all from the curse of a computer's inability to do floating point arithmetic |
|
||||||
|
| 09 - Disk Fragmenter | ★ ★ | Python | Many cursed strategies were attempted before I landed on the final implementation |
|
Binary file not shown.
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 48 KiB |
|
@ -14,3 +14,5 @@
|
||||||
{"day": 7, "part": 2, "runner": "py", "min": 0.02680826187133789, "max": 0.04485297203063965, "avg": 0.029925800323486327, "n": 500}
|
{"day": 7, "part": 2, "runner": "py", "min": 0.02680826187133789, "max": 0.04485297203063965, "avg": 0.029925800323486327, "n": 500}
|
||||||
{"day": 8, "part": 1, "runner": "py", "min": 0.025803089141845703, "max": 0.036757469177246094, "avg": 0.02743640899658203, "n": 200}
|
{"day": 8, "part": 1, "runner": "py", "min": 0.025803089141845703, "max": 0.036757469177246094, "avg": 0.02743640899658203, "n": 200}
|
||||||
{"day": 8, "part": 2, "runner": "py", "min": 0.027710437774658203, "max": 0.035851240158081055, "avg": 0.029560294151306152, "n": 200}
|
{"day": 8, "part": 2, "runner": "py", "min": 0.027710437774658203, "max": 0.035851240158081055, "avg": 0.029560294151306152, "n": 200}
|
||||||
|
{"day": 9, "part": 1, "runner": "py", "min": 0.5576984882354736, "max": 0.5812969207763672, "avg": 0.5654887676239013, "n": 5}
|
||||||
|
{"day": 9, "part": 2, "runner": "py", "min": 3.876859188079834, "max": 4.176096677780151, "avg": 4.0687650680542, "n": 5}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue