-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday_09.py
127 lines (98 loc) · 3.16 KB
/
day_09.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import aoc_helper
raw = aoc_helper.fetch(9, 2024)
def parse_raw(raw: str):
return raw
data = parse_raw(raw)
# providing this default is somewhat of a hack - there isn't any other way to
# force type inference to happen, AFAIK - but this won't work with standard
# collections (list, set, dict, tuple)
def part_one(data=data):
disk = []
file_block = 1
file_id = 0
for i in data:
if file_block:
disk.extend([file_id]*int(i))
file_id += 1
else:
disk.extend("."*int(i))
file_block = 1 - file_block
l = 0
r = len(disk)-1
while l < r:
if disk[l] != '.':
l += 1
continue
if disk[r] == '.':
r -= 1
continue
disk[l], disk[r] = disk[r], disk[l]
l += 1
r -= 1
ans = 0
for i in range(r+1):
ans += disk[i] * i
return ans
aoc_helper.lazy_test(day=9, year=2024, parse=parse_raw, solution=part_one)
# providing this default is somewhat of a hack - there isn't any other way to
# force type inference to happen, AFAIK - but this won't work with standard
# collections (list, set, dict, tuple)
from tqdm import tqdm
def part_two(data=data):
blocks = []
totlen = 0
isfile = 1
file_idx = 0
for i in data:
ln = int(i)
if isfile:
blocks.append((totlen, totlen+ln-1, file_idx))
file_idx += 1
else:
blocks.append((totlen, totlen+ln-1, -1))
isfile = 1-isfile
totlen += ln
for f in tqdm(range(file_idx-1, -1, -1)):
file_idx = None
for i,j in enumerate(blocks):
if j[-1] == f: file_idx = i; break
assert file_idx is not None
fs, fe,ff = blocks.pop(file_idx)
f_len = fe - fs + 1
void_idx = None
for i,b in enumerate(blocks):
if b[0] > fs: break
if b[-1] == -1 and b[1]-b[0]+1 >= f_len:
void_idx = i
break
if void_idx is None:
blocks.insert(file_idx, (fs,fe,ff))
continue
vs, ve, _ = blocks.pop(void_idx)
blocks.append((vs,vs + f_len - 1, ff))
if vs+f_len-1 != ve:
blocks.append((vs+f_len, ve, -1))
blocks.append((fs, fe, -1))
## merge any consecutive voids into a single void
blocks.sort()
merged_blocks = []
for b in blocks:
if not merged_blocks or (b[-1] != -1) or (merged_blocks[-1][-1] != -1) or (merged_blocks[-1][1] < b[0]): merged_blocks.append(b); continue
a = merged_blocks.pop()
merged_blocks.append((
a[0],max(a[1],b[1]),-1
))
blocks = merged_blocks[::]
disk = []
for bs, be, tp in blocks:
if tp == -1:
disk.extend([0]*(be-bs+1))
else:
disk.extend([tp]*(be-bs+1))
ans = 0
for i,j in enumerate(disk):
ans += i * j
return ans
aoc_helper.lazy_test(day=9, year=2024, parse=parse_raw, solution=part_two)
# aoc_helper.lazy_submit(day=9, year=2024, solution=part_one, data=data)
aoc_helper.lazy_submit(day=9, year=2024, solution=part_two, data=data)