commit 139a518977b7ab8394301ba008b29626bd3c06cd
parent 748af4eff54eaf7ac72479c7257d72b04f581153
Author: amin <dev@aminmesbah.com>
Date: Wed, 21 Dec 2022 07:14:27 +0000
Solve 2022 day 1
FossilOrigin-Name: cfdb7e3e2d50cdead9b7106334accf0a860fed26a04e44e047c6e8da6c5f80cd
Diffstat:
A | 2022/am_base.h | | | 118 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | 2022/am_list.h | | | 233 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | 2022/am_memory.h | | | 185 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | 2022/am_string.h | | | 381 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | 2022/day01.c | | | 103 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | 2022/day01_input.txt | | | 2269 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
6 files changed, 3289 insertions(+), 0 deletions(-)
diff --git a/2022/am_base.h b/2022/am_base.h
@@ -0,0 +1,118 @@
+#ifndef AM_BASE_H
+#define AM_BASE_H
+
+#if __STDC_VERSION__ < 201112L
+# error "C11 or greater required."
+#endif
+
+// context
+// https://sourceforge.net/p/predef/wiki/Home/
+#if defined(__clang__)
+# define COMPILER_CLANG 1
+#elif defined (__GNUC__)
+# define COMPILER_GCC 1
+#else
+# error "Unsupported compiler."
+#endif
+
+#if !defined(COMPILER_CLANG)
+# define COMPILER_CLANG 0
+#endif
+#if !defined(COMPILER_GCC)
+# define COMPILER_GCC 0
+#endif
+
+#if defined (__linux__)
+# define OPERATING_SYSTEM_LINUX 1
+#elif defined(_WIN32)
+# define OPERATING_SYSTEM_WINDOWS 1
+#else
+# error "Unsupported OS."
+#endif
+
+#if !defined(OPERATING_SYSTEM_LINUX)
+# define OPERATING_SYSTEM_LINUX 0
+#endif
+#if !defined(OPERATING_SYSTEM_WINDOWS)
+# define OPERATING_SYSTEM_WINDOWS 0
+#endif
+
+// compiler builtins
+#if COMPILER_CLANG || COMPILER_GCC
+# ifndef __has_builtin
+# define __has_builtin(x) 0
+# endif
+#endif
+
+#define IMPLEMENTATION_UNSIGNED_CHAR (CHAR_MIN == 0)
+
+// freestanding headers
+#include <float.h>
+#include <limits.h>
+#include <stdalign.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdnoreturn.h>
+
+// preprocessor improvement
+#define AM__STRINGIFY(S) #S
+#define AM__GLUE(A, B) A##B
+#define AM_STRINGIFY(S) AM__STRINGIFY(S)
+#define AM_GLUE(A, B) AM__GLUE((A), (B))
+
+// assert
+#define static_assert(expr) _Static_assert((expr), "")
+
+#if !defined(AM_ENABLE_ASSERT)
+# define AM_ENABLE_ASSERT 0
+#endif
+
+#if AM_ENABLE_ASSERT
+# if !defined(AM_ASSERT_FAIL)
+# if __has_builtin(__builtin_trap)
+# define AM_ASSERT_FAIL(expr, file, line, func) __builtin_trap()
+# else
+# error "Must define implementation of AM_ASSERT_FAIL(expr, file, line, func)."
+# endif
+# endif
+# define assert(x) ((void)((x) || (AM_ASSERT_FAIL(AM_STRINGIFY(x), __FILE__, __LINE__, __func__),0)))
+#else
+# define assert(c) ((void)0)
+#endif
+
+#define AM_UNREACHABLE assert(false && "Unreachable code reached")
+
+// utility macros
+#define ALIGN_UP_POW_2(x, p) (((x) + (p) - 1) & ~((p) - (1)))
+#define ALIGN_DOWN_POW_2(x, p) ((x) & ~((p) - 1))
+#define ARRAY_COUNT(a) (sizeof(a)/sizeof(*(a)))
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define CLAMP(a, x, b) (((x) < (a)) ? (a) : (((b) < (x)) ? (b) : (x)))
+#define CLAMP_TOP(a, b) MIN((a), (b))
+#define CLAMP_BOT(a, b) MAX((a), (b))
+#define UNUSED(p) (void)(p)
+
+// basic types
+typedef int8_t s8;
+typedef int16_t s16;
+typedef int32_t s32;
+typedef int64_t s64;
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+typedef size_t usz;
+typedef float f32;
+typedef double f64;
+
+#define global static
+#define local_persist static
+#define internal static
+
+// sanity checks
+static_assert(CHAR_BIT == 8);
+
+#endif // AM_BASE_H
diff --git a/2022/am_list.h b/2022/am_list.h
@@ -0,0 +1,233 @@
+#ifndef AM_LIST_H
+#define AM_LIST_H
+
+#define DLL_APPEND_NP(f, l, n, next, prev) \
+ ((f) == NULL \
+ ? ((f) = (l) = (n) \
+ , (f)->prev = (n)->next = NULL) \
+ : ((n)->prev = (l) \
+ , (l)->next = (n) \
+ , (l) = (n) \
+ , (n)->next = NULL))
+
+#define DLL_REMOVE_NP(f, l, n, next, prev) \
+ ((f) == (l) && (f) == (n) \
+ ? ((f) = (l) = NULL) \
+ : ((f) == (n) \
+ ? ((f) = (f)->next \
+ , (f)->prev = NULL) \
+ : ((l) == (n) \
+ ? ((l) = (l)->prev \
+ , (l)->next = NULL) \
+ : ((n)->prev->next = (n)->next \
+ , (n)->next->prev = (n)->prev))))
+
+#define SLL_QUEUE_PUSH_N(f, l, n, next) \
+ ((f) == NULL \
+ ? ((f) = (l) = (n)) \
+ : ((l)->next = (n) \
+ , (l) = (n) \
+ , (n)->next = NULL))
+
+#define SLL_QUEUE_PUSH_FRONT_N(f, l, n, next) \
+ ((f) == NULL \
+ ? ((f) = (l) = (n) \
+ , (n)->next = NULL) \
+ : ((n)->next = (f) \
+ , (f) = (n)))
+
+// TODO: It's maybe somewhat surprising to the user that these pop functions
+// don't return the popped node.
+#define SLL_QUEUE_POP_N(f, l, next) \
+ ((f) == (l) \
+ ? ((f) = (l) = NULL) \
+ : ((f) = (f)->next))
+
+
+#define SLL_STACK_PUSH_N(f, n, next) ((n)->next = (f), (f) = (n))
+
+#define SLL_STACK_POP_N(f, next) \
+ ((f) == NULL \
+ ? 0 \
+ : ((f) = (f)->next))
+
+#define DLL_APPEND(f, l, n) DLL_APPEND_NP((f), (l), (n), next, prev)
+#define DLL_PREPEND(f, l, n) DLL_APPEND_NP((l), (f), (n), prev, next)
+#define DLL_REMOVE(f, l, n) DLL_REMOVE_NP((f), (l), (n), next, prev)
+
+#define SLL_QUEUE_PUSH(f, l, n) SLL_QUEUE_PUSH_N((f), (l), (n), next)
+#define SLL_QUEUE_PUSH_FRONT(f, l, n) SLL_QUEUE_PUSH_FRONT_N((f), (l), (n), next)
+#define SLL_QUEUE_POP(f, l) SLL_QUEUE_POP_N((f), (l), next)
+
+#define SLL_STACK_PUSH(f, n) SLL_STACK_PUSH_N((f), (n), next)
+#define SLL_STACK_POP(f) SLL_STACK_POP_N((f), next)
+
+#ifdef AM_LIST_TESTS
+typedef struct TestNode TestNode;
+struct TestNode {
+ TestNode *next;
+ TestNode *prev;
+ s32 val;
+};
+
+internal void am_list_test(void) {
+ TestNode nodes[10] = {0};
+ for (size_t i = 0; i < ARRAY_COUNT(nodes); i++) {
+ nodes[i].val = i;
+ }
+
+ {
+ TestNode *first = NULL;
+ TestNode *last = NULL;
+
+ printf("dll append and remove from front\n");
+ for (size_t i = 0; i < ARRAY_COUNT(nodes); i++) {
+ DLL_APPEND(first, last, &nodes[i]);
+ printf("[");
+ for (TestNode *n = first; n; n = n->next) {
+ printf(" %i ", n->val);
+ }
+ printf(" <|> ");
+ for (TestNode *n = last; n; n = n->prev) {
+ printf(" %i ", n->val);
+ }
+ printf("]\n");
+ }
+
+ for (size_t i = 0; i < ARRAY_COUNT(nodes); i++) {
+ DLL_REMOVE(first, last, &nodes[i]);
+ printf("[");
+ for (TestNode *n = first; n; n = n->next) {
+ printf(" %i ", n->val);
+ }
+ printf(" <|> ");
+ for (TestNode *n = last; n; n = n->prev) {
+ printf(" %i ", n->val);
+ }
+ printf("]\n");
+ }
+
+ printf("dll prepend and remove from back\n");
+ for (size_t i = 0; i < ARRAY_COUNT(nodes); i++) {
+ DLL_PREPEND(first, last, &nodes[i]);
+ printf("[");
+ for (TestNode *n = first; n; n = n->next) {
+ printf(" %i ", n->val);
+ }
+ printf(" <|> ");
+ for (TestNode *n = last; n; n = n->prev) {
+ printf(" %i ", n->val);
+ }
+ printf("]\n");
+ }
+
+ for (size_t i = 0; i < ARRAY_COUNT(nodes); i++) {
+ DLL_REMOVE(first, last, &nodes[i]);
+ printf("[");
+ for (TestNode *n = first; n; n = n->next) {
+ printf(" %i ", n->val);
+ }
+ printf(" <|> ");
+ for (TestNode *n = last; n; n = n->prev) {
+ printf(" %i ", n->val);
+ }
+ printf("]\n");
+ }
+
+ printf("dll append and remove from middle\n");
+ for (size_t i = 0; i < ARRAY_COUNT(nodes); i++) {
+ DLL_APPEND(first, last, &nodes[i]);
+ printf("[");
+ for (TestNode *n = first; n; n = n->next) {
+ printf(" %i ", n->val);
+ }
+ printf(" <|> ");
+ for (TestNode *n = last; n; n = n->prev) {
+ printf(" %i ", n->val);
+ }
+ printf("]\n");
+ }
+
+ for (size_t i = 0; i < ARRAY_COUNT(nodes); i++) {
+ DLL_REMOVE(first, last, &nodes[(i + (ARRAY_COUNT(nodes) / 2)) % ARRAY_COUNT(nodes)]);
+ printf("[");
+ for (TestNode *n = first; n; n = n->next) {
+ printf(" %i ", n->val);
+ }
+ printf(" <|> ");
+ for (TestNode *n = last; n; n = n->prev) {
+ printf(" %i ", n->val);
+ }
+ printf("]\n");
+ }
+ }
+
+ {
+ TestNode *first = NULL;
+ TestNode *last = NULL;
+
+ printf("sll queue push and pop\n");
+ for (size_t i = 0; i < ARRAY_COUNT(nodes); i++) {
+ SLL_QUEUE_PUSH(first, last, &nodes[i]);
+ printf("[");
+ for (TestNode *n = first; n; n = n->next) {
+ printf(" %i ", n->val);
+ }
+ printf("]\n");
+ }
+
+ while (first) {
+ SLL_QUEUE_POP(first, last);
+ printf("[");
+ for (TestNode *n = first; n; n = n->next) {
+ printf(" %i ", n->val);
+ }
+ printf("]\n");
+ }
+
+ printf("sll queue push front and pop\n");
+ for (size_t i = 0; i < ARRAY_COUNT(nodes); i++) {
+ SLL_QUEUE_PUSH_FRONT(first, last, &nodes[i]);
+ printf("[");
+ for (TestNode *n = first; n; n = n->next) {
+ printf(" %i ", n->val);
+ }
+ printf("]\n");
+ }
+
+ while (first) {
+ SLL_QUEUE_POP(first, last);
+ printf("[");
+ for (TestNode *n = first; n; n = n->next) {
+ printf(" %i ", n->val);
+ }
+ printf("]\n");
+ }
+ }
+
+ {
+ TestNode *first = NULL;
+
+ printf("sll stack push and pop\n");
+ for (size_t i = 0; i < ARRAY_COUNT(nodes); i++) {
+ SLL_STACK_PUSH(first, &nodes[i]);
+ printf("[");
+ for (TestNode *n = first; n; n = n->next) {
+ printf(" %i ", n->val);
+ }
+ printf("]\n");
+ }
+
+ while (first) {
+ SLL_STACK_POP(first);
+ printf("[");
+ for (TestNode *n = first; n; n = n->next) {
+ printf(" %i ", n->val);
+ }
+ printf("]\n");
+ }
+ }
+}
+#endif // AM_LIST_TESTS
+
+#endif // AM_LIST_H
diff --git a/2022/am_memory.h b/2022/am_memory.h
@@ -0,0 +1,185 @@
+#ifndef AM_MEMORY_H
+#define AM_MEMORY_H
+
+#define MEM_KIB(b) ((u64)(b) << 10)
+#define MEM_MIB(b) ((u64)(b) << 20)
+#define MEM_GIB(b) ((u64)(b) << 30)
+
+#define AM_MEM_RESERVE_FN(name) void *(name)(void *ctx, u64 size)
+typedef AM_MEM_RESERVE_FN(am_mem_reserve_fn);
+
+#define AM_MEM_CHANGE_FN(name) void (name)(void *ctx, void *ptr, u64 size)
+typedef AM_MEM_CHANGE_FN(am_mem_change_fn);
+
+typedef struct {
+ am_mem_reserve_fn* reserve;
+ am_mem_change_fn* commit;
+ am_mem_change_fn* decommit;
+ am_mem_change_fn* release;
+ void *ctx;
+} BaseAllocator;
+
+#define AM_MEM_ARENA_COMMIT_BLOCK_SIZE MEM_MIB(64)
+#define AM_MEM_ARENA_DEFAULT_RESERVE_SIZE MEM_GIB(1)
+
+typedef struct {
+ BaseAllocator *base;
+ u8 *mem;
+ u64 cap;
+ u64 pos;
+ u64 commit_pos;
+} MemArena;
+
+internal AM_MEM_CHANGE_FN(am_mem_change_noop) {
+ UNUSED(ctx);
+ UNUSED(ptr);
+ UNUSED(size);
+}
+
+internal AM_MEM_RESERVE_FN(am_mem_reserve_malloc) {
+ UNUSED(ctx);
+ return malloc(size);
+}
+
+internal AM_MEM_CHANGE_FN(am_mem_release_malloc) {
+ UNUSED(ctx);
+ UNUSED(size);
+ free(ptr);
+}
+
+internal BaseAllocator *am_mem_base_allocator_malloc(void) {
+ local_persist BaseAllocator b;
+ if (!b.reserve) {
+ b = (BaseAllocator) {
+ .reserve = am_mem_reserve_malloc,
+ .commit = am_mem_change_noop,
+ .decommit = am_mem_change_noop,
+ .release = am_mem_release_malloc,
+ };
+ }
+ return &b;
+}
+
+internal MemArena am_mem_arena_create_reserve(BaseAllocator *base, u64 reserve_size) {
+ MemArena a = {
+ .base = base,
+ };
+ a.mem = a.base->reserve(a.base->ctx, reserve_size);
+ a.cap = reserve_size;
+ return a;
+}
+
+internal MemArena am_mem_arena_create(BaseAllocator *base) {
+ return am_mem_arena_create_reserve(base, AM_MEM_ARENA_DEFAULT_RESERVE_SIZE);
+}
+
+internal void *am_mem_arena_push(MemArena *a, u64 size) {
+ void *result = NULL;
+ if (a->mem + size <= a->mem + a->cap) {
+ result = a->mem + a->pos;
+ a->pos += size;
+
+ if (a->pos > a->commit_pos) {
+ u64 aligned = ALIGN_UP_POW_2(a->pos, AM_MEM_ARENA_COMMIT_BLOCK_SIZE);
+ u64 next_commit_pos = CLAMP_TOP(aligned, a->cap);
+ u64 commit_size = next_commit_pos - a->commit_pos;
+ a->base->commit(a->base->ctx, a->mem + a->commit_pos, commit_size);
+ a->commit_pos = next_commit_pos;
+ }
+ }
+ return result;
+}
+
+#define AM_MEM_ARENA_PUSH_ARRAY(arena, T, count) (am_mem_arena_push((arena), sizeof(T) * (count)))
+
+internal void am_mem_arena_pop_to(MemArena *a, u64 pos) {
+ if (pos < a->pos) {
+ a->pos = pos;
+
+ u64 aligned = ALIGN_UP_POW_2(a->pos, AM_MEM_ARENA_COMMIT_BLOCK_SIZE);
+ u64 next_commit_pos = CLAMP_TOP(aligned, a->cap);
+ if (next_commit_pos < a->commit_pos) {
+ u64 decommit_size = a->commit_pos - next_commit_pos;
+ a->base->decommit(a->base->ctx, a->mem + a->commit_pos, decommit_size);
+ a->commit_pos = next_commit_pos;
+ }
+ }
+}
+
+internal void am_mem_arena_release(MemArena *a) {
+ a->base->release(a->base->ctx, a->mem, a->cap);
+ *a = (MemArena){0};
+}
+
+// TODO: SIMD
+internal void am_mem_copy(void *dst, void *src, u64 size) {
+ assert(dst);
+ for (u64 i = 0; i < size; i++) {
+ ((u8 *)dst)[i] = ((u8 *)src)[i];
+ }
+}
+
+internal void am_mem_set(u64 size, void *dst, u8 byte) {
+ assert(dst);
+ for (u64 i = 0; i < size; i++) {
+ ((u8 *)dst)[i] = byte;
+ }
+}
+
+internal bool am_mem_equal(void *dst, void *src, u64 size) {
+ for (u64 i = 0; i < size; i++) {
+ if (((u8 *)dst)[i] != ((u8 *)src)[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+internal void am_memory_test(void) {
+ assert(MEM_KIB(10) == 10240);
+ assert(MEM_MIB(10) == 10485760);
+ assert(MEM_GIB(10) == 10737418240);
+
+ {
+ BaseAllocator *a = am_mem_base_allocator_malloc();
+ u64 num_test_ints = 10;
+ s32 *int_buf = a->reserve(NULL, num_test_ints * sizeof(s32));
+ assert(int_buf);
+ a->release(NULL, int_buf, 0);
+ }
+
+ {
+ MemArena a = am_mem_arena_create(am_mem_base_allocator_malloc());
+ am_mem_arena_push(&a, 1020);
+ assert(a.pos == 1020);
+ u64 p = a.pos;
+ u64 cp = a.commit_pos;
+
+ AM_MEM_ARENA_PUSH_ARRAY(&a, u8, a.cap - a.pos);
+ assert(a.pos == a.cap);
+ assert(a.commit_pos == a.cap);
+
+ am_mem_arena_pop_to(&a, p);
+ assert(a.pos == p);
+ assert(a.commit_pos == cp);
+
+ am_mem_arena_release(&a);
+ assert(a.pos == 0);
+ assert(a.commit_pos == 0);
+ assert(a.mem == NULL);
+ }
+
+ {
+ u8 src[10] = {0};
+ u8 dst[10] = {0};
+ for (u64 i = 0; i < ARRAY_COUNT(src); i++) {
+ assert(i < UINT8_MAX);
+ src[i] = (u8)i;
+ }
+
+ am_mem_copy(dst, src, ARRAY_COUNT(dst));
+ assert(am_mem_equal(dst, src, ARRAY_COUNT(dst)));
+ }
+}
+
+#endif // AM_MEMORY_H
diff --git a/2022/am_string.h b/2022/am_string.h
@@ -0,0 +1,381 @@
+#ifndef AM_STRING_H
+#define AM_STRING_H
+
+#ifndef AM_MEMORY_H
+ #error "am_memory.h is required"
+#endif
+#ifndef AM_LIST_H
+ #error "am_list.h is required"
+#endif
+
+typedef struct {
+ usz size;
+ u8 *str;
+} Str;
+
+typedef struct StrListNode StrListNode;
+struct StrListNode {
+ StrListNode *next;
+ Str s;
+};
+
+typedef struct {
+ StrListNode *first;
+ StrListNode *last;
+ u64 node_count;
+ u64 total_size;
+} StrList;
+
+#define AM_STR_LIT(s) (Str) { .str = (u8 *)(s), .size = sizeof(s) - 1, }
+#define AM_STR_EXPAND(s) (s32)((s).size), ((s).str)
+
+internal usz am_cstr_len(char *cstr) {
+ usz len = 0;
+ while (cstr && *cstr != '\0') {
+ len++;
+ cstr++;
+ }
+ return len;
+}
+
+internal Str am_str(u8 *str, usz size) {
+ return (Str) { .size = size, .str = str, };
+}
+
+internal Str am_str_from_range(u8 *start, u8 *opl) {
+ assert(start < opl);
+ return am_str(start, (usz)(opl - start));
+}
+
+internal Str am_str_from_cstr(char *cstr, usz len) {
+ return am_str((u8 *)cstr, len);
+}
+
+// TODO: Use string interning
+internal bool am_str_eq(Str s1, Str s2) {
+ if (s1.size != s2.size) {
+ return false;
+ }
+
+ for (usz i = 0; i < s1.size; i++) {
+ if (s1.str[i] != s2.str[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+internal bool am_cstr_eq(char *cstr1, char *cstr2) {
+ usz len1 = am_cstr_len(cstr1);
+ usz len2 = am_cstr_len(cstr2);
+ return am_str_eq(am_str_from_cstr(cstr1, len1), am_str_from_cstr(cstr2, len2));
+}
+
+internal Str am_str_line(Str s, u8 *cursor) {
+ u8 *opl = s.str + s.size;
+
+ assert(cursor >= s.str && cursor < opl);
+
+ u8 *end = cursor;
+ while (end < opl) {
+ if (*end == '\n') {
+ break;
+ }
+ end++;
+ }
+
+ u8 *beginning = cursor - (*cursor == '\n');
+ while (beginning > s.str) {
+ if (*beginning == '\n') {
+ beginning++;
+ break;
+ }
+ beginning--;
+ }
+
+ return am_str_from_range(beginning, end);
+}
+
+internal bool am_str_contains(Str s, char c) {
+ for (usz i = 0; i < s.size; i++) {
+ if (s.str[i] == c) {
+ return true;
+ }
+ }
+ return false;
+}
+
+internal bool am_cstr_contains(char *s, usz len, char c) {
+ return am_str_contains(am_str_from_cstr(s, len), c);
+}
+
+internal bool am_str_cstr_eq(Str s, char *cstr) {
+ return am_str_eq(s, am_str_from_cstr(cstr, am_cstr_len(cstr)));
+}
+
+internal void am_str_list_append(MemArena *arena, StrList *list, Str s) {
+ StrListNode *node = am_mem_arena_push(arena, sizeof(StrListNode));
+ *node = (StrListNode) {
+ .s = s,
+ };
+ SLL_QUEUE_PUSH(list->first, list->last, node);
+ list->node_count += 1;
+ list->total_size += s.size;
+}
+
+internal void am_str_list_discard_empty(StrList *list) {
+ assert(list);
+ if (list->node_count) {
+ StrListNode *previous = NULL;
+
+ for (StrListNode *n = list->first; n; n = n->next) {
+ if (n->s.size == 0) {
+ assert(list->node_count > 0);
+ list->node_count--;
+ if (previous) {
+ previous->next = n->next;
+ } else {
+ list->first = n->next;
+ }
+ } else {
+ previous = n;
+ }
+ }
+ }
+}
+
+typedef struct {
+ Str pre;
+ Str mid;
+ Str post;
+} StringJoinOptions;
+
+internal Str am_str_join(MemArena *arena, StrList *list, StringJoinOptions *options) {
+ StringJoinOptions join;
+ if (options) {
+ join = *options;
+ } else {
+ join = (StringJoinOptions){0};
+ }
+
+ Str s = {0};
+
+ if (list->node_count) {
+ assert(list->node_count > 0);
+
+ u64 total_size = list->total_size
+ + join.pre.size
+ + (join.mid.size * (list->node_count - 1))
+ + join.post.size;
+
+ s = (Str) {
+ .str = AM_MEM_ARENA_PUSH_ARRAY(arena, u8, total_size),
+ .size = total_size,
+ };
+
+ u8 *p = s.str;
+ am_mem_copy(p, join.pre.str, join.pre.size);
+ p += join.pre.size;
+
+ bool is_mid = false;
+ for (StrListNode *n = list->first; n; n = n->next) {
+ if (is_mid) {
+ am_mem_copy(p, join.mid.str, join.mid.size);
+ p += join.mid.size;
+ }
+
+ am_mem_copy(p, n->s.str, n->s.size);
+ p += n->s.size;
+
+ is_mid = true;
+ }
+
+ am_mem_copy(p, join.post.str, join.post.size);
+ p += join.post.size;
+ }
+
+ return s;
+}
+
+internal StrList am_str_split(MemArena *arena, Str s, u8 *split_chars, u64 split_char_count) {
+ StrList list = {0};
+
+ u8 *cursor = s.str;
+ u8 *split_beginning = cursor;
+ u8 *opl = s.str + s.size;
+ while (cursor <= opl) {
+ bool split_byte = false;
+ for (u64 i = 0; i < split_char_count; i++) {
+ if (split_chars[i] == *cursor) {
+ split_byte = true;
+ break;
+ }
+ }
+
+ if (split_byte) {
+ if (cursor == split_beginning) {
+ am_str_list_append(arena, &list, AM_STR_LIT(""));
+ } else {
+ am_str_list_append(arena, &list, am_str_from_range(split_beginning, cursor));
+ }
+ split_beginning = cursor + 1;
+ }
+ cursor++;
+ }
+
+ return list;
+}
+
+internal void am_string_test(void) {
+ assert(am_cstr_len("abcdefg") == 7);
+ assert(am_cstr_len("") == 0);
+ assert(am_cstr_len("\0") == 0);
+ assert(am_cstr_eq("", ""));
+ assert(am_cstr_eq("\0", "\0"));
+ assert(am_cstr_eq("abc", "abc"));
+ assert(!am_cstr_eq("ABC", "abc"));
+ assert(!am_cstr_eq("", " "));
+ assert(!am_cstr_eq("abc", "abcde"));
+ assert(!am_str_cstr_eq(AM_STR_LIT("abcd"), "abc"));
+ assert(am_str_cstr_eq(AM_STR_LIT("abc"), "abc"));
+ assert(am_cstr_contains("abc", 3, 'c'));
+ assert(am_cstr_contains("a c", 3, ' '));
+ assert(am_cstr_contains("", 1, '\0'));
+ assert(!am_cstr_contains("abc", 3, 'z'));
+ assert(!am_cstr_contains("", 0, 'z'));
+ assert(!am_cstr_contains("", 0, '\0'));
+ assert(am_cstr_contains("https://www.example.com", 23, '/'));
+
+ {
+ StrList l = {0};
+ MemArena a = am_mem_arena_create(am_mem_base_allocator_malloc());
+ Str strings[] = {
+ AM_STR_LIT("one"),
+ AM_STR_LIT("two"),
+ AM_STR_LIT("three"),
+ };
+
+ for (u64 i = 0; i < ARRAY_COUNT(strings); i++) {
+ am_str_list_append(&a, &l, strings[i]);
+ }
+
+ Str joined = am_str_join(&a, &l, &(StringJoinOptions){
+ .pre = AM_STR_LIT("Joined: '"),
+ .mid = AM_STR_LIT(", "),
+ .post = AM_STR_LIT("'."),
+ });
+
+ printf("%.*s\n", AM_STR_EXPAND(joined));
+
+ StrList split = am_str_split(&a, AM_STR_LIT(", one, two, three, four, "), (u8 *)", ", 2);
+
+ for (StrListNode *n = split.first; n; n = n->next) {
+ printf("split: '%.*s'\n", AM_STR_EXPAND(n->s));
+ }
+
+ am_mem_arena_release(&a);
+ }
+
+ {
+ MemArena a = am_mem_arena_create(am_mem_base_allocator_malloc());
+ StrList lines = am_str_split(&a, AM_STR_LIT("one|two|three|four"), (u8 *)"|", 1);
+
+ Str expected[] = {
+ AM_STR_LIT("one"),
+ AM_STR_LIT("two"),
+ AM_STR_LIT("three"),
+ AM_STR_LIT("four"),
+ };
+
+ size_t i = 0;
+ for (StrListNode *line = lines.first; line; line = line->next) {
+ printf("Expected: '%.*s', Got: '%.*s'\n", AM_STR_EXPAND(expected[i]), AM_STR_EXPAND(line->s));
+ assert(i < ARRAY_COUNT(expected));
+ assert(am_str_eq(line->s, expected[i]));
+ i++;
+ }
+
+ assert(i + 1 == ARRAY_COUNT(expected));
+ am_mem_arena_release(&a);
+ }
+
+ {
+ MemArena a = am_mem_arena_create(am_mem_base_allocator_malloc());
+ StrList lines = am_str_split(&a, AM_STR_LIT("|one|two||three|four|"), (u8 *)"|", 1);
+
+ Str expected[] = {
+ AM_STR_LIT(""),
+ AM_STR_LIT("one"),
+ AM_STR_LIT("two"),
+ AM_STR_LIT(""),
+ AM_STR_LIT("three"),
+ AM_STR_LIT("four"),
+ AM_STR_LIT(""),
+ };
+
+ size_t i = 0;
+ for (StrListNode *line = lines.first; line; line = line->next) {
+ printf("Expected: '%.*s', Got: '%.*s'\n", AM_STR_EXPAND(expected[i]), AM_STR_EXPAND(line->s));
+ assert(i < ARRAY_COUNT(expected));
+ assert(am_str_eq(line->s, expected[i]));
+ i++;
+ }
+
+ assert(i + 1 == ARRAY_COUNT(expected));
+ am_mem_arena_release(&a);
+ }
+
+ {
+ MemArena a = am_mem_arena_create(am_mem_base_allocator_malloc());
+ StrList lines = am_str_split(&a, AM_STR_LIT("|||"), (u8 *)"|", 1);
+
+ Str expected[] = {
+ AM_STR_LIT(""),
+ AM_STR_LIT(""),
+ AM_STR_LIT(""),
+ AM_STR_LIT(""),
+ };
+
+ size_t i = 0;
+ for (StrListNode *line = lines.first; line; line = line->next) {
+ printf("Expected: '%.*s', Got: '%.*s'\n", AM_STR_EXPAND(expected[i]), AM_STR_EXPAND(line->s));
+ assert(i < ARRAY_COUNT(expected));
+ assert(am_str_eq(line->s, expected[i]));
+ i++;
+ }
+
+ assert(i + 1 == ARRAY_COUNT(expected));
+ am_mem_arena_release(&a);
+ }
+
+ {
+ MemArena a = am_mem_arena_create(am_mem_base_allocator_malloc());
+ StrList lines = am_str_split(&a, AM_STR_LIT(""), (u8 *)"|", 1);
+
+ assert(lines.node_count == 0);
+ am_mem_arena_release(&a);
+ }
+
+ {
+ MemArena a = am_mem_arena_create(am_mem_base_allocator_malloc());
+ StrList lines = am_str_split(&a, AM_STR_LIT("one two three four"), (u8 *)"|", 1);
+
+ Str expected[] = {
+ AM_STR_LIT("one two three four"),
+ };
+
+ size_t i = 0;
+ for (StrListNode *line = lines.first; line; line = line->next) {
+ printf("Expected: '%.*s', Got: '%.*s'\n", AM_STR_EXPAND(expected[i]), AM_STR_EXPAND(line->s));
+ assert(i < ARRAY_COUNT(expected));
+ assert(am_str_eq(line->s, expected[i]));
+ i++;
+ }
+
+ assert(i + 1 == ARRAY_COUNT(expected));
+ am_mem_arena_release(&a);
+ }
+}
+
+#endif // AM_STRING_H
diff --git a/2022/day01.c b/2022/day01.c
@@ -0,0 +1,103 @@
+#if 0
+# Self-building c file. Invoke like: `./file.c`
+outdir=out
+input=$(basename "$0")
+output="$outdir"/$(basename "$0" .c)
+mkdir --parents "$outdir" || exit
+echo "Building ${output}." || exit
+clang -std=c11 -O0 -g -Wall -Wextra -pedantic -Wno-unused-function "$input" -o "$output" || exit
+if [ "$1" = "-r" ];
+then
+ ./"$output" "$@"
+fi
+exit
+#endif
+
+#include <inttypes.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+_Noreturn void assert_fail(const char *expr, const char *file, int line, const char *func) {
+ fprintf(stderr, "%s:%d: %s: Assertion failed: '%s'\n", file, line, func, expr);
+ abort();
+}
+
+#define AM_ENABLE_ASSERT 1
+#define AM_ASSERT_FAIL(expr, file, line, func) assert_fail(expr, file, line, func)
+#include "am_base.h"
+#include "am_memory.h"
+#include "am_list.h"
+#include "am_string.h"
+
+Str open_file(MemArena *arena, char *path) {
+ FILE *f = fopen(path, "r");
+ assert(f);
+
+ int error = fseek(f, 0L, SEEK_END);
+ assert(!error);
+
+ s64 size = ftell(f);
+ assert(size >= 0);
+ rewind(f);
+
+ u8 *buf = am_mem_arena_push(arena, size);
+ assert(buf);
+
+ usz items_read = fread(buf, 1, size, f);
+ assert(items_read == (usz)size);
+
+ error = fclose(f);
+ assert(!error);
+
+ return am_str(buf, size);
+}
+
+u64 u64_from_string(Str s) {
+ u64 result = 0;
+ for (usz i = 0; i < s.size; i++) {
+ assert(s.str[i] >= '0' && s.str[i] <= '9');
+
+ u64 place_value = 1;
+ for (usz p = 0; p < (s.size - i - 1); p++) {
+ place_value *= 10;
+ }
+
+ result += (s.str[i] - '0') * place_value;
+ }
+ return result;
+}
+
+int main(void) {
+ MemArena a = am_mem_arena_create(am_mem_base_allocator_malloc());
+ Str input = open_file(&a, "day01_input.txt");
+ StrList lines = am_str_split(&a, input, (u8 *)"\n", 1);
+
+ u64 top[3] = {0};
+ u64 calories = 0;
+
+ for (StrListNode *line = lines.first; line; line = line->next) {
+ calories += u64_from_string(line->s);
+
+ if (am_str_eq(line->s, AM_STR_LIT("")) || line == lines.last) {
+ if (calories > top[0]) {
+ top[0] = calories;
+ }
+
+ u64 sum = top[0] + top[1] + top[2];
+ u64 min = MIN(top[0], MIN(top[1], top[2]));
+ u64 max = MAX(top[0], MAX(top[1], top[2]));
+
+ top[0] = min;
+ top[1] = sum - min - max;
+ top[2] = max;
+
+ calories = 0;
+ }
+ }
+
+ am_mem_arena_release(&a);
+
+ printf("Day 1.1: %" PRIu64 "\n", top[2]);
+ printf("Day 1.2: %" PRIu64 "\n", top[0] + top[1] + top[2]);
+ return 0;
+}
diff --git a/2022/day01_input.txt b/2022/day01_input.txt
@@ -0,0 +1,2269 @@
+3264
+4043
+2537
+3319
+2485
+3218
+5611
+1753
+7232
+3265
+1751
+2233
+
+10589
+5121
+11465
+9307
+1347
+9392
+12037
+
+6025
+4328
+3982
+4487
+1139
+1440
+2970
+3390
+1844
+5400
+1651
+4109
+3584
+2926
+4297
+
+8921
+13298
+12300
+5607
+3304
+5037
+
+1729
+10057
+
+3538
+3984
+3451
+5638
+2880
+1008
+2940
+6245
+3865
+5060
+2878
+2460
+6557
+
+1584
+6391
+3479
+2264
+2683
+3680
+1183
+5121
+6499
+5543
+1192
+4818
+
+1337
+8128
+8966
+7601
+7749
+5017
+3251
+1074
+6095
+
+11824
+17144
+5396
+15416
+
+6244
+6589
+4953
+4250
+1422
+1252
+4555
+5240
+4244
+4088
+
+27353
+
+6629
+7231
+7673
+7029
+6994
+6347
+6381
+1503
+2145
+1114
+6068
+
+3473
+3935
+4054
+3558
+3818
+5370
+4807
+2703
+5407
+2532
+6833
+1675
+
+20016
+7587
+13088
+
+3477
+3118
+5815
+3551
+2316
+4254
+4814
+5726
+5324
+6096
+3596
+3374
+3975
+4152
+1946
+
+4549
+3639
+6338
+6882
+3514
+6488
+2192
+4522
+4370
+3637
+3500
+2964
+1850
+
+6900
+5145
+13864
+8145
+4579
+
+1984
+1589
+9279
+10987
+5213
+
+3997
+1978
+5061
+2710
+2695
+4713
+5930
+3005
+6189
+2619
+6897
+5032
+2374
+
+1738
+6817
+1993
+13747
+8574
+13341
+
+3869
+1810
+3501
+1366
+4240
+2005
+6102
+6069
+4135
+6667
+1239
+2799
+1900
+
+4711
+1330
+9725
+5965
+8271
+11932
+
+5319
+6078
+1652
+1958
+1992
+1997
+2824
+6542
+1998
+2713
+6806
+4993
+6569
+
+9262
+
+3814
+11917
+4812
+1884
+3686
+10993
+
+8845
+6032
+9899
+10384
+3834
+2275
+
+3559
+2268
+1446
+
+2265
+5503
+5056
+2547
+7394
+2514
+8105
+4630
+9392
+
+2377
+10479
+3452
+9175
+13773
+
+6090
+1467
+2747
+9310
+2839
+9392
+10752
+5771
+
+8193
+4139
+4728
+5180
+5884
+9236
+
+5721
+10884
+10268
+3255
+2377
+11574
+4498
+
+17228
+7306
+6465
+
+69149
+
+6323
+3435
+2801
+6385
+4192
+1593
+4373
+6654
+7190
+6142
+
+10960
+3399
+12251
+8249
+8210
+3571
+
+2299
+4349
+1476
+5703
+1497
+4008
+1435
+5043
+2203
+4252
+2407
+5891
+
+1419
+1588
+
+4266
+2424
+1846
+3265
+5720
+5396
+2013
+2664
+4712
+1040
+3186
+1693
+1537
+3226
+
+15568
+16153
+15408
+9417
+15524
+
+18017
+4247
+1764
+18920
+
+14176
+18583
+
+4896
+1029
+14517
+10183
+9726
+
+5242
+4156
+2314
+4018
+3542
+1619
+5349
+2524
+2620
+4675
+6491
+5315
+3959
+5215
+
+2638
+5346
+6209
+1466
+2854
+6677
+2242
+8476
+5236
+
+3827
+4489
+7735
+5656
+11568
+12323
+
+8560
+7046
+5453
+4141
+1356
+8940
+8338
+3749
+7297
+
+10693
+7191
+8803
+10504
+2033
+6374
+6820
+10316
+
+5869
+12102
+12675
+7688
+10906
+12593
+
+9028
+8234
+4453
+2117
+7328
+9404
+6664
+7206
+6357
+
+3018
+5515
+6479
+1522
+4582
+5881
+4019
+1288
+5288
+4007
+5816
+2354
+5648
+5405
+
+4120
+3890
+11718
+5713
+6986
+10362
+5529
+
+8243
+2097
+10194
+3023
+11120
+9524
+2052
+
+12552
+14406
+3981
+9703
+10329
+
+7256
+9424
+4701
+
+5694
+1262
+3521
+4194
+3530
+7472
+1773
+1787
+6229
+6608
+5905
+3065
+
+3366
+
+15198
+25328
+
+3805
+4163
+4192
+4013
+2693
+3029
+4559
+5243
+3088
+4804
+1245
+1800
+4999
+3162
+6114
+
+3808
+3672
+6397
+3747
+4312
+5015
+4237
+5326
+3961
+1382
+1380
+5517
+1140
+
+3360
+6936
+3880
+4242
+7431
+5597
+6195
+5305
+1051
+1015
+1866
+3179
+
+17144
+2423
+8330
+
+5153
+2301
+4944
+1566
+5647
+6726
+6248
+1537
+6951
+1272
+1177
+2013
+
+7595
+9953
+19751
+14200
+
+2576
+1684
+6463
+6643
+2911
+1650
+2492
+5726
+4830
+6591
+4477
+6691
+6390
+
+5209
+5099
+1115
+5456
+4573
+5954
+4389
+1703
+1595
+1348
+5814
+4031
+3086
+4039
+5445
+
+3506
+3956
+1504
+5435
+5660
+6882
+1962
+4891
+2596
+3838
+7206
+5554
+
+10423
+4792
+16000
+12857
+5040
+
+7410
+2589
+6769
+8168
+7526
+4349
+
+5160
+12452
+13889
+7499
+1985
+12491
+
+1033
+9259
+6288
+5566
+6134
+11010
+7512
+
+5196
+4644
+1825
+5564
+5759
+7134
+5589
+5387
+1328
+2314
+4948
+7354
+
+6875
+2105
+3444
+6997
+3962
+1141
+2000
+7561
+6447
+5629
+7035
+
+1499
+7160
+5201
+3206
+2719
+5177
+6566
+3455
+3304
+1648
+3273
+
+6142
+3697
+2247
+6537
+5579
+7126
+2674
+1842
+1482
+5504
+1105
+
+5669
+7401
+8229
+6261
+4378
+5548
+2360
+5703
+7650
+2086
+
+23865
+10240
+2321
+
+4221
+8067
+1395
+1397
+5776
+5136
+6820
+1428
+3375
+6117
+4467
+
+2505
+4307
+5626
+8867
+
+4709
+5951
+3811
+4998
+4460
+6243
+1790
+2172
+5694
+6245
+3273
+2664
+4813
+5669
+
+5803
+4856
+2508
+6301
+4454
+2430
+4868
+4883
+6211
+1749
+2998
+3450
+2414
+5617
+
+9135
+8583
+7582
+8349
+7609
+4434
+8362
+3472
+
+44093
+
+7933
+3349
+6041
+3238
+5036
+9100
+4252
+
+14356
+24185
+
+11887
+23333
+16694
+
+6324
+1438
+5180
+5329
+6798
+4806
+5285
+4757
+4599
+3897
+2308
+5014
+
+1455
+4268
+1903
+1436
+4563
+5135
+4876
+6561
+4776
+3530
+3080
+5724
+5520
+
+3419
+2363
+4474
+6069
+2504
+6749
+4094
+5991
+8045
+1302
+5649
+
+20607
+13990
+
+7588
+9960
+8919
+11254
+6295
+3856
+10295
+
+1161
+3773
+1559
+1198
+5967
+5237
+3369
+4437
+7698
+2756
+2639
+
+43493
+
+18577
+2593
+16336
+13785
+
+6567
+2409
+8001
+4173
+11587
+8238
+3023
+
+5146
+10077
+2630
+4827
+6199
+3701
+3840
+3068
+
+3272
+5212
+3674
+5352
+3129
+4242
+2711
+3064
+4987
+5362
+4858
+3180
+6090
+2265
+4791
+
+14702
+1034
+
+12170
+8780
+14933
+3727
+
+4239
+7116
+1120
+7853
+7862
+5512
+2309
+3094
+6359
+
+9172
+12494
+8382
+
+8629
+11921
+9629
+11535
+7792
+9996
+
+6887
+10548
+3429
+2373
+6208
+5406
+5440
+
+2164
+3233
+1512
+1556
+5476
+3462
+4261
+3563
+2409
+6236
+2568
+4638
+4775
+1131
+
+27798
+30212
+
+5409
+4676
+5445
+2119
+3557
+1135
+6724
+2779
+1324
+2157
+4456
+6329
+2155
+
+4084
+1379
+7443
+12904
+
+7167
+12163
+9588
+11186
+9015
+
+35132
+18974
+
+3418
+
+12568
+1418
+7691
+12369
+1144
+6141
+
+2523
+5150
+2276
+6036
+1492
+5069
+5782
+2999
+4505
+2347
+1234
+5376
+3356
+2489
+1456
+
+30181
+
+3189
+2572
+5145
+4350
+6403
+1285
+5678
+3796
+3792
+2334
+2710
+3536
+5580
+
+2991
+7718
+1798
+5300
+11608
+3376
+11658
+
+58468
+
+6099
+4433
+7634
+7768
+3804
+5523
+6959
+4752
+8693
+2705
+
+5315
+4218
+
+5678
+2293
+2385
+2568
+1644
+3332
+5968
+4159
+5935
+2667
+4518
+2823
+4648
+3072
+5644
+
+14306
+7557
+15251
+6896
+14250
+
+10549
+1662
+10040
+2614
+4843
+1111
+9585
+
+9531
+2249
+1949
+8715
+9466
+1471
+7952
+
+2585
+8702
+10548
+12849
+5342
+10193
+
+21463
+24241
+9125
+
+36676
+
+18212
+11298
+8690
+
+6861
+1095
+4586
+1260
+2795
+3208
+4650
+4147
+5764
+1051
+6882
+5670
+
+16681
+22273
+1336
+
+3370
+3537
+2062
+4985
+2063
+2339
+5988
+3777
+5822
+2760
+1915
+4668
+4717
+5847
+4598
+
+5829
+4829
+4872
+3893
+5320
+1832
+7637
+7137
+6079
+3006
+7422
+
+34780
+21066
+
+1164
+3444
+8079
+4633
+5030
+8296
+8703
+7929
+8767
+4489
+
+1950
+5492
+4920
+3849
+6553
+1802
+1574
+4962
+1671
+2382
+4990
+2511
+3485
+
+6003
+8237
+
+10793
+12510
+2959
+9397
+6153
+
+7943
+1934
+3817
+7937
+6856
+3813
+4408
+8046
+4605
+3994
+8081
+
+10589
+11870
+8367
+7889
+10172
+9758
+9447
+
+6566
+4971
+4600
+6863
+4212
+5240
+6523
+7979
+2695
+4934
+
+6527
+2008
+4595
+7104
+7497
+10199
+6640
+7909
+
+7970
+7026
+4812
+4331
+3244
+5260
+3089
+2871
+3915
+1445
+
+3182
+9915
+5769
+6470
+10524
+7486
+5041
+
+5575
+
+6482
+2235
+2834
+3999
+4428
+1713
+3366
+4477
+2282
+1331
+5095
+5268
+5482
+3409
+
+21109
+
+8502
+2007
+3250
+6035
+6099
+2605
+6323
+5532
+3677
+8194
+
+11224
+1704
+10152
+11640
+1018
+7016
+2700
+
+12204
+
+1191
+5039
+5036
+3778
+1669
+5277
+5345
+3833
+5379
+1286
+2042
+5365
+4518
+5517
+
+2750
+4544
+3817
+5392
+1745
+4056
+1557
+1819
+6187
+4867
+6445
+4475
+3026
+5516
+
+13176
+25505
+2657
+
+29617
+4098
+
+1733
+3055
+3730
+5327
+3111
+4912
+1842
+2471
+1964
+2747
+1573
+4097
+5558
+4940
+2065
+
+1177
+3510
+6178
+1267
+9395
+1387
+1251
+9112
+1265
+
+4073
+8822
+
+5585
+4905
+1005
+4303
+2129
+1565
+1577
+1747
+7097
+7135
+2546
+
+6368
+6384
+1873
+2027
+2111
+5781
+4392
+1640
+1874
+5147
+6551
+4992
+
+11673
+15872
+10747
+5457
+
+7576
+6084
+3279
+5582
+8329
+7176
+6561
+5342
+8481
+6333
+
+7617
+12916
+8957
+17210
+
+4173
+1088
+5981
+2094
+4598
+3192
+3968
+1486
+3888
+4186
+5948
+3764
+3173
+1597
+5057
+
+7430
+3183
+20030
+4003
+
+5891
+6434
+2213
+1762
+6106
+7550
+6766
+6075
+1119
+4462
+
+2460
+7385
+3906
+2805
+2519
+2189
+6803
+2705
+5167
+2972
+6855
+6996
+
+3922
+4300
+2172
+7515
+9388
+8687
+5087
+6373
+4001
+
+3288
+3888
+3873
+7575
+1902
+3315
+4831
+3272
+4914
+
+2120
+3223
+3582
+4864
+1944
+2625
+2666
+1710
+2511
+4362
+3073
+3994
+3171
+
+8037
+2890
+3124
+8901
+1411
+6858
+5184
+1294
+7790
+
+7884
+7169
+4372
+5820
+6836
+2878
+7608
+2434
+8600
+8117
+
+33732
+17277
+
+31526
+6202
+
+6081
+5669
+1460
+7548
+1054
+3713
+8470
+
+7033
+4205
+4404
+4261
+2975
+7865
+5190
+1675
+1349
+7748
+
+7345
+6389
+3056
+2777
+12209
+10038
+
+5285
+7634
+5875
+6074
+3076
+2687
+4342
+5471
+4113
+
+2993
+10714
+5204
+6732
+4746
+12416
+
+19555
+17202
+13776
+6280
+
+2820
+11278
+6160
+9522
+6585
+
+9093
+6397
+10417
+4902
+4899
+
+5602
+4917
+4964
+5689
+4316
+4041
+5290
+3223
+4065
+3514
+3552
+5864
+4823
+6481
+
+3239
+5151
+2862
+4568
+1964
+3003
+3575
+4445
+6875
+5511
+1591
+1681
+6874
+
+7348
+1881
+7702
+6305
+2373
+6320
+1544
+2897
+2784
+5977
+6964
+
+1757
+7460
+5212
+3491
+1157
+3753
+1983
+3015
+1298
+2812
+3569
+4680
+
+22481
+
+8578
+7141
+11229
+5622
+13937
+1699
+
+3479
+1258
+2782
+5573
+7720
+6726
+4043
+3059
+5028
+8075
+
+3232
+6633
+5344
+1862
+6215
+3674
+2507
+5509
+1982
+4422
+1709
+
+2759
+2497
+3959
+1725
+2430
+3256
+1416
+4213
+3452
+6809
+6817
+3151
+
+5187
+2502
+6982
+3414
+11460
+12085
+5775
+
+1490
+4368
+4135
+1494
+5683
+5443
+5182
+6209
+3240
+1433
+3373
+3048
+5768
+4132
+
+22305
+10502
+
+6633
+2336
+6714
+3046
+4740
+4650
+2901
+5832
+5690
+4211
+6168
+4901
+2448
+
+8640
+11265
+10961
+10744
+10955
+
+16404
+15126
+4253
+1372
+
+9862
+9547
+20599
+
+8872
+3452
+2169
+7757
+5535
+9697
+8147
+8775
+
+14862
+
+68282
+
+4343
+11948
+2346
+16745
+
+12892
+12538
+15571
+11814
+
+4406
+1323
+3769
+5868
+5023
+6057
+5967
+2891
+2778
+5696
+4376
+2244
+4102
+4721
+
+8420
+
+8564
+2803
+11178
+17801
+
+34616
+
+4635
+3716
+6634
+3494
+2905
+4254
+8053
+4871
+5523
+5088
+2928
+
+7447
+16669
+9215
+14663
+
+4248
+3260
+3347
+5552
+4781
+1715
+5642
+5414
+3223
+3043
+3415
+6463
+5932
+
+29980
+37187
+
+9703
+7176
+8191
+10002
+7145
+5926
+10760
+7384
+
+32599
+26889
+
+5843
+1632
+3871
+5645
+9544
+3097
+1820
+
+6941
+4838
+5440
+4389
+5309
+5449
+5897
+4418
+4641
+6905
+4951
+2198
+1031
+
+4553
+1428
+4164
+2850
+1146
+2496
+4807
+4776
+1573
+2865
+1225
+5182
+2617
+1514
+5828
+
+5660
+1567
+5066
+4985
+4683
+4819
+3894
+4432
+5188
+4791
+5916
+3867
+4285
+5863
+5570
+
+5394
+3391
+4052
+3230
+4524
+1059
+3685
+1808
+2161
+2662
+3718
+5945
+5094
+4867
+4258
+
+28646
+31561
+
+11012
+2804
+5719
+5299
+2500
+11059
+
+1318
+5060
+1097
+5290
+1059
+3435
+1082
+6242
+1623
+2004
+3567
+1725
+5056
+
+4643
+5165
+14091
+6412
+13186
+
+5560
+
+7978
+4943
+8311
+6023
+15930
+
+1972
+7310
+6563
+1748
+6142
+4529
+2106
+7066
+4598
+7301
+2132
+4005
+
+1173
+6436
+6047
+5197
+6500
+4588
+5341
+4781
+4750
+4244
+1199
+4931
+4863
+5628
+
+10302
+8627
+5405
+6570
+11439
+1447
+
+22318
+21787
+9491
+
+4710
+4259
+5894
+2971
+4273
+4994
+3414
+4179
+2483
+5404
+1646
+3099
+4035
+4066
+
+6374
+8210
+4288
+2226
+3271
+8759
+6171
+7020
+8299
+1958
+
+2744
+6690
+1431
+5118
+5387
+7128
+5517
+6299
+7515
+4304
+1846
+
+1941
+1309
+1888
+4992
+5942
+4182
+2334
+3283
+4907
+2610
+3373
+2936
+1908
+
+3400
+6953
+5233
+5348
+8743
+2799
+7890
+1898
+7783
+
+38934
+
+3843
+1038
+3364
+6113
+3952
+7192
+5767
+3932
+4462
+2088
+3925
+3990
+
+2596
+10301
+11026
+12033
+2542
+13448
+
+4798
+6076
+3906
+1617
+8462
+2051
+4827
+1905
+5940
+7175
+
+8305
+6626
+1600
+5228
+6332
+1206
+4840
+4600
+5363
+
+6425
+13475
+11305
+14037
+
+6154
+1016
+3673
+1827
+3628
+4238
+2483
+4762
+3413
+3148
+4659
+3451
+6465
+2363
+
+35242
+27022
+
+2722
+11484
+12323
+6822
+7951
+4387
+
+36866
+
+5755
+20057
+5657
+
+2491
+2205
+3527
+9556
+8363
+3109
+8618
+1481
+6234
+
+7365
+1920
+1578
+3271
+3325
+1263
+1816
+7031
+8020
+2353
+3127
+
+8027
+13092
+7531
+12350
+
+10451
+9259
+13080
+12849
+
+3984
+2140
+2655
+2766
+8665
+2282
+4391
+1435
+4821
+4977
+
+2366
+
+6198
+17922
+22945
+
+2077
+6263
+11643
+11377
+3735
+11634
+5022
+
+16598
+7968
+
+31400
+22664
+
+5414
+5057
+1898
+3063
+4075
+2527
+3502
+6713
+3109
+6376
+2487
+2279
+1057
+
+12654
+11007
+2365
+8272
+2895
+
+15798
+3536
+14549
+
+1066
+1181
+6142
+9592
+3412
+8683
+
+3274
+1129
+1645
+4784
+4039
+5447
+4766
+1310
+3346
+4062
+2219
+4290
+4733
+3033
+1306
+
+2006
+2898
+3600
+1802
+4760
+5306
+1000
+1279
+1205
+5224
+2652
+4914
+4042
+1559
+
+20342
+16632
+
+18586
+1712
+11316
+16623
+
+7964
+6856
+7863
+7417
+4608
+7216
+4263
+6552
+3187
+
+6415
+2442
+2928
+4853
+6899
+6747
+3803
+3522
+5680
+6184
+3326
+5707
+1695
+
+61737
+
+18154
+7052
+
+4635
+3560
+8043
+5917
+9440
+7535
+7213
+7625
+
+3389
+1034
+4154
+4872
+4843
+2238
+1174
+2922
+1067
+5715
+5093
+3302
+1076
+3017
+4711
+
+9322
+11596
+6347
+11332
+9376
+9230
+
+6475
+6492
+4953
+6492
+3935
+2286
+7152
+4659
+5762
+4989
+6438
+1020