i:0N 2#.'1:"i/9.in"
a:(+/*'i)#,/&'i / blocks that will be used, is it free?
+/(&*'i)*(&~a),|&a / checksum: file ID * block position
a:@[&+/'i;&,/&'i;:;0N] / blocks, null for empty
m:{ / move[blocks, ID]
l:+/x=y / length of file
i:(*&x=y)&/&l&/':^x / first available free space
@[x(y=x)'0N;i+!l;:;y]} / move file to i
+/(f^0N)*&~^f:a m/|!#i / move blocks in descending order, then checksum
Another lame imperative day...
I have a feeling there's a more elegant way to express part 1, but I just can't grasp it.
Part 2 can definitely be optimized, at the cost of clarity. For example, you only need to consider free blocks to the left of the file. I experimented with other methods of finding the first available free space, such as whiles and null scans, but stencil seemed to be the fastest.
~/aoc24k/9.html