Compare commits
10 Commits
093c558628
...
9890e141f2
Author | SHA1 | Date | |
---|---|---|---|
9890e141f2 | |||
869259ef4e | |||
2c2c4ccfa9 | |||
344124eebb | |||
25d56534c9 | |||
bd9cf44c2d | |||
78dc6e8d2c | |||
db68cca73e | |||
441471ae48 | |||
750ada0c1d |
2
Makefile
2
Makefile
@ -1,4 +1,4 @@
|
|||||||
main: main.c
|
main: main.c day*.c vec.h aoc.h point.h
|
||||||
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 int (*solution_cb)(void*);
|
typedef void (*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,7 +16,8 @@ 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++) {
|
||||||
@ -45,7 +46,8 @@ static void *day1_parse(char **lines, int line_count) {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int day1_part1(void *p) {
|
static void 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++) {
|
||||||
@ -55,10 +57,11 @@ static int day1_part1(void *p) {
|
|||||||
}
|
}
|
||||||
max_calories = MAX(max_calories, calories);
|
max_calories = MAX(max_calories, calories);
|
||||||
}
|
}
|
||||||
return max_calories;
|
printf("%d\n", max_calories);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int day1_part2(void *p) {
|
static void 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;
|
||||||
@ -79,7 +82,7 @@ static int day1_part2(void *p) {
|
|||||||
max_calories3 = calories;
|
max_calories3 = calories;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return max_calories1 + max_calories2 + max_calories3;
|
printf("%d\n", 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
Normal file
126
day10.c
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
#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
Normal file
187
day11.c
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
#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,34 +2,32 @@
|
|||||||
#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;
|
||||||
|
|
||||||
typedef struct {
|
static void *day2_parse(char **lines, int line_count)
|
||||||
Round *rounds;
|
{
|
||||||
size_t count;
|
Vec *vec = vec_malloc(line_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++) {
|
||||||
data->rounds[i].opponent = lines[i][0];
|
Round *round = malloc(sizeof(Round));
|
||||||
data->rounds[i].you = lines[i][2];
|
round->opponent = lines[i][0];
|
||||||
|
round->you = lines[i][2];
|
||||||
|
vec_push(vec, round);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int day2_part1(void *p) {
|
static void day2_part1(void *p)
|
||||||
day2_Data *data = (day2_Data*)p;
|
{
|
||||||
|
Vec *rounds = p;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
for (int i = 0; i < data->count; i++) {
|
for (int i = 0; i < rounds->count; i++) {
|
||||||
Round *round = &data->rounds[i];
|
Round *round = rounds->data[i];
|
||||||
char you = round->you;
|
char you = round->you;
|
||||||
char opponent = round->opponent;
|
char opponent = round->opponent;
|
||||||
|
|
||||||
@ -51,14 +49,15 @@ static int day2_part1(void *p) {
|
|||||||
result += 6;
|
result += 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
printf("%d\n", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int day2_part2(void *p) {
|
static void 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->rounds[i];
|
Round *round = data->data[i];
|
||||||
char you = round->you;
|
char you = round->you;
|
||||||
char opponent = round->opponent;
|
char opponent = round->opponent;
|
||||||
|
|
||||||
@ -82,7 +81,7 @@ static int day2_part2(void *p) {
|
|||||||
result += 6;
|
result += 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
printf("%d\n", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
ADD_SOLUTION(2, day2_parse, day2_part1, day2_part2);
|
ADD_SOLUTION(2, day2_parse, day2_part1, day2_part2);
|
||||||
|
94
day3.c
Normal file
94
day3.c
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#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
Normal file
78
day4.c
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#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
Normal file
165
day5.c
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
#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
Normal file
56
day6.c
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#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
Normal file
166
day7.c
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
#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
Normal file
119
day8.c
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#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
Normal file
213
day9.c
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
#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,6 +10,15 @@
|
|||||||
|
|
||||||
#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)
|
||||||
{
|
{
|
||||||
@ -154,8 +163,10 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
void* parsed = solution->parse(lines, line_count);
|
void* parsed = solution->parse(lines, line_count);
|
||||||
|
|
||||||
printf("part1: %d\n", solution->part1(parsed));
|
printf("part1:\n");
|
||||||
printf("part2: %d\n", solution->part2(parsed));
|
solution->part1(parsed);
|
||||||
|
printf("part2:\n");
|
||||||
|
solution->part2(parsed);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
8
point.h
Normal file
8
point.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef POINT_H_
|
||||||
|
#define POINT_H_
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int x, y;
|
||||||
|
} Point;
|
||||||
|
|
||||||
|
#endif //POINT_H_
|
44
vec.h
Normal file
44
vec.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#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