diff --git a/.gitignore b/.gitignore index e8c8b6f..8ce1ee0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ -day1 -day1_input -day1_test +*.txt +*.elf +blink.log +compile_commands.json diff --git a/Makefile b/Makefile index 5cbced4..50519a1 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,14 @@ -all: day1 +FILES = $(wildcard ./*) +SRCS = $(filter %.c,$(FILES)) +BINS = $(SRCS:%.c=%.elf) -%: %.c - gcc-tree -o $@ -Wall -Werror -pedantic -D_GNU_SOURCE -std=gnu2y -O3 -g $< +CFLAGS = -Wall -Werror -pedantic -D_GNU_SOURCE -std=gnu2y -O3 -g -Wno-unused\ + -nostartfiles -static -Ttext=C475000 + +all: $(BINS) + +%.elf: %.c + gcc-tree -o $@ $(CFLAGS) $< + +clean: + rm ./*.elf diff --git a/day1.c b/day1.c index 011eb41..fccb42c 100644 --- a/day1.c +++ b/day1.c @@ -1,23 +1,26 @@ -#include -#include -#include +#include "lib.h" +#define DBG 1 + +#define RUN_PART1 1 +#define RUN_PART2 1 +#define RUN_TEST1 1 +#define RUN_TEST2 1 + +#define TEST1_EXPECT 3 +#define TEST2_EXPECT 6 + +static char input[] = { -#embed "day1_input" +#embed "day1_input.txt" }; +static char test[] = { -#embed "day1_test" +#embed "day1_test.txt" }; -unsigned grabnum(const char *s, const char **end) { - unsigned r = 0; - for (; *s >= '0' && *s <= '9'; s++) - r = r * 10 + (*s - '0'); - *end = s; - return r; -} - +static unsigned long do_part1(size_t src_len, const char src[src_len]) { const char *s = src; unsigned long count = 0; @@ -36,6 +39,7 @@ unsigned long do_part1(size_t src_len, const char src[src_len]) { return count; } +static unsigned do_part2(size_t src_len, const char src[src_len]) { const char *s = src, *ns = s + 1; unsigned count = 0; @@ -70,24 +74,40 @@ unsigned do_part2(size_t src_len, const char src[src_len]) { return count; } -int main() { - printf("PART 1 TEST: "); - if (unsigned long v = do_part1(countof(test), test); v != 3) { - printf("FAILED (got %lu, expected 3)\n", v); +void _start() { +#if RUN_TEST1 + print("PART 1 TEST: "); + if (unsigned long v = do_part1(countof(test), test); v != TEST1_EXPECT) { + print("FAILED (got "); + printd(v); + print(", expected " xstr(TEST1_EXPECT) ")\n"); } else { - printf("PASSED\n"); + print("PASSED\n"); } +#endif - printf("PART 1 RESULT: %lu\n", - do_part1(countof(input), input)); +#if RUN_PART1 + print("PART 1 RESULT: "); + printd(do_part1(countof(input), input)); + print("\n"); +#endif - printf("PART 2 TEST: "); - if (unsigned v = do_part2(countof(test), test); v != 6) { - printf("FAILED (got %u, expected 6)\n", v); +#if RUN_TEST2 + print("PART 2 TEST: "); + if (unsigned v = do_part2(countof(test), test); v != TEST2_EXPECT) { + print("FAILED (got "); + printd(v); + print(", expected " xstr(TEST2_EXPECT) ")\n"); } else { - printf("PASSED\n"); + print("PASSED\n"); } +#endif - printf("PART 2 RESULT: %u\n", - do_part2(countof(input), input)); +#if RUN_PART2 + print("PART 2 RESULT: "); + printd(do_part2(countof(input), input)); + print("\n"); +#endif + + syscall(SYS_exit_group, 0); } diff --git a/day2.c b/day2.c new file mode 100644 index 0000000..81204eb --- /dev/null +++ b/day2.c @@ -0,0 +1,296 @@ +#include "lib.h" + +#define DBG 0 + +static +unsigned char input[] = { +#embed "day2_input.txt" +}; + +static +unsigned char test[] = { +#embed "day2_test.txt" +}; + + +struct id { + size_t len; + bcdint v; +}; + +static +struct id next_palindrome_part1(struct id s) { + if (s.len % 2 == 1) { + size_t len = s.len + 1; + unsigned high_shift = (len / 2) * 4; + + bcdint high = 1 << (high_shift - 4); + + return (struct id) { + .len = len, + .v = (high << high_shift) | high + }; + } + + unsigned high_shift = (s.len / 2) * 4; + bcdint low_mask = (1 << high_shift) - 1; + + bcdint high = s.v >> high_shift; + bcdint low = s.v & low_mask; + + if (low > high) + high = bcdadd(high, 1); + + return (struct id) { + .len = s.len, + .v = (high << high_shift) | high + }; +} + +static +bcdint do_part1(size_t file_len, unsigned char file[file_len]) { + unsigned char *src = file, *tmp; + bcdint result = 0; + +#if DBG + print("\n"); +#endif + +do { +#if DBG + print_watch_ptr(src); + print("\t"); + print(str(src) ":"); + for (size_t i = 0; i < 2; i++) { + print(" "); + print_hex_char(src[i]); + } + print("\n"); +#endif + + tmp = src; + bcdint rs = grabbcd(src, &src); + struct id first = { + .len = src - tmp, + .v = rs + }; + + src++; + + tmp = src; + bcdint re = grabbcd(src, &src); + + src++; + +#if DBG + printh(rs); + print(" to "); + printh(re); + print("\n"); +#endif + +struct id next = first; +do { + next = next_palindrome_part1(next); + if (next.v <= re) { + result = bcdadd(result, next.v); +#if DBG + print_watch_hex(next.v); + print("\t"); + print_watch_hex(next.len); + print("\t"); + print_watch_hex(result); + print("\n"); +#endif + } + bcdint tmp = bcdadd(next.v, 1); + for (bcdint chk = next.v; chk > 0; chk >>= 4) { + if ((chk & 0xF) != 9) goto no_len_change; + } + next.len++; +no_len_change: + next.v = tmp; +} while (next.v <= re); + +#if DBG + print("reached "); + printh(re); + print("\n"); +#endif + +} while (src != &file[file_len]); + + return result; +} + +static +struct id next_palindrome_part2(struct id s) { + bcdint best = -1; + + for (unsigned i = 2; i <= s.len; i++) { + if (s.len % i == 0) { + unsigned high_shift = (s.len / i) * 4; + + bcdint high = s.v >> (high_shift * (i - 1)); + + for (int j = i - 2; j >= 0; j--) { + bcdint low = (s.v >> (high_shift * (j))) & ((1 << high_shift) - 1); + + if (low < high) { + break; + } else if (low > high) { + high = bcdadd(high, 1); + break; + } + } + + bcdint next = 0; + for (unsigned j = 0; j < i; j++) { + next |= high << (high_shift * j); + } + + if (next < best) { + best = next; + } + } + } + + if (best != -1) { + return (struct id) { + .len = s.len, + .v = best + }; + } + + size_t len = s.len + 1; + unsigned high_shift = (len / 2) * 4; + + bcdint high = 1 << (high_shift - 4); + + return (struct id) { + .len = len, + .v = (high << high_shift) | high + }; +} + +static +bcdint do_part2(size_t file_len, unsigned char file[file_len]) { + unsigned char *src = file, *tmp; + bcdint result = 0; + +#if DBG + print("\n"); +#endif + +do { +#if DBG + print_watch_ptr(src); + print("\t"); + print(str(src) ":"); + for (size_t i = 0; i < 2; i++) { + print(" "); + print_hex_char(src[i]); + } + print("\n"); +#endif + + tmp = src; + bcdint rs = grabbcd(src, &src); + struct id first = { + .len = src - tmp, + .v = rs + }; + + src++; + + tmp = src; + bcdint re = grabbcd(src, &src); + + src++; + +#if DBG + printh(rs); + print(" to "); + printh(re); + print("\n"); +#endif + +struct id next = first; +do { + next = next_palindrome_part2(next); + if (next.v <= re) { + result = bcdadd(result, next.v); +#if DBG + print_watch_hex(next.v); + print("\t"); + print_watch_hex(next.len); + print("\t"); + print_watch_hex(result); + print("\n"); +#endif + } + bcdint tmp = bcdadd(next.v, 1); + for (bcdint chk = next.v; chk > 0; chk >>= 4) { + if ((chk & 0xF) != 9) goto no_len_change; + } + next.len++; +no_len_change: + next.v = tmp; +} while (next.v <= re); + +#if DBG + print("reached "); + printh(re); + print("\n"); +#endif + +} while (src != &file[file_len]); + + return result; +} + +#define RUN_TEST1 1 +#define RUN_PART1 1 +#define RUN_TEST2 1 +#define RUN_PART2 1 + +#define TEST1_EXPECT 0x1227775554l +#define TEST2_EXPECT 0x4174379265l + +void _start() { +#if RUN_TEST1 + print("PART 1 TEST: "); + if (bcdint v = do_part1(countof(test), test); v != TEST1_EXPECT) { + print("FAILED (got "); + printh(v); + print(", expected " xstr(TEST1_EXPECT) ")\n"); + } else { + print("PASSED\n"); + } +#endif + +#if RUN_PART1 + print("PART 1 RESULT: "); + printh(do_part1(countof(input), input)); + print("\n"); +#endif + +#if RUN_TEST2 + print("PART 2 TEST: "); + if (bcdint v = do_part2(countof(test), test); v != TEST2_EXPECT) { + print("FAILED (got "); + printh(v); + print(", expected " xstr(TEST2_EXPECT) ")\n"); + } else { + print("PASSED\n"); + } +#endif + +#if RUN_PART2 + print("PART 2 RESULT: "); + printh(do_part2(countof(input), input)); + print("\n"); +#endif + + syscall(SYS_exit_group, 0); +} diff --git a/lib.h b/lib.h new file mode 100644 index 0000000..c15d826 --- /dev/null +++ b/lib.h @@ -0,0 +1,147 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +#define xstr(s) str(s) +#define str(s) #s + +typedef uint64_t bcdint; + +static +void printns(size_t len, unsigned char chars[len]) { + syscall(SYS_write, STDOUT_FILENO, chars, len); +} + +static +void printptr(uintptr_t v) { + char buf[sizeof(uintptr_t)*2] = { }; + char *p = buf+countof(buf); + for (size_t i = 0; i < countof(buf); i++) { + p--; + if ((v & 0x0F) < 0xA) { + *p = '0' + (v & 0x0F); + } else { + *p = 'A' - 0xA + (v & 0x0F); + } + v >>= 4; + } + syscall(SYS_write, STDOUT_FILENO, p, countof(buf)); +} + +static +void print_many_char(size_t len, char chars[len]) { + syscall(SYS_write, STDOUT_FILENO, chars, len); +} + +#define print(string) print_many_char(sizeof(string)-1, string) + +static +void printd(unsigned long v) { + if (!v) { + print("0"); + return; + } + char buf[32]; + char *p = buf+32; + unsigned count = 0; + while (v) { + p--; + *p = '0' + (v % 10); + v /= 10; + count++; + } + syscall(SYS_write, STDOUT_FILENO, p, count); +} + +static +void printh(unsigned long v) { + if (!v) { + print("0"); + return; + } + char buf[32]; + char *p = buf+32; + unsigned count = 0; + while (v) { + p--; + if ((v & 0x0F) < 0xA) { + *p = '0' + (v & 0x0F); + } else { + *p = 'A' - 0xA + (v & 0x0F); + } + v >>= 4; + count++; + } + syscall(SYS_write, STDOUT_FILENO, p, count); +} + +static +void print_hex_char(unsigned char v) { + char buf[2]; + + if ((v >> 4) < 0x0A) { + buf[0] = '0' + (v >> 4); + } else { + buf[0] = 'A' - 0xA + (v >> 4); + } + + if ((v & 0x0F) < 0xA) { + buf[1] = '0' + (v & 0x0F); + } else { + buf[1] = 'A' - 0xA + (v & 0x0F); + } + + syscall(SYS_write, STDOUT_FILENO, buf, sizeof(buf)); +} + +static +void print_pre_hex(size_t len, unsigned char prefix[len], unsigned long v) { + printns(len, prefix); + printh(v); +} + +static +void print_pre_ptr(size_t len, unsigned char prefix[len], void *ptr) { + printns(len, prefix); + printptr((uintptr_t)ptr); +} + +#define print_watch_ptr(expr) print_pre_ptr(\ + sizeof(#expr ": ")-1, (unsigned char*)(#expr ": "), expr) +#define print_watch_hex(expr) print_pre_hex(\ + sizeof(#expr ": ")-1, (unsigned char*)(#expr ": "), expr) + +static +bcdint grabbcd(unsigned char *s, unsigned char **end) { + bcdint r = 0; + for (; *s >= '0' && *s <= '9'; s++) + r = (r << 4) + (*s - '0'); + if (end) *end = s; + return r; +} + +static +unsigned grabnum(const char *s, const char **end) { + unsigned r = 0; + for (; *s >= '0' && *s <= '9'; s++) + r = r * 10 + (*s - '0'); + *end = s; + return r; +} + +// from wikipedia, the free encyclopedia +// https://en.wikipedia.org/wiki/Binary-coded_decimal +static bcdint bcdadd(bcdint a, bcdint b) { + bcdint t1, t2; + t1 = a + 0x0666666666666666; + t2 = t1 ^ b; + t1 = t1 + b; + t2 = t1 ^ t2; + t2 = ~t2 & 0x1111111111111110; + t2 = (t2 >> 2) | (t2 >> 3); + return t1 - t2; +}