Day 9: Disk Fragmenter
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465
Nim
Wrote ugly-ass code today, but it was surprisingly easy to debug and fast.
Solution:
Part 1: Parse data into a sequence of blocks and empty space like in example (I use -1
for empty space) and two indexes. First index goes 0 -> end, second index starts at the end. When we encounter empty space -> we use value from second index and decrement it (while skipping empty spaces). Repeat until both indexes meet at some point.
Part 2: Parse data into sequence of block objects and try to insert each data block into each empty space block before it. Somehow it all just worked without too many bugs.
Runtime (final version): 123 ms
type
BlockKind = enum Data, Space
Block = object
size: int
case kind: BlockKind
of Data:
index: int
of Space:
discard
func parseBlocks(input: string): tuple[blocks: seq[Block], id: int] =
for i, c in input:
let digit = c.ord - '0'.ord
if i mod 2 == 0:
result.blocks.add Block(kind: Data, size: digit, index: result.id)
if i < input.high: inc result.id
else:
result.blocks.add Block(kind: Space, size: digit)
proc solve(input: string): AOCSolution[int, int] =
block p1:
var memBlocks = newSeqOfCap[int](100_000)
var indBlock = 0
for i, c in input:
let digit = c.ord - '0'.ord
if i mod 2 == 0:
memBlocks.add (indBlock).repeat(digit)
inc indBlock
else:
memBlocks.add -1.repeat(digit)
var ind = 0
var revInd = memBlocks.high
while ind <= revInd:
if memBlocks[ind] == -1:
while memBlocks[revInd] == -1: dec revInd
result.part1 += ind * memBlocks[revInd]
dec revInd
else:
result.part1 += ind * memBlocks[ind]
inc ind
block p2:
var (memBlocks, index) = parseBlocks(input)
var revInd = memBlocks.high
while revInd > 0:
doAssert memBlocks[revInd].kind == Data
var spaceInd = -1
let blockSize = memBlocks[revInd].size
for ind in 0..revInd:
if memBlocks[ind].kind == Space and memBlocks[ind].size >= blockSize:
spaceInd = ind; break
if spaceInd != -1:
let bSize = memBlocks[revInd].size
let diffSize = memBlocks[spaceInd].size - bSize
swap(memBlocks[spaceInd], memBlocks[revInd])
if diffSize != 0:
memBlocks[revInd].size = bSize
memBlocks.insert(Block(kind: Space, size: diffSize), spaceInd + 1)
inc revInd # shift index bc we added object
dec index
# skip space blocks and data blocks with higher index
while (dec revInd; revInd < 0 or
memBlocks[revInd].kind != Data or
memBlocks[revInd].index != index): discard
var unitIndex = 0
for b in memBlocks:
case b.kind
of Data:
for _ in 1..b.size:
result.part2 += unitIndex * b.index
inc unitIndex
of Space:
unitIndex += b.size