day 2
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
day1
|
||||
day1_input
|
||||
day1_test
|
||||
*.txt
|
||||
*.elf
|
||||
blink.log
|
||||
compile_commands.json
|
||||
|
||||
16
Makefile
16
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
|
||||
|
||||
72
day1.c
72
day1.c
@@ -1,23 +1,26 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdcountof.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
296
day2.c
Normal file
296
day2.c
Normal file
@@ -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);
|
||||
}
|
||||
147
lib.h
Normal file
147
lib.h
Normal file
@@ -0,0 +1,147 @@
|
||||
#pragma once
|
||||
#include <stdlib.h>
|
||||
#include <stdcountof.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user