advent-of-code

Solutions for Advent of Code.
git clone git://git.amin.space/advent-of-code.git
Log | Files | Refs | LICENSE

commit eedb0f83188dbfee87962a2852cc80fabb39a0d3
parent d8a5a6058174fbd586c62ffeb1bff9463ec45dd1
Author: amin <dev@aminmesbah.com>
Date:   Sat,  4 Dec 2021 03:34:00 +0000

Solve 2021 day 3 part 2

FossilOrigin-Name: 14b7af817a84c5b15c4a730444579c8f66e4d7ff667860d67db6a026c453648e
Diffstat:
A2021/day03_02.c | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 142 insertions(+), 0 deletions(-)

diff --git a/2021/day03_02.c b/2021/day03_02.c @@ -0,0 +1,142 @@ +#if 0 +# Self-building c file. Invoke like: `./file.c` +outdir=out +input=$(basename "$0") +output="$outdir"/$(basename "$0" .c) +if [ "$input" -nt "$output" ]; +then + mkdir --parents "$outdir" || exit + echo "Building ${output}." || exit + clang -std=c11 -Wall -Wextra -pedantic -Wno-unused-function "$input" -o "$output" || exit +fi +if [ "$1" = "-r" ]; +then + ./"$output" "$@" +fi +exit +#endif + +#include <errno.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +_Noreturn void assert_fail(const char *expr, const char *file, int line, const char *func) { + fprintf(stderr, "%s:%d: %s: Assertion failed: '%s'\n", file, line, func, expr); + abort(); +} + +#define AM_ENABLE_ASSERT 1 +#define AM_ASSERT_FAIL(expr, file, line, func) assert_fail(expr, file, line, func) +#include "am_base.h" +#include "am_memory.h" +#include "am_list.h" +#include "am_string.h" + +Str open_file(MemArena *arena, char *path) { + FILE *f = fopen(path, "r"); + assert(f); + + s32 error = fseek(f, 0L, SEEK_END); + assert(!error); + + s64 size = ftell(f); + assert(size >= 0); + rewind(f); + + u8 *buf = am_mem_arena_push(arena, size); + assert(buf); + + size_t items_read = fread(buf, 1, size, f); + assert(items_read == (size_t)size); + + error = fclose(f); + assert(!error); + + return am_str(buf, size); +} + +int compare_u64(const void *a, const void *b) { + u64 num_a = *((u64 *)a); + u64 num_b = *((u64 *)b); + if (num_a == num_b) { + return 0; + } else if (num_a < num_b) { + return -1; + } else { + return 1; + } +} + +u64 filter_by_bit_frequency(u64 *numbers, u64 num_numbers, u64 number_width, bool most_popular) { + u64 first = 0; + u64 opl = num_numbers; + + u64 digit = 0; + while (opl - first > 1) { + assert(digit < number_width); + + //printf("Candidates for digit %" PRIu64 "\n", digit); + //for (u64 i = first; i < opl; i++) { + // char buf[64] = {0}; + // for (size_t digit_i = 0; digit_i < number_width; digit_i++) { + // buf[digit_i] = ((numbers[i] >> (number_width - 1 - digit_i)) & 1) + '0'; + // } + // printf("%4" PRIu64 ": %-4" PRIu64 " %s\n", i, numbers[i], buf); + //} + + for (u64 i = first; i < opl; i++) { + if (((numbers[i] >> (number_width - 1 - digit)) & 1)) { + if ((i - first) > ((opl - first) / 2)) { + // Zero is more frequent + most_popular ? (opl = i) : (first = i); + } else { + // One is more or equally frequent + most_popular ? (first = i) : (opl = i); + } + assert(first < opl); + break; + } + } + + digit++; + } + assert(opl - first == 1); + return numbers[first]; +} + +int main(void) { + MemArena a = am_mem_arena_create(am_mem_base_allocator_malloc()); + Str input = open_file(&a, "day03_input.txt"); + StrList lines = am_str_split(&a, input, (u8 *)"\n", 1); + + u64 num_numbers = lines.node_count; + u64 *numbers = AM_MEM_ARENA_PUSH_ARRAY(&a, u64, num_numbers); + assert(numbers); + memset(numbers, 0, num_numbers); + + u64 width = lines.first->s.size; + { + u64 numbers_i = 0; + for (StrListNode *line = lines.first; line; line = line->next) { + assert(line->s.size == width); + for (u64 i = 0; i < width; i++) { + numbers[numbers_i] |= (line->s.str[i] == '1') << (width - i - 1); + } + numbers_i++; + } + } + + qsort(numbers, num_numbers, sizeof(u64), &compare_u64); + + u64 o2_generator_rating = filter_by_bit_frequency(numbers, num_numbers, width, true); + u64 co2_scrubber_rating = filter_by_bit_frequency(numbers, num_numbers, width, false); + + //printf("Oxygen Generator Rating: %" PRIu64 "\n", o2_generator_rating); + //printf("CO2 Scrubber Rating: %" PRIu64 "\n", co2_scrubber_rating); + printf("Life Support Rating: %" PRIu64 "\n", o2_generator_rating * co2_scrubber_rating); + + am_mem_arena_release(&a); + return 0; +}