From 1485eb3cd514849e06eca29c7d256bc4e3d41fd8 Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Fri, 5 Dec 2025 08:52:58 +0100 Subject: [PATCH] Implement 2025 day 5 in C --- 2025/day05/.gitignore | 1 + 2025/day05/Makefile | 6 ++ 2025/day05/README.md | 12 ++++ 2025/day05/sample.txt | 11 +++ 2025/day05/solve.c | 160 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 190 insertions(+) create mode 100644 2025/day05/.gitignore create mode 100644 2025/day05/Makefile create mode 100644 2025/day05/README.md create mode 100644 2025/day05/sample.txt create mode 100644 2025/day05/solve.c diff --git a/2025/day05/.gitignore b/2025/day05/.gitignore new file mode 100644 index 0000000..b199abc --- /dev/null +++ b/2025/day05/.gitignore @@ -0,0 +1 @@ +solve diff --git a/2025/day05/Makefile b/2025/day05/Makefile new file mode 100644 index 0000000..8bb8a51 --- /dev/null +++ b/2025/day05/Makefile @@ -0,0 +1,6 @@ +CFLAGS=-Wall -Wextra -O2 -g + +all: solve + +clean: + $(RM) solve diff --git a/2025/day05/README.md b/2025/day05/README.md new file mode 100644 index 0000000..cbe984e --- /dev/null +++ b/2025/day05/README.md @@ -0,0 +1,12 @@ +# Day 05: C + +C is weird. It's a very simple language but it's made complicated by the fact that you have to do +everything yourself. Relatively straightforward solution. + +```console +$ make +cc -Wall -Wextra -O2 -g solve.c -o solve +$ ./solve sample.txt +Part1: 3 +Part2: 14 +``` diff --git a/2025/day05/sample.txt b/2025/day05/sample.txt new file mode 100644 index 0000000..2e9078d --- /dev/null +++ b/2025/day05/sample.txt @@ -0,0 +1,11 @@ +3-5 +10-14 +16-20 +12-18 + +1 +5 +8 +11 +17 +32 diff --git a/2025/day05/solve.c b/2025/day05/solve.c new file mode 100644 index 0000000..a38e301 --- /dev/null +++ b/2025/day05/solve.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include + + #define MAX(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) + +typedef struct { + uint64_t start; + uint64_t end; +} range_t; + +typedef struct { + size_t length; + size_t capacity; + range_t* buffer; +} ranges_t; + +static int cmp_range(void const* va, void const* vb) { + range_t const* a = va; + range_t const* b = vb; + + if (a->start == b->start) { + return (a->end > b->end) - (a->end < b->end); + } else { + return (a->start > b->start) - (a->start < b-> start); + } +} + +static void simplify_ranges(ranges_t* ranges) { + // First, sort ranges ascending by start (then end) + qsort(ranges->buffer, ranges->length, sizeof(range_t), cmp_range); + + const size_t length = ranges->length; + range_t* write_ptr = &ranges->buffer[0]; + + // Important, skip the first iteration, it can never be merged + for (size_t i = 1; i < length; ++i) { + if (ranges->buffer[i].start <= write_ptr->end) { + // Merge the two ranges + write_ptr->end = MAX(write_ptr->end, ranges->buffer[i].end); + ranges->length--; + } else { + write_ptr++; + if (write_ptr != &ranges->buffer[i]) { + memcpy(write_ptr, &ranges->buffer[i], sizeof(range_t)); + } + } + } + + // for (size_t i = 0; i < ranges->length; ++i) { + // printf("%" PRIu64 "-%" PRIu64 "\n", ranges->buffer[i].start, ranges->buffer[i].end); + // } + + // printf("Original length: %u, new length: %u\n", (unsigned int) length, (unsigned int) ranges->length); +} + +bool is_fresh(const uint64_t ingredient, ranges_t const * const ranges) { + size_t min = 0; + size_t size = ranges->length; + range_t const* buffer = ranges->buffer; + + while (size > 1) { + size_t half = size / 2; + size_t mid = min + half; + + if (buffer[mid].start <= ingredient) { + min = mid; + } + + size -= half; + } + + return buffer[min].start <= ingredient && buffer[min].end >= ingredient; +} + +int main(const int argc, char const** argv) { + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + ranges_t ranges = { + .length = 0, + .capacity = 2, + .buffer = malloc(2 * sizeof(range_t)), + }; + + FILE* input = fopen(argv[1], "r"); + if (input == NULL) { + perror("failed to open file"); + exit(1); + } + + uint64_t ingredient; + bool seen_first = false; + + while (!seen_first) { + uint64_t start; + uint64_t end; + + switch (fscanf(input, "%" PRIu64 "-%" PRIu64, &start, &end)) { + case 1: + seen_first = true; + ingredient = start; + break; + + case 2: + if (ranges.capacity == ranges.length) { + size_t new_capacity = ranges.capacity * 2; + range_t* buffer = realloc(ranges.buffer, new_capacity * sizeof(range_t)); + if (buffer == NULL) { + printf("Failed to resize ranges buffer\n"); + return 1; + } + + ranges.capacity = new_capacity; + ranges.buffer = buffer; + } + + ranges.buffer[ranges.length].start = start; + ranges.buffer[ranges.length].end = end; + ranges.length++; + break; + default: + printf("Unexpected end of file\n"); + return 1; + } + } + + simplify_ranges(&ranges); + + int total_fresh = 0; + + do { + if (is_fresh(ingredient, &ranges)) { + total_fresh++; + } + } while (fscanf(input, "%" PRIu64 "\n", &ingredient) == 1); + + printf("Part1: %u\n", total_fresh); + + uint64_t combined_fresh = 0; + + for (size_t i = 0; i < ranges.length; ++i) { + combined_fresh += ranges.buffer[i].end - ranges.buffer[i].start + 1; + } + + printf("Part2: %" PRIu64 "\n", combined_fresh); + + fclose(input); + free(ranges.buffer); + + return 0; +}