From 6709bf83e98d440ce219348260e13c1ef249526d Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Thu, 1 Dec 2022 21:39:07 +0200 Subject: [PATCH] solve day 1 --- .gitignore | 2 + Makefile | 6 ++ aoc.h | 39 +++++++++++++ day1.c | 85 ++++++++++++++++++++++++++++ main.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 292 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 aoc.h create mode 100644 day1.c create mode 100644 main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..58d53e9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build +input.txt diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f09daaf --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +main: main.c + mkdir -p build + gcc -o build/main main.c -lcurl + +run: main + ./build/main diff --git a/aoc.h b/aoc.h new file mode 100644 index 0000000..6eac67c --- /dev/null +++ b/aoc.h @@ -0,0 +1,39 @@ +#ifndef AOC_H_ +#define AOC_H_ + +#include + +typedef int (*solution_cb)(void*); +typedef struct { + int day; + + void* (*parse)(char** lines, int count); + int (*part1)(void* data); + int (*part2)(void* data); +} Solution; + +// Macro magic for easy of use +#define ADD_SOLUTION(_day, parse, part1, part2) \ + static Solution ptr_##parse; \ + static Solution ptr_##part1; \ + static Solution ptr_##part2 \ + __attribute((used, section("g_solutions"))) = { \ + .parse = parse, \ + .part1 = part1, \ + .part2 = part2, \ + .day = _day \ + } + +#define SOLUTIONS ({ \ + extern Solution __start_##g_solutions; \ + &__start_##g_solutions; \ + }) + +#define SOLUTIONS_END ({ \ + extern Solution __stop_##g_solutions; \ + &__stop_##g_solutions; \ + }) + +#define SOLUTIONS_COUNT SOLUTIONS_END - SOLUTIONS + +#endif //AOC_H_ diff --git a/day1.c b/day1.c new file mode 100644 index 0000000..8fffa68 --- /dev/null +++ b/day1.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include + +#include "aoc.h" + +typedef struct { + int *calories; + size_t count; +} Calories; + +typedef struct { + Calories *elfs; + size_t count; +} Data; + +static void *parse(char **lines, int line_count) { + int elf_indexes[300] = { 0 }; + int elf_count = 1; + for (int i = 1; i < line_count; i++) { + if (strlen(lines[i-1]) == 0) { + elf_indexes[elf_count++] = i; + } + } + elf_indexes[elf_count] = line_count+1; + + Data *data = calloc(1, sizeof(Data)); + data->elfs = calloc(elf_count, sizeof(Calories)); + data->count = elf_count; + + for (int i = 0; i < elf_count; i++) { + int count = (elf_indexes[i+1]-elf_indexes[i])-1; + Calories *calories = &data->elfs[i]; + calories->calories = calloc(count, sizeof(int)); + calories->count = count; + + for (int j = 0; j < count; j++) { + int line = elf_indexes[i]+j; + calories->calories[j] = atoi(lines[line]); + } + } + + return data; +} + +static int part1(void *p) { + Data *data = (Data*)p; + int max_calories = 0; + for (int i = 0; i < data->count; i++) { + int calories = 0; + for (int j = 0; j < data->elfs[i].count; j++) { + calories += data->elfs[i].calories[j]; + } + max_calories = MAX(max_calories, calories); + } + return max_calories; +} + +static int part2(void *p) { + Data *data = (Data*)p; + int max_calories1 = 0; + int max_calories2 = 0; + int max_calories3 = 0; + for (int i = 0; i < data->count; i++) { + int calories = 0; + for (int j = 0; j < data->elfs[i].count; j++) { + calories += data->elfs[i].calories[j]; + } + if (calories > max_calories1) { + max_calories3 = max_calories2; + max_calories2 = max_calories1; + max_calories1 = calories; + } else if (calories > max_calories2) { + max_calories3 = max_calories2; + max_calories2 = calories; + } else if(calories > max_calories3) { + max_calories3 = calories; + } + } + return max_calories1 + max_calories2 + max_calories3; +} + +ADD_SOLUTION(1, parse, part1, part2); diff --git a/main.c b/main.c new file mode 100644 index 0000000..a6be887 --- /dev/null +++ b/main.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "aoc.h" + +#include "day1.c" + +Solution *find_solution(int day) +{ + for (int i = 0; i < SOLUTIONS_COUNT; i++) { + Solution *s = &SOLUTIONS[i]; + if (s->day == day) { + return s; + } + } + return NULL; +} + +char **read_lines(int *line_count, FILE *f) +{ + *line_count = 0; + + rewind(f); + while(!feof(f)){ + char ch = fgetc(f); + if(ch == '\n') { + (*line_count)++; + } + } + + char **lines = malloc(*line_count * sizeof(char*)); + + char *line; + size_t len = 0; + int i = 0; + size_t read; + rewind(f); + while ((read = getline(&line, &len, f)) != -1) { + line[read-1] = '\0'; + lines[i++] = strdup(line); + } + + return lines; +} + +int download_input(int day, char *filename, char *session) +{ + int rc = 0; + + curl_global_init(CURL_GLOBAL_ALL); + FILE *f = fopen(filename, "w"); + CURL *curl = curl_easy_init(); + + CURLcode curl_code; + if (curl) { + char *cookie_header = calloc(42 + strlen(session), sizeof(char)); + sprintf(cookie_header, "Cookie: session=%s", session); + + char url[81] = { 0 }; + sprintf(url, "https://adventofcode.com/2022/day/%d/input", day); + + struct curl_slist *chunk = NULL; + chunk = curl_slist_append(chunk, cookie_header); + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, f); + curl_easy_setopt(curl, CURLOPT_URL, &url); + curl_code = curl_easy_perform(curl); + if (curl_code == CURLE_OK) { + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + if (http_code != 200) { + fprintf(stderr, "Request failed: HTTP code %ld\n", http_code); + rc = -1; + } + } else { + fprintf(stderr, "Request failed: %s\n", curl_easy_strerror(curl_code)); + rc = -1; + } + + curl_easy_cleanup(curl); + curl_slist_free_all(chunk); + } +end: + curl_global_cleanup(); + fclose(f); + if (rc) { + remove(filename); + } + return rc; +} + +void print_solutions() +{ + fprintf(stderr, "Available solutions: "); + for (int i = 0; i < SOLUTIONS_COUNT; i++) { + Solution *s = &SOLUTIONS[i]; + fprintf(stderr, "%d ", s->day); + } + fprintf(stderr, "\n"); +} + +int main(int argc, char** argv) { + if (argc < 2) { + fprintf(stderr, "Usage: %s [input.txt]\n", argv[0]); + exit(1); + } + + int day = atoi(argv[1]); + if (day == 0) { + fprintf(stderr, "Day number is invalid\n"); + print_solutions(); + exit(1); + } + + Solution *solution = find_solution(day); + if (solution == NULL) { + fprintf(stderr, "Failed to find solution to %d\n", day); + print_solutions(); + exit(1); + } + + char *input_file = NULL; + if (argc >= 3) { + input_file = argv[2]; + } else if ( access( "input.txt", F_OK ) != -1 ) { + input_file = "input.txt"; + } else { + char* session = getenv("AOC_SESSION"); + if (session && !download_input(1, "input.txt", session)) { + input_file = "input.txt"; + } else { + fprintf(stderr, "Missing input file"); + exit(1); + } + } + + FILE *f = fopen(input_file, "r"); + if (f == NULL) { + fprintf(stderr, "Failed to open file solution to day '%s': %s\n", input_file, strerror(errno)); + return 1; + } + + int line_count; + char **lines = read_lines(&line_count, f); + + fclose(f); + + void* parsed = solution->parse(lines, line_count); + + printf("part1: %d\n", solution->part1(parsed)); + printf("part2: %d\n", solution->part2(parsed)); + + return 0; +}