advent-of-code-2024/day-09/main.c

122 lines
3.0 KiB
C

#include "aoc.h"
typedef struct {
int id; // -1 if free space
int len;
int offset;
} Block;
static void
dump(int *ids, int len) {
for (int i = 0; i < len; i++) {
if (ids[i] == -1) {
printf(".");
}
else {
printf("%d", ids[i] % 10);
}
}
puts("");
}
static void
disk_from_blocks(i32 *disk, Block *blocks, usize block_count) {
for (usize i = 0; i < block_count; i++) {
Block *block = blocks + i;
for (int j = 0; j < block->len; j++) {
disk[j] = block->id;
}
disk += block->len;
}
}
int main(int argc, char **argv) {
(void) argc;
Arena *arena = make_arena(Megabytes(10));
str input = str_trim(read_file(arena, argv[1]));
enum {
STATE_BLOCK,
STATE_SPACE,
} state = STATE_BLOCK;
int block_id = 0;
DYNAMIC_ARRAY(Block) blocks = {0};
isize total_size = 0;
for (usize i = 0; i < input.len; ++i) {
int len = input.data[i] - '0';
*push(&blocks, arena) = (Block) {
.id = (state == STATE_BLOCK) ? block_id : -1,
.len = len,
.offset = total_size
};
total_size += len;
if (state == STATE_BLOCK) {
block_id++;
state = STATE_SPACE;
}
else {
state = STATE_BLOCK;
}
}
ASSERT(state == STATE_SPACE);
i32 *disk = ARENA_ALLOC_ARRAY(arena, i32, total_size);
disk_from_blocks(disk, blocks.data, blocks.len);
isize to = 0, from = total_size - 1;
for (;;) {
while (to <= from && disk[to] != -1) {
to++;
}
while (from > to && disk[from] == -1) {
from--;
}
if (to >= from) {
break;
}
ASSERT((disk[to] == -1) && (disk[from] != -1));
disk[to] = disk[from];
disk[from] = -1;
from--;
to++;
}
i64 part_1 = 0;
for (isize i = 0; i < total_size && disk[i] != -1; i++) {
part_1 += i * disk[i];
}
printf("%ld\n", part_1);
// restore original layout
disk_from_blocks(disk, blocks.data, blocks.len);
for (isize from_block_index = blocks.len - 1; from_block_index >= 0; from_block_index -= 2) {
Block *from = blocks.data + from_block_index;
ASSERT(from->id != -1);
for (isize to_block_index = 1; to_block_index < from_block_index; to_block_index += 2) {
Block *to = blocks.data + to_block_index;
ASSERT(to->id == -1);
if (from->len <= to->len) {
for (isize i = 0; i < from->len; i++) {
disk[to->offset + i] = from->id;
disk[from->offset + i] = -1;
}
to->offset += from->len;
to->len -= from->len;
break;
}
}
}
i64 part_2 = 0;
for (isize i = 0; i < total_size; i++) {
if (disk[i] != -1) {
part_2 += i * disk[i];
}
}
printf("%ld\n", part_2);
}