diff --git a/Makefile b/Makefile index 96b4694..c0ab356 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ include dreamcast/headers.mk MAKEFILE_PATH := $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST))))) CFLAGS += -I$(MAKEFILE_PATH) CFLAGS += -I$(MAKEFILE_PATH)/dreamcast/ +CFLAGS += -Wno-char-subscripts LIB ?= $(MAKEFILE_PATH)/dreamcast include aoc.mk diff --git a/aoc.mk b/aoc.mk index f24a604..b463689 100644 --- a/aoc.mk +++ b/aoc.mk @@ -3,7 +3,9 @@ OBJ = \ heapsort.o \ printf.o \ runner.o \ - unparse.o + unparse.o \ + cartesian.o \ + array.o DREAMCAST_OBJ = \ runner_dreamcast.o \ diff --git a/array.c b/array.c new file mode 100644 index 0000000..89d8484 --- /dev/null +++ b/array.c @@ -0,0 +1,19 @@ +#include "array.h" + +int array_sum_char(char * a, int length) +{ + int sum = 0; + for (int i = 0; i < length; i++) { + sum += a[i]; + } + return sum; +} + +int array_sum_int(int * a, int length) +{ + int sum = 0; + for (int i = 0; i < length; i++) { + sum += a[i]; + } + return sum; +} diff --git a/array.h b/array.h new file mode 100644 index 0000000..5e582b5 --- /dev/null +++ b/array.h @@ -0,0 +1,12 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +int array_sum_char(char * a, int length); +int array_sum_int(int * a, int length); + +#ifdef __cplusplus +} +#endif diff --git a/cartesian.c b/cartesian.c new file mode 100644 index 0000000..e1cba1b --- /dev/null +++ b/cartesian.c @@ -0,0 +1,13 @@ +#include + +#include "cartesian.h" + +bool cartesian_inside(int width, int height, + int x, int y) +{ + return + x >= 0 && + y >= 0 && + x < width && + y < height ; +} diff --git a/cartesian.h b/cartesian.h new file mode 100644 index 0000000..56a331e --- /dev/null +++ b/cartesian.h @@ -0,0 +1,12 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +bool cartesian_inside(int width, int height, + int x, int y); + +#ifdef __cplusplus +} +#endif diff --git a/day4/solution.c b/day4/solution.c index 1d5724b..6476089 100644 --- a/day4/solution.c +++ b/day4/solution.c @@ -3,6 +3,7 @@ #include "printf.h" #include "parse.h" +#include "cartesian.h" enum offset_type { N, @@ -26,18 +27,6 @@ static char offsets[][2] = { [SE] = { 1, 1}, }; -static bool xy_inside(int width, int height, - int x, int y) -{ - if (y < 0 || x < 0) - return false; - if (x >= width) - return false; - if (y >= height) - return false; - return true; -} - static char get_char(const char * input, int stride, int x, int y) @@ -55,7 +44,7 @@ static bool offset_match(const char * input, int str_length) { for (int i = 0; i < str_length; i++) { - if (!xy_inside(width, height, x, y)) + if (!cartesian_inside(width, height, x, y)) return false; char c = get_char(input, stride, x, y); diff --git a/day6/solution.c b/day6/solution.c index 4891821..9b48a35 100644 --- a/day6/solution.c +++ b/day6/solution.c @@ -4,6 +4,7 @@ #include "printf.h" #include "parse.h" +#include "cartesian.h" #include "solution.h" @@ -26,22 +27,12 @@ static struct position find_guard(const char * input, int length, return (struct position){x, y}; } -static bool position_inside_map(int width, int height, - int x, int y) -{ - return - x >= 0 && - y >= 0 && - x < width && - y < height ; -} - static bool position_contains_obstacle(const char * input, int stride, int width, int height, int x, int y) { - if (!position_inside_map(width, height, x, y)) + if (!cartesian_inside(width, height, x, y)) return false; char c = input[y * stride + x]; @@ -151,8 +142,8 @@ int64_t day6_part1(const char * input, int length) day6_state.step = false; */ - bool guard_inside_map = position_inside_map(width, height, - guard.position.x, guard.position.y); + bool guard_inside_map = cartesian_inside(width, height, + guard.position.x, guard.position.y); if (!guard_inside_map) break; @@ -183,8 +174,8 @@ static bool speculative_obstacle_causes_loop(const char * input, guard.position = origin; while (true) { - bool guard_inside_map = position_inside_map(width, height, - guard.position.x, guard.position.y); + bool guard_inside_map = cartesian_inside(width, height, + guard.position.x, guard.position.y); if (!guard_inside_map) break; @@ -227,8 +218,8 @@ int64_t day6_part2(const char * input, int length) for (int i = 0; i < width * height; i++) loops[i] = 0; while (true) { - bool guard_inside_map = position_inside_map(width, height, - guard.position.x, guard.position.y); + bool guard_inside_map = cartesian_inside(width, height, + guard.position.x, guard.position.y); if (!guard_inside_map) break; diff --git a/day8/input.txt b/day8/input.txt new file mode 100644 index 0000000..69c52ac --- /dev/null +++ b/day8/input.txt @@ -0,0 +1,50 @@ +.....8............1r.....a....................O... +.a..............4..q.........................0...9 +....a.........8................................... +.................D.....................V0......... +.....d............................................ +.r..........q....................................O +..................q...........................9... +..............D..............X..................V. +........D................X.................0...... +.........8............X........................... +....................J....................9..0..... +..a..B............r..W........J...............R..Q +......WD...q.....1..........Q..............R..V... +.1W...................u........................... +..............................u.............R..... +....B..............d..c..................R........ +.............J..............X............V........ +......1...........................3............... +......B...........d...................3........... +............8..J.......u.....3.................... +...........4.............6........................ +.....4v.............d.......................O..... +..........................v.2..................... +.............................................s.... +..................4...M..W..................s..... +......................m........................... +...........M...................................... +..b..................c............................ +....................Co..........KQ.......O.s...... +.................C............................s... +.......x............c............................3 +........o......A....U.....Q.........5............. +...............U..................j...5........... +.....K.......U................j..........2........ +.......A.v.....w.....................c...5........ +..K....................................j.......... +...............K.yk....B.............2............ +......C....b..............x...........Y........... +.....mA..C......U................................. +........M.....A.....................2..6...5...... +.............................7.......Y............ +.m.M......w..v.................................... +............m...........x.....Y................... +....................k....w........................ +......b.....w..S....7............................. +..............S..............x...........Y........ +....................S...6......................... +.y...............S..........7.6.................9. +o..........k...............b...................... +yo...........k.................................... diff --git a/day8/input.txt.h b/day8/input.txt.h new file mode 100644 index 0000000..98b3052 --- /dev/null +++ b/day8/input.txt.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_day8_input_txt_start __asm("_binary_day8_input_txt_start"); +extern uint32_t _binary_day8_input_txt_end __asm("_binary_day8_input_txt_end"); +extern uint32_t _binary_day8_input_txt_size __asm("_binary_day8_input_txt_size"); + +#ifdef __cplusplus +} +#endif diff --git a/day8/sample1.txt b/day8/sample1.txt new file mode 100644 index 0000000..78a1e91 --- /dev/null +++ b/day8/sample1.txt @@ -0,0 +1,12 @@ +............ +........0... +.....0...... +.......0.... +....0....... +......A..... +............ +............ +........A... +.........A.. +............ +............ diff --git a/day8/sample1.txt.h b/day8/sample1.txt.h new file mode 100644 index 0000000..6fef83f --- /dev/null +++ b/day8/sample1.txt.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_day8_sample1_txt_start __asm("_binary_day8_sample1_txt_start"); +extern uint32_t _binary_day8_sample1_txt_end __asm("_binary_day8_sample1_txt_end"); +extern uint32_t _binary_day8_sample1_txt_size __asm("_binary_day8_sample1_txt_size"); + +#ifdef __cplusplus +} +#endif diff --git a/day8/solution.c b/day8/solution.c new file mode 100644 index 0000000..77dbb06 --- /dev/null +++ b/day8/solution.c @@ -0,0 +1,158 @@ +#include + +#include "parse.h" +#include "printf.h" +#include "cartesian.h" +#include "array.h" + +struct position { + char x; + char y; +}; + +struct antenna { + struct position position[8]; + char count; +}; + +#define FIRST_ANTENNA '0' +#define LAST_ANTENNA 'z' +#define ANTENNA_TYPES ((LAST_ANTENNA - FIRST_ANTENNA) + 1) + +void parse_antennas(const char * input, int length, struct antenna * antennas) +{ + int x = 0; + int y = 0; + for (int i = 0; i < length; i++) { + char c = input[i]; + if (c >= FIRST_ANTENNA && c <= LAST_ANTENNA) { + struct antenna * ant = &antennas[c - FIRST_ANTENNA]; + ant->position[ant->count++] = (struct position){x, y}; + } + if (c == '\n') { + x = 0; + y += 1; + } else { + x += 1; + } + } +} + +struct position vector(struct position a, struct position b) +{ + return (struct position){b.x - a.x, b.y - a.y}; +} + +void part1_antinodes(int width, int height, + struct position p1, struct position p2, + char * antinodes) +{ + struct position slope = vector(p1, p2); + + struct position a[2] = { + { + p1.x - slope.x, + p1.y - slope.y, + }, + { + p2.x + slope.x, + p2.y + slope.y, + } + }; + + for (int k = 0; k < 2; k++) { + if (cartesian_inside(width, height, a[k].x, a[k].y)) { + antinodes[a[k].y * width + a[k].x] = 1; + } + } +} + +void interpolate_antinodes(int width, + int height, + struct position ant, + struct position slope, + char * antinodes) +{ + int x = ant.x; + int y = ant.y; + while (true) { + if (!cartesian_inside(width, height, x, y)) + break; + + antinodes[y * width + x] = 1; + + x -= slope.x; + y -= slope.y; + } +} + +void part2_antinodes(int width, int height, + struct position p1, struct position p2, + char * antinodes) +{ + struct position slope = vector(p1, p2); + + interpolate_antinodes(width, height, p1, (struct position){-slope.x, -slope.y}, antinodes); + interpolate_antinodes(width, height, p2, (struct position){ slope.x, slope.y}, antinodes); +} + +typedef void (* part_solver)(int width, int height, + struct position p1, struct position p2, + char * antinodes); + +void find_antinodes(int width, int height, + const struct antenna * antennas, + char * antinodes, + part_solver func) +{ + for (int t = FIRST_ANTENNA; t <= LAST_ANTENNA; t++) { + const struct antenna * ant = &antennas[t - FIRST_ANTENNA]; + for (int i = 0; i < ant->count; i++) { + for (int j = i + 1; j < ant->count; j++) { + func(width, height, + ant->position[i], ant->position[j], + antinodes); + } + } + } +} + +int64_t day8_part1(const char * input, int length) +{ + int stride = parse_stride(input, length); + int height = parse_height(input, length); + int width = stride - 1; + + struct antenna antennas[ANTENNA_TYPES]; + for (int i = 0; i < ANTENNA_TYPES; i++) + antennas[i].count = 0; + char antinodes[width * height]; + for (int i = 0; i < width * height; i++) + antinodes[i] = 0; + + parse_antennas(input, length, antennas); + + find_antinodes(width, height, antennas, antinodes, part1_antinodes); + + return array_sum_char(antinodes, width * height); +} + +int64_t day8_part2(const char * input, int length) +{ + int stride = parse_stride(input, length); + int height = parse_height(input, length); + int width = stride - 1; + + struct antenna antennas[ANTENNA_TYPES]; + for (int i = 0; i < ANTENNA_TYPES; i++) + antennas[i].count = 0; + char antinodes[width * height]; + for (int i = 0; i < width * height; i++) + antinodes[i] = 0; + + parse_antennas(input, length, antennas); + + find_antinodes(width, height, antennas, antinodes, part2_antinodes); + + return array_sum_char(antinodes, width * height); +} diff --git a/gen.sh b/gen.sh index 72012df..ae4f9c9 100755 --- a/gen.sh +++ b/gen.sh @@ -15,12 +15,12 @@ if [ ! -z "$day" ]; then cat < day${day}/solution.c #include -int day${day}_part1(const char * input, int length) +int64_t day${day}_part1(const char * input, int length) { return -1; } -int day${day}_part2(const char * input, int length) +int64_t day${day}_part2(const char * input, int length) { return -1; } diff --git a/input_dreamcast.inc b/input_dreamcast.inc index 294768c..5f04779 100644 --- a/input_dreamcast.inc +++ b/input_dreamcast.inc @@ -13,6 +13,8 @@ #include "day6/input.txt.h" #include "day7/sample1.txt.h" #include "day7/input.txt.h" +#include "day8/sample1.txt.h" +#include "day8/input.txt.h" static struct start_size sample[][2] = { { @@ -57,6 +59,12 @@ static struct start_size sample[][2] = { { ( char *)&_binary_day7_sample1_txt_start, (uint32_t)&_binary_day7_sample1_txt_size }, }, + { + { ( char *)&_binary_day8_sample1_txt_start, + (uint32_t)&_binary_day8_sample1_txt_size }, + { ( char *)&_binary_day8_sample1_txt_start, + (uint32_t)&_binary_day8_sample1_txt_size }, + }, }; static struct start_size input[] = { @@ -74,4 +82,6 @@ static struct start_size input[] = { (uint32_t)&_binary_day6_input_txt_size }, { ( char *)&_binary_day7_input_txt_start, (uint32_t)&_binary_day7_input_txt_size }, + { ( char *)&_binary_day8_input_txt_start, + (uint32_t)&_binary_day8_input_txt_size }, }; diff --git a/printf.c b/printf.c index 2f51539..f5d589b 100644 --- a/printf.c +++ b/printf.c @@ -11,6 +11,7 @@ enum format_type { FORMAT_BASE10_64, FORMAT_BASE16, FORMAT_STRING, + FORMAT_CHAR, FORMAT_PERCENT, }; @@ -48,6 +49,9 @@ static const char * parse_escape(const char * format, struct format * ft) case 's': ft->type = FORMAT_STRING; return format + 1; + case 'c': + ft->type = FORMAT_CHAR; + return format + 1; case '%': ft->type = FORMAT_PERCENT; return format + 1; @@ -105,6 +109,12 @@ void _printf(const char * format, ...) } } break; + case FORMAT_CHAR: + { + const int c = va_arg(args, const int); + global_output_buffer.buf[global_output_buffer.buf_ix++] = (char)c; + } + break; case FORMAT_PERCENT: global_output_buffer.buf[global_output_buffer.buf_ix++] = '%'; break; diff --git a/printf.h b/printf.h index 7bf8196..8a41492 100644 --- a/printf.h +++ b/printf.h @@ -10,6 +10,8 @@ void _printf(const char * format, ...); #define printf(...) _printf(__VA_ARGS__) #endif +void print_char(char c); + struct output_buffer { int buf_ix; char buf[16 * 1024]; diff --git a/runner.c b/runner.c index e81c807..f41c6a5 100644 --- a/runner.c +++ b/runner.c @@ -18,17 +18,20 @@ struct day_funcs { #include "runner.inc" const int solution_days = (sizeof (solution)) / (sizeof (solution[0])); +const int solution_ticks = solution_days * 2; bool runner_tick(struct runner_state * runner_state) { - int part = runner_state->tick % 2; - int day = runner_state->tick / 2; + int tick = (solution_ticks - 1) - runner_state->tick; - if (day >= solution_days) { + if (tick < 0) { runner_state->want_render = false; return true; } + int part = tick % 2; + int day = tick / 2; + runner_state->want_render = solution[day].render != NULL; char * buf; diff --git a/runner.inc b/runner.inc index 5968df7..447f295 100644 --- a/runner.inc +++ b/runner.inc @@ -15,6 +15,8 @@ void day6_render(const struct font * font, const void * maple_ft0_data); int64_t day7_part1(const char * input, int length); int64_t day7_part2(const char * input, int length); +int64_t day8_part1(const char * input, int length); +int64_t day8_part2(const char * input, int length); struct day_funcs solution[] = { { @@ -45,4 +47,8 @@ struct day_funcs solution[] = { {day7_part1, day7_part2}, NULL, }, + { + {day8_part1, day8_part2}, + NULL, + }, }; diff --git a/runner_dreamcast.cpp b/runner_dreamcast.cpp index 86852d9..e58877c 100644 --- a/runner_dreamcast.cpp +++ b/runner_dreamcast.cpp @@ -444,3 +444,11 @@ int main() serial::string("return\n"); } + + +extern "C" +void print_char(char c) +{ + global_output_buffer.buf[global_output_buffer.buf_ix++] = c; + serial::character(c); +} diff --git a/solutions.mk b/solutions.mk index 6023483..9c2bf15 100644 --- a/solutions.mk +++ b/solutions.mk @@ -21,4 +21,7 @@ DAY_OBJ = \ day6/solution.o \ day7/sample1.txt.o \ day7/input.txt.o \ - day7/solution.o + day7/solution.o \ + day8/sample1.txt.o \ + day8/input.txt.o \ + day8/solution.o