advent2021

Advent of Code 2021 Solutions
git clone git://bsandro.tech/advent2021
Log | Files | Refs

commit 611849971270657c9e0a448daa378bde4fd349a2
parent 35af63181a8d7493308737dc0d8a4094a5fc0100
Author: bsandro <[email protected]>
Date:   Wed,  8 Dec 2021 00:19:04 +0200

Added day 07 puzzle 2 bruteforce solution

Diffstat:
Acommon/quicksort.h | 30++++++++++++++++++++++++++++++
Acommon/util.c | 40++++++++++++++++++++++++++++++++++++++++
Mcommon/util.h | 22++++++++--------------
Mday04/Makefile | 2+-
Mday04/puzzle12.c | 22+---------------------
Mday05/Makefile | 2+-
Mday07/Makefile | 7+++++--
Mday07/main.c | 21++++++++++++++++++---
Mday07/puzzle.c | 59++---------------------------------------------------------
Aday07/puzzle_brute.c | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10 files changed, 168 insertions(+), 99 deletions(-)

diff --git a/common/quicksort.h b/common/quicksort.h @@ -0,0 +1,30 @@ +#pragma once + +/* ******************* quicksort ***********************/ + +static void qs_swap(int *a, int *b) { + int tmp = *a; + *a = *b; + *b = tmp; +} + +static long long qs_partition(int *numbers, long long low, long long high) { + int pivot = numbers[high]; + long long i = low - 1; + for (long long j = low; j <= high - 1; ++j) { + if (numbers[j] < pivot) { + i++; + qs_swap(&numbers[i], &numbers[j]); + } + } + qs_swap(&numbers[i+1], &numbers[high]); + return i + 1; +} + +static void qs(int *numbers, long long low, long long high) { + if (low < high) { + long long p = qs_partition(numbers, low, high); + qs(numbers, low, p - 1); + qs(numbers, p + 1, high); + } +} diff --git a/common/util.c b/common/util.c @@ -0,0 +1,40 @@ +#include <string.h> +#include <stdlib.h> +#include "util.h" + +void array_init(struct array_t *array, size_t elem_size, size_t cap) { + assert(array->data == NULL); + array->cap = cap; + array->elem_size = elem_size; + array->data = calloc(cap, elem_size); + assert(array->data != NULL); +} + +void array_expand(struct array_t *array) { + size_t new_cap = array->cap * 2; + array->data = realloc(array->data, array->elem_size * new_cap); + assert(array->data != NULL); + array->cap = new_cap; +} + +/* ******************* parse plain numbers array *******************/ +void parse_numbers_array(struct array_t *numbers, const char *str, const char *delim) { + assert(numbers != NULL); + char *tmp = strndup(str, STR_LEN_LIMIT); + char *token = NULL; + assert(tmp != NULL); + + while ((token = strsep(&tmp, delim)) != NULL) { + int num = atoi(token); + + if (numbers->count >= numbers->cap) { + array_expand(numbers); + } + + int *data = (int *)numbers->data; + data[numbers->count++] = num; + } + + free(tmp); +} + diff --git a/common/util.h b/common/util.h @@ -1,11 +1,15 @@ +#pragma once + #include <stdio.h> #include <assert.h> +#define STR_LEN_LIMIT 8192 #define PRINT_ERR(func) fprintf(stderr, #func "() error: %s\n", strerror(errno)); #define FMT_(l) #l #define FMT(l) FMT_(l) +/* ************** simple arrays **********************/ struct array_t { void *data; size_t elem_size; @@ -23,18 +27,8 @@ struct array_t { printf("\n"); \ } while (0); -void array_init(struct array_t *array, size_t elem_size, size_t cap) { - assert(array->data == NULL); - array->cap = cap; - array->elem_size = elem_size; - array->data = calloc(cap, elem_size); - assert(array->data != NULL); -} - -void array_expand(struct array_t *array) { - size_t new_cap = array->cap * 2; - array->data = realloc(array->data, array->elem_size * new_cap); - assert(array->data != NULL); - array->cap = new_cap; -} +void array_init(struct array_t *array, size_t elem_size, size_t cap); +void array_expand(struct array_t *array); +/* ******************* parse plain numbers array *******************/ +void parse_numbers_array(struct array_t *numbers, const char *str, const char *delim); diff --git a/day04/Makefile b/day04/Makefile @@ -1,6 +1,6 @@ NAME=$(shell basename ${PWD}) CC=cc -SRC=$(wildcard *.c) +SRC=$(wildcard *.c ../common/*.c) DEPS:=$(wildcard *.h ../common/*.h) OBJ:=$(SRC:.c=.o) diff --git a/day04/puzzle12.c b/day04/puzzle12.c @@ -22,7 +22,6 @@ struct board_t { bool won; }; -void make_numbers_array(struct array_t *numbers, const char *str); void fill_board(struct board_t *board, int row, const char *str); int check_board(struct board_t *board, int num); void print_boards(const struct array_t *boards); @@ -53,7 +52,7 @@ void puzzle(const char *filename, int *result1, int *result2) { while (fgets(buf, STR_LEN, infile) != NULL) { // first line is always random numbers sequence if (line_num == 0) { - make_numbers_array(&numbers, buf); + parse_numbers_array(&numbers, buf, ","); } else if (strlen(buf) == 1) { // line sized 1 is a separator before boards if (boards.count >= boards.cap) { @@ -150,25 +149,6 @@ void print_boards(const struct array_t *boards) { } } -void make_numbers_array(struct array_t *numbers, const char *str) { - char *tmp = strndup(str, STR_LEN); - char *token = NULL; - assert(tmp != NULL); - - while ((token = strsep(&tmp, ",")) != NULL) { - int num = atoi(token); - - if (numbers->count >= numbers->cap) { - array_expand(numbers); - } - - int *data = (int *)numbers->data; - data[numbers->count++] = num; - } - - free(tmp); -} - void fill_board(struct board_t *board, int row, const char *str) { char *tmp = strndup(str, STR_LEN); assert(tmp != NULL); diff --git a/day05/Makefile b/day05/Makefile @@ -1,6 +1,6 @@ NAME=$(shell basename ${PWD}) CC=cc -SRC=$(wildcard *.c) +SRC=$(wildcard *.c ../common/*.c) DEPS:=$(wildcard *.h ../common/*.h) OBJ:=$(SRC:.c=.o) diff --git a/day07/Makefile b/day07/Makefile @@ -1,9 +1,9 @@ NAME=$(shell basename ${PWD}) CC=cc -SRC=$(wildcard *.c) +SRC=$(wildcard *.c ../common/*.c) DEPS:=$(wildcard *.h ../common/*.h) OBJ:=$(SRC:.c=.o) -CFLAGS=-O0 -g -std=c99 -Werror -Wall -Wextra -I. -I../common +CFLAGS=-O2 -std=c99 -Werror -Wall -Wextra -I. -I../common LDFLAGS=-lc -lm all: $(NAME) @@ -24,3 +24,6 @@ run: $(NAME) test: $(NAME) ./$(NAME) test.txt + +brute: $(NAME) + ./$(NAME) -b input.txt diff --git a/day07/main.c b/day07/main.c @@ -1,7 +1,9 @@ #include <stdio.h> #include <time.h> +#include <string.h> void puzzle(const char *filename, size_t *res1, size_t *res2); +void puzzle_brute(const char *filename, size_t *res1, size_t *res2); int main(int argc, char *argv[]) { printf("Advent of Code: day 07\n"); @@ -10,17 +12,30 @@ int main(int argc, char *argv[]) { if (argc <= 0) { return -1; } - if (argc <= 1) { + + if (argc == 1) { printf("Usage: %s inputfile.txt\n", argv[0]); return -1; } - const char *filename = argv[1]; + const char *filename = argv[1]; //NULL; + int is_brute = 0; + + if (argc == 2) { + filename = argv[1]; + } else { // > 2 + is_brute = strlen(argv[1]) == 2 && strncmp(argv[1], "-b", 2) == 0; + filename = argv[2]; + } size_t counter1 = 0; size_t counter2 = 0; - puzzle(filename, &counter1, &counter2); + if (is_brute) { + puzzle_brute(filename, &counter1, &counter2); + } else { + puzzle(filename, &counter1, &counter2); + } printf("Puzzle #1: %zu\n", counter1); printf("Puzzle #2: %zu\n", counter2); diff --git a/day07/puzzle.c b/day07/puzzle.c @@ -11,17 +11,10 @@ #include <math.h> #include "util.h" +#include "quicksort.h" #define STR_LEN 16384 -void make_numbers_array(struct array_t *numbers, const char *str); - -void qs_swap(int *a, int *b); -long long qs_partition(int *numbers, long long low, long long high); -void qs(int *numbers, long long low, long long high); - -/* ****************************************************************** */ - void puzzle(const char *filename, size_t *result1, size_t *result2) { FILE *infile = fopen(filename, "r"); if (infile == NULL) { @@ -36,7 +29,7 @@ void puzzle(const char *filename, size_t *result1, size_t *result2) { array_init(&numbers, sizeof(int), 100); while (fgets(buf, STR_LEN, infile) != NULL) { - make_numbers_array(&numbers, buf); + parse_numbers_array(&numbers, buf, ","); ++line_num; bzero(buf, STR_LEN); } @@ -66,51 +59,3 @@ void puzzle(const char *filename, size_t *result1, size_t *result2) { free(numbers.data); fclose(infile); } - -/* ************************* BOILERPLATE ************************* */ - -void make_numbers_array(struct array_t *numbers, const char *str) { - char *tmp = strndup(str, STR_LEN); - char *token = NULL; - assert(tmp != NULL); - - while ((token = strsep(&tmp, ",")) != NULL) { - int num = atoi(token); - - if (numbers->count >= numbers->cap) { - array_expand(numbers); - } - - int *data = (int *)numbers->data; - data[numbers->count++] = num; - } - - free(tmp); -} - -void qs_swap(int *a, int *b) { - int tmp = *a; - *a = *b; - *b = tmp; -} - -long long qs_partition(int *numbers, long long low, long long high) { - int pivot = numbers[high]; - long long i = low - 1; - for (long long j = low; j <= high - 1; ++j) { - if (numbers[j] < pivot) { - i++; - qs_swap(&numbers[i], &numbers[j]); - } - } - qs_swap(&numbers[i+1], &numbers[high]); - return i + 1; -} - -void qs(int *numbers, long long low, long long high) { - if (low < high) { - long long p = qs_partition(numbers, low, high); - qs(numbers, low, p - 1); - qs(numbers, p + 1, high); - } -} diff --git a/day07/puzzle_brute.c b/day07/puzzle_brute.c @@ -0,0 +1,62 @@ +#define _DEFAULT_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <strings.h> +#include <stdbool.h> +#include <assert.h> +#include <time.h> +#include <math.h> +#include <limits.h> + +#include "util.h" +#include "quicksort.h" + +#define STR_LEN 16384 + +void puzzle_brute(const char *filename, size_t *result1, size_t *result2) { + FILE *infile = fopen(filename, "r"); + if (infile == NULL) { + fprintf(stderr, "fopen() error: %s\n", strerror(errno)); + return; + } + + char buf[STR_LEN] = {0}; + unsigned int line_num = 0; + + struct array_t numbers = { .data = NULL }; + array_init(&numbers, sizeof(int), 100); + + while (fgets(buf, STR_LEN, infile) != NULL) { + parse_numbers_array(&numbers, buf, ","); + ++line_num; + bzero(buf, STR_LEN); + } + + qs((int *)numbers.data, 0, numbers.count - 1); + + // median average + size_t index = numbers.count / 2; + int *data = (int *)numbers.data; + int mid = data[index]; + for (size_t i = 0; i < numbers.count; ++i) { + *result1 += abs(data[i] - mid); + } + + // dumb bruteforcing + *result2 = ULONG_MAX; + for (int i = data[0]; i < data[numbers.count - 1]; ++i) { + size_t sum = 0; + for (size_t j = 0; j < numbers.count; ++j) { + int dist = abs(i - data[j]); + sum += dist * (1 + dist) / 2; + } + *result2 = fmin(*result2, (double)sum); + } + + // mutiny! ignoring feof/ferror. + free(numbers.data); + fclose(infile); +}