Compare commits
No commits in common. "9890e141f221dd253b9e06fb4141ef453e6e9e0e" and "093c558628e53ae1d22610f45e86345f3099f2cc" have entirely different histories.
9890e141f2
...
093c558628
2
Makefile
2
Makefile
@ -1,4 +1,4 @@
|
|||||||
main: main.c day*.c vec.h aoc.h point.h
|
main: main.c
|
||||||
gcc -o main main.c -lcurl
|
gcc -o main main.c -lcurl
|
||||||
|
|
||||||
run: main
|
run: main
|
||||||
|
2
aoc.h
2
aoc.h
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
typedef void (*solution_cb)(void*);
|
typedef int (*solution_cb)(void*);
|
||||||
typedef void* (*parse_cb)(char** lines, int count);
|
typedef void* (*parse_cb)(char** lines, int count);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int day;
|
int day;
|
||||||
|
13
day1.c
13
day1.c
@ -16,8 +16,7 @@ typedef struct {
|
|||||||
size_t count;
|
size_t count;
|
||||||
} Data;
|
} Data;
|
||||||
|
|
||||||
static void *day1_parse(char **lines, int line_count)
|
static void *day1_parse(char **lines, int line_count) {
|
||||||
{
|
|
||||||
int elf_indexes[300] = { 0 };
|
int elf_indexes[300] = { 0 };
|
||||||
int elf_count = 1;
|
int elf_count = 1;
|
||||||
for (int i = 1; i < line_count; i++) {
|
for (int i = 1; i < line_count; i++) {
|
||||||
@ -46,8 +45,7 @@ static void *day1_parse(char **lines, int line_count)
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void day1_part1(void *p)
|
static int day1_part1(void *p) {
|
||||||
{
|
|
||||||
Data *data = (Data*)p;
|
Data *data = (Data*)p;
|
||||||
int max_calories = 0;
|
int max_calories = 0;
|
||||||
for (int i = 0; i < data->count; i++) {
|
for (int i = 0; i < data->count; i++) {
|
||||||
@ -57,11 +55,10 @@ static void day1_part1(void *p)
|
|||||||
}
|
}
|
||||||
max_calories = MAX(max_calories, calories);
|
max_calories = MAX(max_calories, calories);
|
||||||
}
|
}
|
||||||
printf("%d\n", max_calories);
|
return max_calories;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void day1_part2(void *p)
|
static int day1_part2(void *p) {
|
||||||
{
|
|
||||||
Data *data = (Data*)p;
|
Data *data = (Data*)p;
|
||||||
int max_calories1 = 0;
|
int max_calories1 = 0;
|
||||||
int max_calories2 = 0;
|
int max_calories2 = 0;
|
||||||
@ -82,7 +79,7 @@ static void day1_part2(void *p)
|
|||||||
max_calories3 = calories;
|
max_calories3 = calories;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("%d\n", max_calories1 + max_calories2 + max_calories3);
|
return max_calories1 + max_calories2 + max_calories3;
|
||||||
}
|
}
|
||||||
|
|
||||||
ADD_SOLUTION(1, day1_parse, day1_part1, day1_part2);
|
ADD_SOLUTION(1, day1_parse, day1_part1, day1_part2);
|
||||||
|
126
day10.c
126
day10.c
@ -1,126 +0,0 @@
|
|||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "aoc.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
INST_TYPE_NOOP,
|
|
||||||
INST_TYPE_ADD,
|
|
||||||
} INST_TYPE;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
INST_TYPE type;
|
|
||||||
int amount;
|
|
||||||
} Instruction;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Instruction *instructions;
|
|
||||||
int count;
|
|
||||||
} day10_Data;
|
|
||||||
|
|
||||||
static void *day10_parse(char **lines, int line_count)
|
|
||||||
{
|
|
||||||
day10_Data *data = malloc(sizeof(day10_Data));
|
|
||||||
data->count = line_count;
|
|
||||||
data->instructions = malloc(line_count * sizeof(Instruction));
|
|
||||||
|
|
||||||
for (int i = 0; i < line_count; i++) {
|
|
||||||
char *line = lines[i];
|
|
||||||
Instruction *inst = &data->instructions[i];
|
|
||||||
if (!strcmp(line, "noop")) {
|
|
||||||
inst->type = INST_TYPE_NOOP;
|
|
||||||
} else { // addx
|
|
||||||
inst->type = INST_TYPE_ADD;
|
|
||||||
inst->amount = atoi(line + 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day10_part1(void *p)
|
|
||||||
{
|
|
||||||
day10_Data *data = p;
|
|
||||||
|
|
||||||
int regx = 1;
|
|
||||||
int result = 0;
|
|
||||||
int inst_idx = 0;
|
|
||||||
int cycle = 0;
|
|
||||||
int add_timer = 0;
|
|
||||||
bool add_started = false;
|
|
||||||
while (inst_idx < data->count) {
|
|
||||||
Instruction *inst = &data->instructions[inst_idx];
|
|
||||||
if (!add_started) {
|
|
||||||
if (inst->type == INST_TYPE_NOOP) {
|
|
||||||
inst_idx++;
|
|
||||||
} else if (inst->type == INST_TYPE_ADD) {
|
|
||||||
add_started = true;
|
|
||||||
add_timer = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cycle++;
|
|
||||||
|
|
||||||
if ((cycle - 20) % 40 == 0 && cycle <= 220) {
|
|
||||||
result += cycle*regx;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (add_started) {
|
|
||||||
add_timer--;
|
|
||||||
if (add_timer == 0) {
|
|
||||||
add_started = false;
|
|
||||||
regx += inst->amount;
|
|
||||||
inst_idx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%d\n", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day10_part2(void *p)
|
|
||||||
{
|
|
||||||
day10_Data *data = p;
|
|
||||||
|
|
||||||
int regx = 1;
|
|
||||||
int inst_idx = 0;
|
|
||||||
int cycle = 0;
|
|
||||||
int add_timer = 0;
|
|
||||||
bool add_started = false;
|
|
||||||
while (inst_idx < data->count) {
|
|
||||||
Instruction *inst = &data->instructions[inst_idx];
|
|
||||||
if (!add_started) {
|
|
||||||
if (inst->type == INST_TYPE_NOOP) {
|
|
||||||
inst_idx++;
|
|
||||||
} else if (inst->type == INST_TYPE_ADD) {
|
|
||||||
add_started = true;
|
|
||||||
add_timer = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (abs(cycle % 40 - regx) <= 1) {
|
|
||||||
printf("#");
|
|
||||||
} else {
|
|
||||||
printf(".");
|
|
||||||
}
|
|
||||||
|
|
||||||
cycle++;
|
|
||||||
|
|
||||||
if (add_started) {
|
|
||||||
add_timer--;
|
|
||||||
if (add_timer == 0) {
|
|
||||||
add_started = false;
|
|
||||||
regx += inst->amount;
|
|
||||||
inst_idx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cycle % 40 == 0) {
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ADD_SOLUTION(10, day10_parse, day10_part1, day10_part2);
|
|
187
day11.c
187
day11.c
@ -1,187 +0,0 @@
|
|||||||
#include <limits.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "aoc.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
MONKEY_OP_ADD,
|
|
||||||
MONKEY_OP_MUL,
|
|
||||||
MONKEY_OP_SQR
|
|
||||||
} MONKEY_OP;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int *items;
|
|
||||||
int item_count;
|
|
||||||
MONKEY_OP op;
|
|
||||||
int op_value;
|
|
||||||
int test_value;
|
|
||||||
int test_true;
|
|
||||||
int test_false;
|
|
||||||
} Monkey;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Monkey *monkeys;
|
|
||||||
int count;
|
|
||||||
} day11_Data;
|
|
||||||
|
|
||||||
static int count_char(char *str, char target)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
for (int i = 0; i < strlen(str); i++) {
|
|
||||||
count += str[i] == target;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_items(char *items, int **result, int *result_count)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
*result_count = count_char(items, ',')+1;
|
|
||||||
*result = malloc(*result_count * sizeof(int));
|
|
||||||
for (char *num = strtok(items, ","); num; num = strtok(NULL, ",")) {
|
|
||||||
(*result)[i] = atoi(num+1);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_operation(char *operation, MONKEY_OP *op, int *op_value)
|
|
||||||
{
|
|
||||||
if (operation[4] == '+') {
|
|
||||||
*op = MONKEY_OP_ADD;
|
|
||||||
*op_value = atoi(operation + 6);
|
|
||||||
} else if (operation[4] == '*' && operation[6] == 'o') {
|
|
||||||
*op = MONKEY_OP_SQR;
|
|
||||||
} else {
|
|
||||||
*op = MONKEY_OP_MUL;
|
|
||||||
*op_value = atoi(operation + 6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void apply_operation(uint64_t *value, MONKEY_OP op, int op_value)
|
|
||||||
{
|
|
||||||
switch (op) {
|
|
||||||
case MONKEY_OP_ADD:
|
|
||||||
*value += op_value;
|
|
||||||
break;
|
|
||||||
case MONKEY_OP_MUL:
|
|
||||||
*value *= op_value;
|
|
||||||
break;
|
|
||||||
case MONKEY_OP_SQR:
|
|
||||||
*value *= *value;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("abort: %d\n", op);
|
|
||||||
fflush(stdout);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *day11_parse(char **lines, int line_count)
|
|
||||||
{
|
|
||||||
day11_Data *data = malloc(sizeof(day11_Data));
|
|
||||||
data->count = (line_count + 1)/7;
|
|
||||||
data->monkeys = malloc(data->count * sizeof(Monkey));
|
|
||||||
|
|
||||||
for (int i = 0; i < line_count; i+=7) {
|
|
||||||
Monkey *monkey = &data->monkeys[i/7];
|
|
||||||
char *starting_items = lines[i+1] + 17;
|
|
||||||
char *operation = lines[i+2] + 19;
|
|
||||||
char *test_value = lines[i+3] + 21;
|
|
||||||
char *test_true = lines[i+4] + 29;
|
|
||||||
char *test_false = lines[i+5] + 30;
|
|
||||||
parse_items(starting_items, &monkey->items, &monkey->item_count);
|
|
||||||
parse_operation(operation, &monkey->op, &monkey->op_value);
|
|
||||||
monkey->test_value = atoi(test_value);
|
|
||||||
monkey->test_true = atoi(test_true);
|
|
||||||
monkey->test_false = atoi(test_false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t solve(day11_Data *data, int rounds, bool reduce_worry)
|
|
||||||
{
|
|
||||||
int monkey_count = data->count;
|
|
||||||
|
|
||||||
int inspections[monkey_count];
|
|
||||||
for (int i = 0; i < data->count; i++) {
|
|
||||||
inspections[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int total_item_count = 0;
|
|
||||||
for (int i = 0; i < monkey_count; i++) {
|
|
||||||
total_item_count += data->monkeys[i].item_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t items[monkey_count][total_item_count];
|
|
||||||
size_t item_counts[monkey_count];
|
|
||||||
for (int i = 0; i < monkey_count; i++) {
|
|
||||||
Monkey *monkey = &data->monkeys[i];
|
|
||||||
item_counts[i] = monkey->item_count;
|
|
||||||
for (int j = 0; j < monkey->item_count; j++) {
|
|
||||||
items[i][j] = monkey->items[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int modulo = 1;
|
|
||||||
for (int i = 0; i < monkey_count; i++) {
|
|
||||||
modulo *= data->monkeys[i].test_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int round = 1; round <= rounds; round++) {
|
|
||||||
for (int i = 0; i < monkey_count; i++) {
|
|
||||||
Monkey *monkey = &data->monkeys[i];
|
|
||||||
for (int j = 0; j < item_counts[i]; j++) {
|
|
||||||
uint64_t item_worry = items[i][j];
|
|
||||||
apply_operation(&item_worry, monkey->op, monkey->op_value);
|
|
||||||
if (reduce_worry) {
|
|
||||||
item_worry /= 3;
|
|
||||||
} else {
|
|
||||||
item_worry %= modulo;
|
|
||||||
}
|
|
||||||
|
|
||||||
int target_monkey;
|
|
||||||
if (item_worry % monkey->test_value == 0) {
|
|
||||||
target_monkey = monkey->test_true;
|
|
||||||
} else {
|
|
||||||
target_monkey = monkey->test_false;
|
|
||||||
}
|
|
||||||
|
|
||||||
items[target_monkey][item_counts[target_monkey]++] = item_worry;
|
|
||||||
}
|
|
||||||
|
|
||||||
inspections[i] += item_counts[i];
|
|
||||||
item_counts[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t top_inspection1 = 0;
|
|
||||||
uint64_t top_inspection2 = 0;
|
|
||||||
for (int i = 0; i < monkey_count; i++) {
|
|
||||||
if (inspections[i] > top_inspection1) {
|
|
||||||
top_inspection2 = top_inspection1;
|
|
||||||
top_inspection1 = inspections[i];
|
|
||||||
} else if (inspections[i] > top_inspection2) {
|
|
||||||
top_inspection2 = inspections[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return top_inspection1*top_inspection2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day11_part1(void *p)
|
|
||||||
{
|
|
||||||
printf("%lu\n", solve(p, 20, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void day11_part2(void *p)
|
|
||||||
{
|
|
||||||
printf("%lu\n", solve(p, 10000, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
ADD_SOLUTION(11, day11_parse, day11_part1, day11_part2);
|
|
41
day2.c
41
day2.c
@ -2,32 +2,34 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "aoc.h"
|
#include "aoc.h"
|
||||||
#include "vec.h"
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char you, opponent;
|
char you, opponent;
|
||||||
} Round;
|
} Round;
|
||||||
|
|
||||||
static void *day2_parse(char **lines, int line_count)
|
typedef struct {
|
||||||
{
|
Round *rounds;
|
||||||
Vec *vec = vec_malloc(line_count);
|
size_t count;
|
||||||
|
} day2_Data;
|
||||||
|
|
||||||
|
static void *day2_parse(char **lines, int line_count) {
|
||||||
|
day2_Data *data = calloc(1, sizeof(day2_Data));
|
||||||
|
data->count = line_count;
|
||||||
|
data->rounds = calloc(line_count, sizeof(Round));
|
||||||
|
|
||||||
for (int i = 0; i < line_count; i++) {
|
for (int i = 0; i < line_count; i++) {
|
||||||
Round *round = malloc(sizeof(Round));
|
data->rounds[i].opponent = lines[i][0];
|
||||||
round->opponent = lines[i][0];
|
data->rounds[i].you = lines[i][2];
|
||||||
round->you = lines[i][2];
|
|
||||||
vec_push(vec, round);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return vec;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void day2_part1(void *p)
|
static int day2_part1(void *p) {
|
||||||
{
|
day2_Data *data = (day2_Data*)p;
|
||||||
Vec *rounds = p;
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
for (int i = 0; i < rounds->count; i++) {
|
for (int i = 0; i < data->count; i++) {
|
||||||
Round *round = rounds->data[i];
|
Round *round = &data->rounds[i];
|
||||||
char you = round->you;
|
char you = round->you;
|
||||||
char opponent = round->opponent;
|
char opponent = round->opponent;
|
||||||
|
|
||||||
@ -49,15 +51,14 @@ static void day2_part1(void *p)
|
|||||||
result += 6;
|
result += 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("%d\n", result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void day2_part2(void *p)
|
static int day2_part2(void *p) {
|
||||||
{
|
day2_Data *data = (day2_Data*)p;
|
||||||
Vec *data = p;
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
for (int i = 0; i < data->count; i++) {
|
for (int i = 0; i < data->count; i++) {
|
||||||
Round *round = data->data[i];
|
Round *round = &data->rounds[i];
|
||||||
char you = round->you;
|
char you = round->you;
|
||||||
char opponent = round->opponent;
|
char opponent = round->opponent;
|
||||||
|
|
||||||
@ -81,7 +82,7 @@ static void day2_part2(void *p)
|
|||||||
result += 6;
|
result += 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("%d\n", result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ADD_SOLUTION(2, day2_parse, day2_part1, day2_part2);
|
ADD_SOLUTION(2, day2_parse, day2_part1, day2_part2);
|
||||||
|
94
day3.c
94
day3.c
@ -1,94 +0,0 @@
|
|||||||
#include <stddef.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "aoc.h"
|
|
||||||
#include "vec.h"
|
|
||||||
|
|
||||||
static void *day3_parse(char **lines, int line_count)
|
|
||||||
{
|
|
||||||
Vec *vec = vec_malloc(line_count);
|
|
||||||
for (size_t i = 0; i < line_count; i++) {
|
|
||||||
vec_push(vec, lines[i]);
|
|
||||||
}
|
|
||||||
return vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool contains(char needle, char* haystack, size_t len)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
|
||||||
if (haystack[i] == needle) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char find_common(char *str1, char* str2, size_t len)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
|
||||||
if (contains(str1[i], str2, len)) {
|
|
||||||
return str1[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_priority(char c)
|
|
||||||
{
|
|
||||||
if ('a' <= c && c <= 'z') {
|
|
||||||
return (c - 'a') + 1;
|
|
||||||
} else if ('A' <= c && c <= 'Z') {
|
|
||||||
return (c - 'A') + 27;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day3_part1(void *p)
|
|
||||||
{
|
|
||||||
Vec *vec = p;
|
|
||||||
int result = 0;
|
|
||||||
for (size_t i = 0; i < vec->count; i++) {
|
|
||||||
char *b = vec->data[i];
|
|
||||||
int size = strlen(b);
|
|
||||||
char common = find_common(b, b + size/2, size/2);
|
|
||||||
if (common) {
|
|
||||||
result += get_priority(common);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Unknown common char at line: %zu\n", i+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("%d\n", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day3_part2(void *p)
|
|
||||||
{
|
|
||||||
Vec *vec = p;
|
|
||||||
int result = 0;
|
|
||||||
for (size_t i = 0; i < vec->count; i+=3) {
|
|
||||||
char *b1 = vec->data[i+0];
|
|
||||||
char *b2 = vec->data[i+1];
|
|
||||||
char *b3 = vec->data[i+2];
|
|
||||||
int size1 = strlen(b1);
|
|
||||||
int size2 = strlen(b2);
|
|
||||||
int size3 = strlen(b3);
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
for (size_t j = 0; j < size1; j++) {
|
|
||||||
char c = b1[j];
|
|
||||||
if (contains(c, b2, size2) && contains(c, b3, size3)) {
|
|
||||||
result += get_priority(c);
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
fprintf(stderr, "Unknown common char at line: %zu-%zu\n", i+1, i+3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("%d\n", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
ADD_SOLUTION(3, day3_parse, day3_part1, day3_part2);
|
|
78
day4.c
78
day4.c
@ -1,78 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
|
|
||||||
#include "aoc.h"
|
|
||||||
#include "vec.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int from, to;
|
|
||||||
} Range;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Range first;
|
|
||||||
Range second;
|
|
||||||
} DoubleRange;
|
|
||||||
|
|
||||||
static inline void day4_parse_range(Range *range, char *s)
|
|
||||||
{
|
|
||||||
range->from = atoi(strsep(&s, "-"));
|
|
||||||
range->to = atoi(strsep(&s, "-"));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day4_parse_line(DoubleRange *double_range, char *line)
|
|
||||||
{
|
|
||||||
char *line_copy = strdup(line);
|
|
||||||
char *line_copy_start = line_copy;
|
|
||||||
day4_parse_range(&double_range->first, strsep(&line_copy, ","));
|
|
||||||
day4_parse_range(&double_range->second, strsep(&line_copy, ","));
|
|
||||||
free(line_copy_start);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *day4_parse(char **lines, int line_count)
|
|
||||||
{
|
|
||||||
Vec *vec = vec_malloc(line_count);
|
|
||||||
for (size_t i = 0; i < line_count; i++) {
|
|
||||||
DoubleRange *double_range = malloc(sizeof(DoubleRange));
|
|
||||||
vec_push(vec, double_range);
|
|
||||||
day4_parse_line(double_range, lines[i]);
|
|
||||||
}
|
|
||||||
return vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day4_part1(void *p)
|
|
||||||
{
|
|
||||||
Vec *vec = p;
|
|
||||||
int result = 0;
|
|
||||||
for (int i = 0; i < vec->count; i++) {
|
|
||||||
DoubleRange *double_range = vec->data[i];
|
|
||||||
Range *range1 = &double_range->first;
|
|
||||||
Range *range2 = &double_range->second;
|
|
||||||
if ((range1->from <= range2->from && range1->to >= range2->to) ||
|
|
||||||
(range2->from <= range1->from && range2->to >= range1->to)) {
|
|
||||||
result++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("%d\n", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day4_part2(void *p)
|
|
||||||
{
|
|
||||||
Vec *vec = p;
|
|
||||||
int result = 0;
|
|
||||||
for (int i = 0; i < vec->count; i++) {
|
|
||||||
DoubleRange *double_range = vec->data[i];
|
|
||||||
Range *range1 = &double_range->first;
|
|
||||||
Range *range2 = &double_range->second;
|
|
||||||
if ((range1->from <= range2->from && range1->to >= range2->to) ||
|
|
||||||
(range2->from <= range1->from && range2->to >= range1->to) ||
|
|
||||||
MIN(range1->to, range2->to) >= MAX(range1->from, range2->from)) {
|
|
||||||
result++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("%d\n", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ADD_SOLUTION(4, day4_parse, day4_part1, day4_part2);
|
|
165
day5.c
165
day5.c
@ -1,165 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
|
|
||||||
#include "aoc.h"
|
|
||||||
#include "vec.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int from, to, amount;
|
|
||||||
} Move;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Vec *towers;
|
|
||||||
Vec *moves;
|
|
||||||
} day5_Data;
|
|
||||||
|
|
||||||
static Move* day5_parse_move(char *line)
|
|
||||||
{
|
|
||||||
char* line_copy = strdup(line);
|
|
||||||
char* line_copy_original = line_copy;
|
|
||||||
strsep(&line_copy, " ");
|
|
||||||
char* amount = strsep(&line_copy, " ");
|
|
||||||
strsep(&line_copy, " ");
|
|
||||||
char* from = strsep(&line_copy, " ");
|
|
||||||
strsep(&line_copy, " ");
|
|
||||||
char* to = strsep(&line_copy, " ");
|
|
||||||
|
|
||||||
Move *move = malloc(sizeof(Move));
|
|
||||||
move->amount = atoi(amount);
|
|
||||||
move->from = atoi(from)-1;
|
|
||||||
move->to = atoi(to)-1;
|
|
||||||
free(line_copy);
|
|
||||||
return move;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *day5_parse(char **lines, int line_count)
|
|
||||||
{
|
|
||||||
int tower_count = 0;
|
|
||||||
int max_tower_height;
|
|
||||||
|
|
||||||
for (int i = 0; i < line_count; i++) {
|
|
||||||
if (lines[i][0] == '\0') {
|
|
||||||
max_tower_height = i-1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
tower_count = MAX(tower_count, (strlen(lines[i])+1)/4);
|
|
||||||
}
|
|
||||||
|
|
||||||
int move_count = line_count - max_tower_height - 2;
|
|
||||||
Vec *moves = vec_malloc(move_count);
|
|
||||||
for (int i = 0; i < move_count; i++) {
|
|
||||||
char *line = lines[max_tower_height+2+i];
|
|
||||||
vec_push(moves, day5_parse_move(line));
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec *towers = vec_malloc(tower_count);
|
|
||||||
for (int i = 0; i < tower_count; i++) {
|
|
||||||
char* tower = calloc(26, sizeof(char));
|
|
||||||
vec_push(towers, tower);
|
|
||||||
}
|
|
||||||
for (int i = max_tower_height-1; i >= 0; i--) {
|
|
||||||
char* line = lines[i];
|
|
||||||
int line_size = strlen(line);
|
|
||||||
for (int j = 0; j < tower_count; j++) {
|
|
||||||
int index = j*4 + 1;
|
|
||||||
if (index >= line_size) break;
|
|
||||||
if (line[index] == ' ') continue;
|
|
||||||
|
|
||||||
char* tower = towers->data[j];
|
|
||||||
tower[max_tower_height-i-1] = line[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
day5_Data *data = malloc(sizeof(day5_Data));
|
|
||||||
data->moves = moves;
|
|
||||||
data->towers = towers;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void do_move(char **towers, int *tower_sizes, int from, int to)
|
|
||||||
{
|
|
||||||
int from_size = tower_sizes[from];
|
|
||||||
int to_size = tower_sizes[to];
|
|
||||||
towers[to][to_size] = towers[from][from_size-1];
|
|
||||||
|
|
||||||
tower_sizes[from]--;
|
|
||||||
tower_sizes[to]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void do_move_many(char **towers, int *tower_sizes, int from, int to, int amount)
|
|
||||||
{
|
|
||||||
int from_size = tower_sizes[from];
|
|
||||||
int to_size = tower_sizes[to];
|
|
||||||
memcpy(towers[to] + to_size, towers[from] + from_size - amount, amount);
|
|
||||||
|
|
||||||
tower_sizes[from] -= amount;
|
|
||||||
tower_sizes[to] += amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char* form_answer(char **towers, int tower_count, int *tower_sizes)
|
|
||||||
{
|
|
||||||
char *answer = malloc(tower_count + 1);
|
|
||||||
answer[tower_count] = '\0';
|
|
||||||
for (int i = 0; i < tower_count; i++) {
|
|
||||||
char *tower = towers[i];
|
|
||||||
answer[i] = tower[tower_sizes[i]-1];
|
|
||||||
}
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day5_part1(void *p)
|
|
||||||
{
|
|
||||||
day5_Data *data = p;
|
|
||||||
int tower_count = data->towers->count;
|
|
||||||
char *towers[tower_count];
|
|
||||||
int tower_sizes[tower_count];
|
|
||||||
for (int i = 0; i < tower_count; i++) {
|
|
||||||
towers[i] = calloc(26, sizeof(char));
|
|
||||||
memcpy(towers[i], data->towers->data[i], 26);
|
|
||||||
|
|
||||||
tower_sizes[i] = 0;
|
|
||||||
for (int j = 0; j < 26; j++) {
|
|
||||||
if (towers[i][j] == 0) break;
|
|
||||||
tower_sizes[i]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < data->moves->count; i++) {
|
|
||||||
Move *move = data->moves->data[i];
|
|
||||||
for (int j = 0; j < move->amount; j++) {
|
|
||||||
do_move(towers, tower_sizes, move->from, move->to);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%s\n", form_answer(towers, tower_count, tower_sizes));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day5_part2(void *p)
|
|
||||||
{
|
|
||||||
day5_Data *data = p;
|
|
||||||
int tower_count = data->towers->count;
|
|
||||||
char *towers[tower_count];
|
|
||||||
int tower_sizes[tower_count];
|
|
||||||
for (int i = 0; i < tower_count; i++) {
|
|
||||||
towers[i] = calloc(26, sizeof(char));
|
|
||||||
memcpy(towers[i], data->towers->data[i], 26);
|
|
||||||
|
|
||||||
tower_sizes[i] = 0;
|
|
||||||
for (int j = 0; j < 26; j++) {
|
|
||||||
if (towers[i][j] == 0) break;
|
|
||||||
tower_sizes[i]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < data->moves->count; i++) {
|
|
||||||
Move *move = data->moves->data[i];
|
|
||||||
do_move_many(towers, tower_sizes, move->from, move->to, move->amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%s\n", form_answer(towers, tower_count, tower_sizes));
|
|
||||||
}
|
|
||||||
|
|
||||||
ADD_SOLUTION(5, day5_parse, day5_part1, day5_part2);
|
|
56
day6.c
56
day6.c
@ -1,56 +0,0 @@
|
|||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "aoc.h"
|
|
||||||
|
|
||||||
#define MESSAGE_LENGTH 14
|
|
||||||
|
|
||||||
static void *day6_parse(char **lines, int line_count)
|
|
||||||
{
|
|
||||||
return lines[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day6_part1(void *p)
|
|
||||||
{
|
|
||||||
char *msg = p;
|
|
||||||
int n = strlen(msg);
|
|
||||||
for (int i = 3; i < n; i++) {
|
|
||||||
char c1 = msg[i-3];
|
|
||||||
char c2 = msg[i-2];
|
|
||||||
char c3 = msg[i-1];
|
|
||||||
char c4 = msg[i-0];
|
|
||||||
if (c1 != c2 && c1 != c3 && c1 != c4 &&
|
|
||||||
c2 != c3 && c2 != c4 &&
|
|
||||||
c3 != c4) {
|
|
||||||
printf("%d\n", i+1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_start_of_message(char *str)
|
|
||||||
{
|
|
||||||
for (int i=0; i < MESSAGE_LENGTH - 1; i++) {
|
|
||||||
for (int j=i+1; j < MESSAGE_LENGTH; j++) {
|
|
||||||
if (str[i] == str[j]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day6_part2(void *p)
|
|
||||||
{
|
|
||||||
char *msg = p;
|
|
||||||
int n = strlen(msg);
|
|
||||||
for (int i = 0; i < n-13; i++) {
|
|
||||||
if (is_start_of_message(msg+i)) {
|
|
||||||
printf("%d\n", i+14);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ADD_SOLUTION(6, day6_parse, day6_part1, day6_part2);
|
|
166
day7.c
166
day7.c
@ -1,166 +0,0 @@
|
|||||||
#include <limits.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
|
|
||||||
#include "aoc.h"
|
|
||||||
#include "vec.h"
|
|
||||||
|
|
||||||
#define CD_CMD "$ cd"
|
|
||||||
#define LS_CMD "$ ls"
|
|
||||||
|
|
||||||
#define TOTAL_FS_SIZE 70000000
|
|
||||||
#define UPDATE_SIZE 30000000
|
|
||||||
|
|
||||||
struct TreeNode {
|
|
||||||
char *name;
|
|
||||||
struct TreeNode *parent;
|
|
||||||
struct TreeNode **children;
|
|
||||||
size_t children_count;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct TreeNode *append_node(struct TreeNode *parent, char *child_name, size_t size)
|
|
||||||
{
|
|
||||||
struct TreeNode *new_child = calloc(1, sizeof(struct TreeNode));
|
|
||||||
new_child->parent = parent;
|
|
||||||
new_child->name = child_name;
|
|
||||||
new_child->size = size;
|
|
||||||
|
|
||||||
parent->children = realloc(parent->children, sizeof(struct TreeNode*)*(parent->children_count+1));
|
|
||||||
parent->children[parent->children_count] = new_child;
|
|
||||||
parent->children_count++;
|
|
||||||
return new_child;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct TreeNode *get_or_append_child(struct TreeNode *parent, char *child_name)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < parent->children_count; i++) {
|
|
||||||
struct TreeNode *child = parent->children[i];
|
|
||||||
if (strcmp(child->name, child_name) == 0) {
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return append_node(parent, child_name, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int find_char(char *haystack, char needle) {
|
|
||||||
int n = strlen(haystack);
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
if (haystack[i] == needle) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void populate_directory_sizes(struct TreeNode *start)
|
|
||||||
{
|
|
||||||
struct TreeNode *current = start;
|
|
||||||
while (current != start->parent) {
|
|
||||||
bool is_explored = true;
|
|
||||||
for (int i = 0; i < current->children_count; i++) {
|
|
||||||
struct TreeNode *child = current->children[i];
|
|
||||||
if (child->size == -1) {
|
|
||||||
current = child;
|
|
||||||
is_explored = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_explored) {
|
|
||||||
current->size = 0;
|
|
||||||
for (int i = 0; i < current->children_count; i++) {
|
|
||||||
current->size += current->children[i]->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
current = current->parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *day7_parse(char **lines, int line_count)
|
|
||||||
{
|
|
||||||
struct TreeNode *root = calloc(1, sizeof(struct TreeNode));
|
|
||||||
root->name = "/";
|
|
||||||
|
|
||||||
struct TreeNode *current = root;
|
|
||||||
for (int i = 0; i < line_count; i++) {
|
|
||||||
char *line = lines[i];
|
|
||||||
if (strncmp(line, CD_CMD, sizeof(CD_CMD)-1) == 0) {
|
|
||||||
char *dir_name = line + sizeof(CD_CMD);
|
|
||||||
if (strncmp(dir_name, "/", 1) == 0) {
|
|
||||||
current = root;
|
|
||||||
} else if (strncmp(dir_name, "..", 2) == 0) {
|
|
||||||
current = current->parent;
|
|
||||||
} else {
|
|
||||||
current = get_or_append_child(current, dir_name);
|
|
||||||
}
|
|
||||||
} else if (strncmp(line, LS_CMD, sizeof(LS_CMD)) == 0) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
if (strncmp(line, "dir", 3) == 0) {
|
|
||||||
char *dir_name = line + 4;
|
|
||||||
get_or_append_child(current, dir_name);
|
|
||||||
} else {
|
|
||||||
int sep = find_char(line, ' ');
|
|
||||||
char *child_name = line + sep + 1;
|
|
||||||
line[sep] = '\0';
|
|
||||||
int size = strtol(line, NULL, 10);
|
|
||||||
line[sep] = ' ';
|
|
||||||
append_node(current, child_name, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day7_part1(void *p)
|
|
||||||
{
|
|
||||||
struct TreeNode *root = p;
|
|
||||||
|
|
||||||
populate_directory_sizes(root);
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
Vec *stack = vec_malloc(10);
|
|
||||||
vec_push(stack, root);
|
|
||||||
while (stack->count > 0) {
|
|
||||||
struct TreeNode *node = vec_pop(stack);
|
|
||||||
if (node->size <= 100000 && node->children_count > 0) {
|
|
||||||
result += node->size;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < node->children_count; i++) {
|
|
||||||
vec_push(stack, node->children[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%d\n", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day7_part2(void *p)
|
|
||||||
{
|
|
||||||
struct TreeNode *root = p;
|
|
||||||
|
|
||||||
populate_directory_sizes(root);
|
|
||||||
|
|
||||||
int needed_space = UPDATE_SIZE - (TOTAL_FS_SIZE - root->size);
|
|
||||||
|
|
||||||
int result = INT_MAX;
|
|
||||||
Vec *stack = vec_malloc(10);
|
|
||||||
vec_push(stack, root);
|
|
||||||
while (stack->count > 0) {
|
|
||||||
struct TreeNode *node = vec_pop(stack);
|
|
||||||
if (node->size >= needed_space && node->children_count > 0) {
|
|
||||||
result = MIN(result, node->size);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < node->children_count; i++) {
|
|
||||||
vec_push(stack, node->children[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%d\n", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
ADD_SOLUTION(7, day7_parse, day7_part1, day7_part2);
|
|
119
day8.c
119
day8.c
@ -1,119 +0,0 @@
|
|||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
|
|
||||||
#include "aoc.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t **data;
|
|
||||||
size_t width, height;
|
|
||||||
} day8_Map;
|
|
||||||
|
|
||||||
static void *day8_parse(char **lines, int line_count)
|
|
||||||
{
|
|
||||||
day8_Map *map = malloc(sizeof(day8_Map));
|
|
||||||
map->height = line_count;
|
|
||||||
map->width = strlen(lines[0]);
|
|
||||||
map->data = malloc(map->height*sizeof(uint8_t*));
|
|
||||||
for (int y = 0; y < map->height; y++) {
|
|
||||||
map->data[y] = malloc(map->width*sizeof(uint8_t));
|
|
||||||
for (int x = 0; x < map->width; x++) {
|
|
||||||
map->data[y][x] = lines[y][x] - '0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_visible_horizontal(day8_Map *map, uint8_t value, int x0, int x1, int y)
|
|
||||||
{
|
|
||||||
for (int xi = x0; xi < x1; xi++) {
|
|
||||||
if (map->data[y][xi] >= value) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_visible_vertical(day8_Map *map, uint8_t value, int x, int y0, int y1)
|
|
||||||
{
|
|
||||||
for (int yi = y0; yi < y1; yi++) {
|
|
||||||
if (map->data[yi][x] >= value) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_visible(day8_Map *map, int x, int y) {
|
|
||||||
uint8_t current = map->data[y][x];
|
|
||||||
return is_visible_horizontal (map, current, x+1, map->width, y) ||
|
|
||||||
is_visible_horizontal(map, current, 0, x, y) ||
|
|
||||||
is_visible_vertical (map, current, x, y+1, map->height) ||
|
|
||||||
is_visible_vertical (map, current, x, 0, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_horizontal_edge(day8_Map *map, uint8_t value, int x0, int x1, int y)
|
|
||||||
{
|
|
||||||
if (x0 <= x1) {
|
|
||||||
for (int xi = x0; xi <= x1; xi++) {
|
|
||||||
if (map->data[y][xi] >= value) return xi;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int xi = x0; xi >= x1; xi--) {
|
|
||||||
if (map->data[y][xi] >= value) return xi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return x1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_vertical_edge(day8_Map *map, uint8_t value, int x, int y0, int y1)
|
|
||||||
{
|
|
||||||
if (y0 <= y1) {
|
|
||||||
for (int yi = y0; yi <= y1; yi++) {
|
|
||||||
if (map->data[yi][x] >= value) return yi;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int yi = y0; yi >= y1; yi--) {
|
|
||||||
if (map->data[yi][x] >= value) return yi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return y1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_score(day8_Map *map, int x, int y) {
|
|
||||||
uint8_t value = map->data[y][x];
|
|
||||||
int right_edge = get_horizontal_edge(map, value, x+1, map->width-1, y);
|
|
||||||
int left_edge = get_horizontal_edge(map, value, x-1, 0 , y);
|
|
||||||
int bottom_edge = get_vertical_edge (map, value, x, y+1, map->height-1);
|
|
||||||
int top_edge = get_vertical_edge (map, value, x, y-1, 0);
|
|
||||||
return (right_edge - x) * (x - left_edge) * (bottom_edge - y) * (y - top_edge);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day8_part1(void *p)
|
|
||||||
{
|
|
||||||
day8_Map *map = p;
|
|
||||||
|
|
||||||
int result = map->height * map->width - (map->height-2) * (map->width-2);
|
|
||||||
for (int y = 1; y < map->height-1; y++) {
|
|
||||||
for (int x = 1; x < map->width-1; x++) {
|
|
||||||
result += is_visible(map, x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%d\n", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day8_part2(void *p)
|
|
||||||
{
|
|
||||||
day8_Map *map = p;
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
for (int y = 1; y < map->height-1; y++) {
|
|
||||||
for (int x = 1; x < map->width-1; x++) {
|
|
||||||
result = MAX(result, get_score(map, x, y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%d\n", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
ADD_SOLUTION(8, day8_parse, day8_part1, day8_part2);
|
|
213
day9.c
213
day9.c
@ -1,213 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
|
|
||||||
#include "aoc.h"
|
|
||||||
#include "point.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
MOVE_DIR_UP,
|
|
||||||
MOVE_DIR_DOWN,
|
|
||||||
MOVE_DIR_LEFT,
|
|
||||||
MOVE_DIR_RIGHT,
|
|
||||||
} MOVE_DIR;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
MOVE_DIR dir;
|
|
||||||
int count;
|
|
||||||
} RopeMove;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
RopeMove *moves;
|
|
||||||
int count;
|
|
||||||
} day9_Data;
|
|
||||||
|
|
||||||
static MOVE_DIR parse_move_dir(char dir)
|
|
||||||
{
|
|
||||||
switch (dir) {
|
|
||||||
case 'R': return MOVE_DIR_RIGHT;
|
|
||||||
case 'L': return MOVE_DIR_LEFT;
|
|
||||||
case 'U': return MOVE_DIR_UP;
|
|
||||||
case 'D': return MOVE_DIR_DOWN;
|
|
||||||
}
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *day9_parse(char **lines, int line_count)
|
|
||||||
{
|
|
||||||
day9_Data *data = malloc(sizeof(day9_Data));
|
|
||||||
data->moves = malloc(line_count * sizeof(RopeMove));
|
|
||||||
data->count = line_count;
|
|
||||||
|
|
||||||
for (int i = 0; i < line_count; i++) {
|
|
||||||
char *line = lines[i];
|
|
||||||
RopeMove *move = &data->moves[i];
|
|
||||||
move->dir = parse_move_dir(line[0]);
|
|
||||||
move->count = atoi(line+2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sign(int x)
|
|
||||||
{
|
|
||||||
return x > 0 ? 1 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_bounding_box(day9_Data *moves, int *ox, int *oy, int *width, int *height)
|
|
||||||
{
|
|
||||||
int minx = 0, maxx = 0;
|
|
||||||
int miny = 0, maxy = 0;
|
|
||||||
int x = 0, y = 0;
|
|
||||||
for (int i = 0; i < moves->count; i++) {
|
|
||||||
RopeMove *move = &moves->moves[i];
|
|
||||||
switch (move->dir) {
|
|
||||||
case MOVE_DIR_UP:
|
|
||||||
y -= move->count;
|
|
||||||
break;
|
|
||||||
case MOVE_DIR_DOWN:
|
|
||||||
y += move->count;
|
|
||||||
break;
|
|
||||||
case MOVE_DIR_LEFT:
|
|
||||||
x -= move->count;
|
|
||||||
break;
|
|
||||||
case MOVE_DIR_RIGHT:
|
|
||||||
x += move->count;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
minx = MIN(x, minx);
|
|
||||||
maxx = MAX(x, maxx);
|
|
||||||
miny = MIN(y, miny);
|
|
||||||
maxy = MAX(y, maxy);
|
|
||||||
}
|
|
||||||
|
|
||||||
*ox = -minx;
|
|
||||||
*oy = -miny;
|
|
||||||
*width = maxx - minx + 1;
|
|
||||||
*height = maxy - miny + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_move_direction(MOVE_DIR dir, int *dx, int *dy)
|
|
||||||
{
|
|
||||||
switch (dir) {
|
|
||||||
case MOVE_DIR_UP:
|
|
||||||
*dy = -1;
|
|
||||||
break;
|
|
||||||
case MOVE_DIR_DOWN:
|
|
||||||
*dy = 1;
|
|
||||||
break;
|
|
||||||
case MOVE_DIR_LEFT:
|
|
||||||
*dx = -1;
|
|
||||||
break;
|
|
||||||
case MOVE_DIR_RIGHT:
|
|
||||||
*dx = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void follow_point(Point *tail, Point *head)
|
|
||||||
{
|
|
||||||
int diffx = abs(head->x - tail->x);
|
|
||||||
int diffy = abs(head->y - tail->y);
|
|
||||||
if (diffx > 1 || diffy > 1) {
|
|
||||||
if (diffx + diffy > 2) {
|
|
||||||
tail->x += sign(head->x - tail->x);
|
|
||||||
tail->y += sign(head->y - tail->y);
|
|
||||||
} else if (diffx > 1) {
|
|
||||||
tail->x += sign(head->x - tail->x);
|
|
||||||
} else if (diffy > 1) {
|
|
||||||
tail->y += sign(head->y - tail->y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day9_part1(void *p)
|
|
||||||
{
|
|
||||||
day9_Data *moves = p;
|
|
||||||
|
|
||||||
int ox, oy, width, height;
|
|
||||||
get_bounding_box(moves, &ox, &oy, &width, &height);
|
|
||||||
|
|
||||||
bool map[width][height];
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
map[x][y] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
map[ox][oy] = true;
|
|
||||||
|
|
||||||
Point head = { 0, 0 };
|
|
||||||
Point tail = { 0, 0 };
|
|
||||||
for (int i = 0; i < moves->count; i++) {
|
|
||||||
RopeMove *move = &moves->moves[i];
|
|
||||||
int dx = 0, dy = 0;
|
|
||||||
get_move_direction(move->dir, &dx, &dy);
|
|
||||||
for (int j = 0; j < move->count; j++) {
|
|
||||||
head.x += dx;
|
|
||||||
head.y += dy;
|
|
||||||
|
|
||||||
follow_point(&tail, &head);
|
|
||||||
map[tail.x+ox][tail.y+oy] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
result += map[x][y];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("%d\n", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void day9_part2(void *p)
|
|
||||||
{
|
|
||||||
day9_Data *moves = p;
|
|
||||||
|
|
||||||
int ox, oy, width, height;
|
|
||||||
get_bounding_box(moves, &ox, &oy, &width, &height);
|
|
||||||
|
|
||||||
bool map[width][height];
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
map[x][y] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
map[ox][oy] = true;
|
|
||||||
|
|
||||||
int rope_size = 10;
|
|
||||||
Point rope[rope_size];
|
|
||||||
for (int i = 0; i < rope_size; i++) {
|
|
||||||
rope[i].x = 0;
|
|
||||||
rope[i].y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < moves->count; i++) {
|
|
||||||
RopeMove *move = &moves->moves[i];
|
|
||||||
int dx = 0, dy = 0;
|
|
||||||
get_move_direction(move->dir, &dx, &dy);
|
|
||||||
for (int _ = 0; _ < move->count; _++) {
|
|
||||||
Point *head = &rope[0];
|
|
||||||
head->x += dx;
|
|
||||||
head->y += dy;
|
|
||||||
|
|
||||||
for (int j = 1; j < rope_size; j++) {
|
|
||||||
follow_point(&rope[j], &rope[j-1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Point *tail = &rope[rope_size-1];
|
|
||||||
map[tail->x+ox][tail->y+oy] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
result += map[x][y];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("%d\n", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
ADD_SOLUTION(9, day9_parse, day9_part1, day9_part2);
|
|
15
main.c
15
main.c
@ -10,15 +10,6 @@
|
|||||||
|
|
||||||
#include "day1.c"
|
#include "day1.c"
|
||||||
#include "day2.c"
|
#include "day2.c"
|
||||||
#include "day3.c"
|
|
||||||
#include "day4.c"
|
|
||||||
#include "day5.c"
|
|
||||||
#include "day6.c"
|
|
||||||
#include "day7.c"
|
|
||||||
#include "day8.c"
|
|
||||||
#include "day9.c"
|
|
||||||
#include "day10.c"
|
|
||||||
#include "day11.c"
|
|
||||||
|
|
||||||
Solution *find_solution(int day)
|
Solution *find_solution(int day)
|
||||||
{
|
{
|
||||||
@ -163,10 +154,8 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
void* parsed = solution->parse(lines, line_count);
|
void* parsed = solution->parse(lines, line_count);
|
||||||
|
|
||||||
printf("part1:\n");
|
printf("part1: %d\n", solution->part1(parsed));
|
||||||
solution->part1(parsed);
|
printf("part2: %d\n", solution->part2(parsed));
|
||||||
printf("part2:\n");
|
|
||||||
solution->part2(parsed);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
8
point.h
8
point.h
@ -1,8 +0,0 @@
|
|||||||
#ifndef POINT_H_
|
|
||||||
#define POINT_H_
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int x, y;
|
|
||||||
} Point;
|
|
||||||
|
|
||||||
#endif //POINT_H_
|
|
44
vec.h
44
vec.h
@ -1,44 +0,0 @@
|
|||||||
#ifndef VEC_H_
|
|
||||||
#define VEC_H_
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int count;
|
|
||||||
int capacity;
|
|
||||||
void **data;
|
|
||||||
} Vec;
|
|
||||||
|
|
||||||
static inline Vec *vec_malloc(size_t capacity)
|
|
||||||
{
|
|
||||||
Vec *vec = (Vec*)malloc(sizeof(Vec));
|
|
||||||
vec->count = 0;
|
|
||||||
vec->capacity = capacity;
|
|
||||||
vec->data = (void**)malloc(capacity * sizeof(void*));
|
|
||||||
return vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void vec_push(Vec *vec, void* value)
|
|
||||||
{
|
|
||||||
if (vec->count >= vec->capacity) {
|
|
||||||
vec->capacity = (vec->capacity + 1) * 2;
|
|
||||||
vec->data = (void**)realloc(vec->data, vec->capacity * sizeof(void*));
|
|
||||||
}
|
|
||||||
vec->data[vec->count++] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void *vec_pop(Vec* vec)
|
|
||||||
{
|
|
||||||
vec->count--;
|
|
||||||
return vec->data[vec->count];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void vec_free(Vec *v)
|
|
||||||
{
|
|
||||||
free(v->data);
|
|
||||||
free(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif //VEC_H_
|
|
Loading…
Reference in New Issue
Block a user