1
1
module Day09
2
2
3
3
using AdventOfCode2024
4
+ using StaticArrays
4
5
5
6
6
7
function day09 (input:: String = readInput (joinpath (@__DIR__ , " .." , " data" , " day09.txt" )))
7
- data, filelist, spacelist = parse_data (input)
8
- p1 = part1! (copy (data ))
9
- p2 = part2! (data )
8
+ blocks = parse_input (input)
9
+ p1 = part1! (deepcopy (blocks ))
10
+ p2 = part2! (blocks )
10
11
return [p1, p2]
11
12
end
12
13
13
- function parse_data (input)
14
- data = Int[]
15
- filelist = Tuple{Int,Int}[]
16
- spacelist = Tuple{Int,Int}[]
17
- id = 0
18
- isfile = true
19
- index = 1
20
- for d ∈ rstrip (input)
21
- n = parse (Int, d)
22
- if isfile
23
- push! (data, (id * ones (Int, n)). .. )
24
- push! (filelist, (index, n))
25
- id += 1
26
- else
27
- push! (data, (- 1 * ones (Int, n)). .. )
28
- push! (spacelist, (index, n))
29
- end
30
- isfile = ! isfile
31
- index += n
14
+ function parse_input (input)
15
+ digits = parse .(Int, split (rstrip (input), " " ))
16
+ if length (digits) % 2 == 1
17
+ push! (digits, 0 )
32
18
end
33
- return data, filelist, spacelist
34
- end
35
19
36
- function part1! (data)
37
- ispace, inumber = 1 , length (data)
38
- while ispace < inumber
39
- while ispace < length (data) && data[ispace] != - 1
40
- ispace += 1
41
- end
42
- while inumber > 0 && data[inumber] == - 1
43
- inumber -= 1
44
- end
45
- ispace > inumber && break
46
- data[ispace], data[inumber] = data[inumber], data[ispace]
47
- ispace += 1
48
- inumber -= 1
20
+ # start index of block, capacity, used space, original id
21
+ disk = Vector {MVector{4,Int}} ()
22
+ current_id = 0
23
+ current_index = 1
24
+ i = 1
25
+ while i < length (digits)
26
+ push! (disk, (current_index, digits[i] + digits[i+ 1 ], digits[i], current_id))
27
+ current_index += digits[i] + digits[i+ 1 ]
28
+ current_id += 1
29
+ i += 2
49
30
end
50
- return checksum (data)
31
+ return disk
51
32
end
52
33
53
- function checksum (data)
54
- s, i = 0 , 1
55
- while i < length (data)
56
- if data[i] == - 1
34
+ function part1! (blocks:: Vector{MVector{4,Int}} )
35
+ data = generate_disk (blocks)
36
+ i, j = 1 , length (blocks)
37
+ while i < j
38
+ freeindex = blocks[i][1 ] + blocks[i][3 ]
39
+ free = blocks[i][2 ] - blocks[i][3 ]
40
+ maxtransfer = blocks[j][3 ]
41
+ transfer = free >= maxtransfer ? maxtransfer : free
42
+ data[freeindex: freeindex+ transfer- 1 ] .= blocks[j][4 ]
43
+ data[blocks[j][1 ]+ blocks[j][3 ]- transfer: blocks[j][1 ]+ blocks[j][3 ]- 1 ] .= - 1
44
+ blocks[i][3 ] += transfer
45
+ blocks[j][3 ] -= transfer
46
+ if blocks[i][2 ] == blocks[i][3 ]
57
47
i += 1
58
- continue
59
48
end
60
- s += data[i] * (i - 1 )
61
- i += 1
49
+ if blocks[j][3 ] == 0
50
+ j -= 1
51
+ end
62
52
end
63
- return s
53
+ return data |> checksum
64
54
end
65
55
66
- # TODO : Debug: Why is this wrong?
67
- function part2! (data, filelist, spacelist)
68
- for (ifilestart, ifilelength) ∈ reverse (filelist)
69
- for (i, (ispacestart, ispacelength)) ∈ enumerate (spacelist)
70
- if ispacelength >= ifilelength
71
- data[ispacestart: ispacestart + ifilelength - 1 ] .= data[ifilestart]
72
- data[ifilestart: ifilestart + ifilelength - 1 ] .= - 1
73
- spacelist[i] = (ispacestart + ifilelength, ispacelength - ifilelength)
56
+ function part2! (blocks:: Vector{MVector{4,Int}} )
57
+ data = generate_disk (blocks)
58
+ original_usage = [b[3 ] for b ∈ blocks]
59
+ for j ∈ reverse (axes (blocks, 1 ))
60
+ transfer = original_usage[j]
61
+ for i ∈ 1 : j- 1
62
+ free = blocks[i][2 ] - blocks[i][3 ]
63
+ if free >= transfer
64
+ data[blocks[i][1 ]+ blocks[i][3 ]: blocks[i][1 ]+ blocks[i][3 ]+ transfer- 1 ] .= blocks[j][4 ]
65
+ data[blocks[j][1 ]: blocks[j][1 ]+ transfer- 1 ] .= - 1
66
+ blocks[i][3 ] += transfer
67
+ blocks[j][3 ] -= transfer
74
68
break
75
69
end
76
70
end
77
- println (string (data))
78
- end
79
- return checksum (data)
80
- end
81
-
82
- function part2! (data)
83
- ifile = length (data)
84
- while true
85
- ifile, lenfile = prev_file (data, ifile)
86
- ifile == 0 && return checksum (data)
87
- ispace, lenspace = free_space (data, lenfile, ifile)
88
- if ispace == 0
89
- ifile -= 1
90
- continue
91
- else
92
- data[ispace: ispace+ lenfile- 1 ] .= data[ifile]
93
- data[ifile: ifile+ lenfile- 1 ] .= - 1
94
- ifile -= 1
95
- end
96
71
end
97
-
72
+ return data |> checksum
98
73
end
99
74
100
- function prev_file (data, i)
101
- i <= 0 && return 0 , 0
102
- if data[i] == - 1
103
- while data[i] == - 1
104
- if i == 0
105
- return 0 , 0
106
- end
107
- i -= 1
108
- end
109
- end
110
- id = data[i]
111
- while i > 0 && data[i] == id
112
- i -= 1
75
+ function generate_disk (blocks:: Vector{MVector{4,Int}} )
76
+ data = - 1 * ones (Int, blocks[end ][1 ] + blocks[end ][2 ] - 1 )
77
+ for block ∈ blocks
78
+ data[block[1 ]: block[1 ]+ block[3 ]- 1 ] .= block[4 ]
113
79
end
114
- istart = i + 1
115
- iend = istart
116
- while iend <= length (data) && data[iend] == data[istart]
117
- iend += 1
118
- end
119
- iend -= 1
120
- return istart, iend - istart + 1
80
+ return data
121
81
end
122
82
123
- function free_space (data, len, imax)
124
- free_indices = findall (x -> x == - 1 , data)
125
- visited = similar (data, Bool)
126
- visited .= false
127
- for i ∈ free_indices
128
- i >= imax && return 0 , 0
129
- visited[i] && continue
130
- istart = iend = i
131
- while iend <= length (data) && data[iend] == - 1
132
- visited[iend] = true
133
- iend += 1
83
+ function checksum (data:: Vector{Int} )
84
+ s, i = 0 , 1
85
+ while i < length (data)
86
+ if data[i] == - 1
87
+ i += 1
88
+ continue
134
89
end
135
- iend -= 1
136
- l = iend - istart + 1
137
- l >= len && return istart, l
90
+ s += data[i] * (i - 1 )
91
+ i += 1
138
92
end
139
- return 0 , 0
93
+ return s
140
94
end
141
95
142
96
end # module
0 commit comments