main.c (3367B)
1#include "aoc.h" 2#include "allocator.h" 3#include "util.h" 4#include "dvec_s.h" 5 6#include <assert.h> 7#include <string.h> 8#include <stdio.h> 9 10static const int freq[] = { 0, 1, 0, -1 }; 11 12void 13parse_input(struct dvec *phases) 14{ 15 const char *c, *sep; 16 int *val; 17 18 sep = strchr(aoc.input, '\n'); 19 assert(sep != NULL); 20 21 for (c = aoc.input; c < sep; c++) { 22 val = dvec_add_slot(phases); 23 *val = *c - '0'; 24 } 25} 26 27void 28fft(struct dvec *phases, size_t rounds) 29{ 30 struct dvec copy; 31 size_t r, i, k, l; 32 ssize_t sum; 33 int digit; 34 int *val; 35 36 dvec_init(©, sizeof(int), 0, &stdlib_strict_heap_allocator); 37 38 for (r = 0; r < rounds; r++) { 39 dvec_copy(©, phases); 40 41 for (i = 0; i < copy.len; i++) { 42 sum = 0; 43 for (k = 0; k < copy.len; k++) { 44 l = (k + 1) / (i + 1); 45 digit = *(int *)dvec_at(©, k); 46 sum += freq[l % 4] * digit; 47 } 48 sum = ABS(sum) % 10; 49 val = dvec_at(phases, i); 50 *val = (int) sum; 51 } 52 } 53 54 dvec_deinit(©); 55} 56 57void 58fft_dup(struct dvec *phases, size_t offset, size_t rounds, size_t dup) 59{ 60 size_t r, i, len, lutlen; 61 int *lut, *lutc, *lutp; 62 int digit, *slot; 63 64 /* | a b c 65 * --+------------------------ 66 * 1 | a+b+c b+c c 67 * 2 | a+2b+3c b+2c c 68 * n |a+nb+n(n+1)/2c b+nc c 69 * 70 * a+sum(1)b+sum(sum(1))c .. not nice 71 * 72 * sum(1): n 73 * sum(sum(1)): n(n+1)/2 74 * sum(sum(sum(1))): (K2+K1)/2 = (n^2+n)/2 + (n^3-n)/6 75 * 76 * .. calculation possible but not practically feasible since we 77 * would have to do 10000..th sum() .. will have to use a lookup table 78 */ 79 80 len = phases->len * dup; 81 assert(offset >= len / 2 && offset < len); 82 83 lutlen = len - offset; 84 lut = malloc(lutlen * sizeof(int) * (rounds + 1)); 85 assert(lut != NULL); 86 87 /* top row */ 88 for (i = 0; i < lutlen; i++) { 89 digit = *(int *)dvec_at(phases, (i + offset) % phases->len); 90 lut[i] = digit; 91 } 92 93 /* right column */ 94 digit = *(int *)dvec_at(phases, (len - 1) % phases->len); 95 for (r = 0; r < rounds; r++) { 96 lut[(r + 1) * lutlen + lutlen - 1] = digit; 97 } 98 99 for (r = 0; r < rounds; r++) { 100 lutp = &lut[r * lutlen + lutlen - 2]; 101 lutc = &lut[(r + 1) * lutlen + lutlen - 2]; 102 for (i = 1; i < lutlen; i++, lutp--, lutc--) 103 lutc[0] = (lutp[0] + lutc[1]) % 10; 104 } 105 106 dvec_clear(phases); 107 for (i = 0; i < 8; i++) { 108 slot = dvec_add_slot(phases); 109 *slot = lut[rounds * lutlen + i]; 110 } 111 112 free(lut); 113} 114 115void 116part1(void) 117{ 118 struct dvec phases; 119 char *answer; 120 size_t i; 121 int digit; 122 123 dvec_init(&phases, sizeof(int), 64, &stdlib_strict_heap_allocator); 124 125 parse_input(&phases); 126 127 fft(&phases, 100); 128 129 answer = malloc(9); 130 for (i = 0; i < 8; i++) { 131 digit = *(int *)dvec_at(&phases, i); 132 answer[i] = '0' + (char) digit; 133 } 134 answer[i] = 0; 135 136 aoc.answer = answer; 137 aoc.solution = "29956495"; 138 139 dvec_deinit(&phases); 140} 141 142void 143part2(void) 144{ 145 struct dvec phases; 146 char *answer; 147 int digit; 148 size_t offset; 149 size_t base; 150 size_t i; 151 152 dvec_init(&phases, sizeof(int), 64, &stdlib_strict_heap_allocator); 153 154 parse_input(&phases); 155 156 base = 1; 157 offset = 0; 158 for (i = 0; i < 7; i++) { 159 digit = *(int *)dvec_at(&phases, 6 - i); 160 offset += base * (size_t) digit; 161 base *= 10; 162 } 163 164 fft_dup(&phases, offset, 100, 10000); 165 166 answer = malloc(9); 167 for (i = 0; i < 8; i++) { 168 digit = *(int *)dvec_at(&phases, i); 169 answer[i] = '0' + (char) digit; 170 } 171 answer[i] = 0; 172 173 aoc.answer = answer; 174 aoc.solution = "73556504"; 175 176 dvec_deinit(&phases); 177}