177 lines
4.3 KiB
C
177 lines
4.3 KiB
C
#include <stdint.h>
|
|
|
|
#include "memory.h"
|
|
#include "printf.h"
|
|
#include "parse.h"
|
|
|
|
static int disk_map_to_blocks1(const char * input, int length,
|
|
int * blocks)
|
|
{
|
|
int head = 0;
|
|
int tail = (parse_find_first_right(input, length, '\n') - input) - 1;
|
|
tail = (tail / 2) * 2; // round down to even index
|
|
|
|
int ix = 0;
|
|
|
|
int compact_file_id = -1;
|
|
int compact_file_size = 0;
|
|
|
|
while (head <= tail) {
|
|
switch (head % 2) {
|
|
case 0: // even : a file / id
|
|
{
|
|
int file_id = head / 2;
|
|
int file_size = parse_base10_digit(input[head++]);
|
|
while (file_size > 0) {
|
|
blocks[ix++] = file_id;
|
|
file_size -= 1;
|
|
}
|
|
}
|
|
break;
|
|
case 1: // odd : free space
|
|
{
|
|
int free_space = parse_base10_digit(input[head++]);
|
|
while (free_space > 0) {
|
|
if (compact_file_size == 0) { // next from tail
|
|
compact_file_id = tail / 2;
|
|
compact_file_size = parse_base10_digit(input[tail]);
|
|
tail -= 2;
|
|
}
|
|
blocks[ix++] = compact_file_id;
|
|
compact_file_size -= 1;
|
|
free_space -= 1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
while (compact_file_size > 0) {
|
|
blocks[ix++] = compact_file_id;
|
|
compact_file_size -= 1;
|
|
}
|
|
|
|
return ix;
|
|
}
|
|
|
|
static int64_t calculate_checksum(int * blocks, int length)
|
|
{
|
|
int64_t sum = 0;
|
|
for (int i = 0; i < length; i++) {
|
|
int64_t id = blocks[i];
|
|
if (id < 0)
|
|
continue;
|
|
int64_t next_sum = sum + id * (int64_t)i;
|
|
if (next_sum < sum)
|
|
printf("overflow\n");
|
|
sum = next_sum;
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
static int allocate_leftmost_freespace(const char * free_list,
|
|
int file_id,
|
|
int file_size)
|
|
{
|
|
for (int free_ix = 0; free_ix < file_id; free_ix += 1) {
|
|
if (free_list[free_ix] >= file_size) {
|
|
// allocate this free space to this file
|
|
return free_ix;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int disk_map_to_blocks2(const char * input, int length,
|
|
int * blocks)
|
|
{
|
|
int tail = (parse_find_first_right(input, length, '\n') - input) - 1;
|
|
tail = (tail / 2) * 2; // round down to even index
|
|
|
|
char free_list[length / 2];
|
|
for (int i = 0; i < length / 2; i++) {
|
|
free_list[i] = parse_base10_digit(input[i * 2 + 1]);
|
|
}
|
|
|
|
int alloc_ids[length / 2];
|
|
|
|
while (tail >= 0) {
|
|
int file_id = tail / 2;
|
|
int file_size = parse_base10_digit(input[tail]);
|
|
|
|
int free_ix = allocate_leftmost_freespace(free_list,
|
|
file_id,
|
|
file_size);
|
|
if (free_ix != -1) {
|
|
// move the file to the free space
|
|
free_list[free_ix] -= file_size;
|
|
alloc_ids[file_id] = free_ix * 2 + 1;
|
|
} else {
|
|
// do not move the file
|
|
alloc_ids[file_id] = file_id * 2 + 0;
|
|
}
|
|
|
|
tail -= 2;
|
|
}
|
|
|
|
/*
|
|
for (int i = 0; i < length / 2; i++) {
|
|
printf("%d %d ; ", i, alloc_ids[i]);
|
|
}
|
|
printf("\n");
|
|
*/
|
|
|
|
// build the block list from alloc_ids
|
|
int ix = 0;
|
|
for (int disk_map_ix = 0; disk_map_ix < length; disk_map_ix++) {
|
|
int map_size = parse_base10_digit(input[disk_map_ix]);
|
|
|
|
// find alloc_ids for this disk_map_ix, starting from the end of alloc_ids
|
|
for (int file_id = (length / 2) - 1; file_id >= 0; file_id -= 1) {
|
|
if (alloc_ids[file_id] == disk_map_ix) {
|
|
int file_size = parse_base10_digit(input[file_id * 2 + 0]);
|
|
for (int i = 0; i < file_size; i++) {
|
|
blocks[ix++] = file_id;
|
|
}
|
|
map_size -= file_size;
|
|
}
|
|
}
|
|
|
|
// is there free space for this disk_map_ix?
|
|
while (map_size > 0) {
|
|
blocks[ix++] = -1;
|
|
map_size -= 1;
|
|
}
|
|
}
|
|
|
|
return ix;
|
|
}
|
|
|
|
static void print_blocks(int * blocks, int length)
|
|
{
|
|
for (int i = 0; i < length; i++) {
|
|
int file_id = blocks[i];
|
|
if (file_id == -1)
|
|
print_char('.');
|
|
else
|
|
printf("%d", file_id);
|
|
}
|
|
print_char('\n');
|
|
}
|
|
|
|
int64_t day9_part1(const char * input, int length)
|
|
{
|
|
int blocks[length * 9];
|
|
int ix = disk_map_to_blocks1(input, length, blocks);
|
|
//print_blocks(blocks, ix);
|
|
return calculate_checksum(blocks, ix);
|
|
}
|
|
|
|
int64_t day9_part2(const char * input, int length)
|
|
{
|
|
int blocks[length * 9];
|
|
int ix = disk_map_to_blocks2(input, length, blocks);
|
|
//print_blocks(blocks, ix);
|
|
return calculate_checksum(blocks, ix);
|
|
}
|