aoc-2019-c

git clone https://git.sinitax.com/sinitax/aoc-2019-c
Log | Files | Refs | README | sfeed.txt

commit ef73ac2bc8dbde3b9fbf91821c925670b0cfea75
parent d670b95b371a9ee99df7b2f0e4c373fd57e48220
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sat, 25 Mar 2023 01:40:38 +0100

Add day 16

Diffstat:
A16/info.mk | 3+++
A16/input | 2++
A16/main.c | 177+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A16/part1 | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A16/part2 | 32++++++++++++++++++++++++++++++++
A16/test1 | 1+
A16/test2 | 1+
7 files changed, 311 insertions(+), 0 deletions(-)

diff --git a/16/info.mk b/16/info.mk @@ -0,0 +1,3 @@ +16_SRC = 16/main.c common/main.c common/aoc.c common/util.c +16_SRC += lib/libdvec/build/libdvec.a lib/liballoc/build/liballoc.a +16_HDR = common/aoc.h common/util.h diff --git a/16/input b/16/input @@ -0,0 +1,2 @@ +59769638638635227792873839600619296161830243411826562620803755357641409702942441381982799297881659288888243793321154293102743325904757198668820213885307612900972273311499185929901117664387559657706110034992786489002400852438961738219627639830515185618184324995881914532256988843436511730932141380017180796681870256240757580454505096230610520430997536145341074585637105456401238209187118397046373589766408080120984817035699228422366952628344235542849850709181363703172334788744537357607446322903743644673800140770982283290068502972397970799328249132774293609700245065522290562319955768092155530250003587007804302344866598232236645453817273744027537630 + diff --git a/16/main.c b/16/main.c @@ -0,0 +1,177 @@ +#include "allocator.h" +#include "util.h" +#include "aoc.h" +#include "dvec.h" + +#include <assert.h> +#include <string.h> +#include <stdio.h> + +static const int freq[] = { 0, 1, 0, -1 }; + +void +parse_input(struct dvec *phases) +{ + const char *c, *sep; + int *val; + + sep = strchr(aoc.input, '\n'); + assert(sep != NULL); + + for (c = aoc.input; c < sep; c++) { + val = dvec_add_slot(phases, NULL); + *val = *c - '0'; + } +} + +void +fft(struct dvec *phases, size_t rounds) +{ + struct dvec copy; + size_t r, i, k, l; + ssize_t sum; + int digit; + int *val; + + dvec_init(&copy, sizeof(int), 0, &stdlib_strict_heap_allocator); + + for (r = 0; r < rounds; r++) { + dvec_copy(&copy, phases); + + for (i = 0; i < copy.len; i++) { + sum = 0; + for (k = 0; k < copy.len; k++) { + l = (k + 1) / (i + 1); + digit = *(int *)dvec_at(&copy, k); + sum += freq[l % 4] * digit; + } + sum = ABS(sum) % 10; + val = dvec_at(phases, i); + *val = (int) sum; + } + } + + dvec_deinit(&copy); +} + +void +fft_dup(struct dvec *phases, size_t offset, size_t rounds, size_t dup) +{ + size_t r, i, len, lutlen; + int *lut, *lutc, *lutp; + int digit, *slot; + + /* | a b c + * --+------------------------ + * 1 | a+b+c b+c c + * 2 | a+2b+3c b+2c c + * n |a+nb+n(n+1)/2c b+nc c + * + * a+sum(1)b+sum(sum(1))c .. not nice + * + * sum(1): n + * sum(sum(1)): n(n+1)/2 + * sum(sum(sum(1))): (K2+K1)/2 = (n^2+n)/2 + (n^3-n)/6 + * + * .. calculation possible but not practically feasible since we + * would have to do 10000..th sum() .. will have to use a lookup table + */ + + len = phases->len * dup; + assert(offset >= len / 2 && offset < len); + + lutlen = len - offset; + lut = malloc(lutlen * sizeof(int) * (rounds + 1)); + assert(lut != NULL); + + /* top row */ + for (i = 0; i < lutlen; i++) { + digit = *(int *)dvec_at(phases, (i + offset) % phases->len); + lut[i] = digit; + } + + /* right column */ + digit = *(int *)dvec_at(phases, (len - 1) % phases->len); + for (r = 0; r < rounds; r++) { + lut[(r + 1) * lutlen + lutlen - 1] = digit; + } + + for (r = 0; r < rounds; r++) { + lutp = &lut[r * lutlen + lutlen - 2]; + lutc = &lut[(r + 1) * lutlen + lutlen - 2]; + for (i = 1; i < lutlen; i++, lutp--, lutc--) + lutc[0] = (lutp[0] + lutc[1]) % 10; + } + + dvec_clear(phases); + for (i = 0; i < 8; i++) { + slot = dvec_add_slot(phases, NULL); + *slot = lut[rounds * lutlen + i]; + } + + free(lut); +} + +void +part1(void) +{ + struct dvec phases; + char *answer; + size_t i; + int digit; + + dvec_init(&phases, sizeof(int), 64, &stdlib_strict_heap_allocator); + + parse_input(&phases); + + fft(&phases, 100); + + answer = malloc(9); + for (i = 0; i < 8; i++) { + digit = *(int *)dvec_at(&phases, i); + answer[i] = '0' + (char) digit; + } + answer[i] = 0; + + aoc.answer = answer; + aoc.solution = "29956495"; + + dvec_deinit(&phases); +} + +void +part2(void) +{ + struct dvec phases; + char *answer; + int digit; + size_t offset; + size_t base; + size_t i; + + dvec_init(&phases, sizeof(int), 64, &stdlib_strict_heap_allocator); + + parse_input(&phases); + + base = 1; + offset = 0; + for (i = 0; i < 7; i++) { + digit = *(int *)dvec_at(&phases, 6 - i); + offset += base * (size_t) digit; + base *= 10; + } + + fft_dup(&phases, offset, 100, 10000); + + answer = malloc(9); + for (i = 0; i < 8; i++) { + digit = *(int *)dvec_at(&phases, i); + answer[i] = '0' + (char) digit; + } + answer[i] = 0; + + aoc.answer = answer; + aoc.solution = ""; + + dvec_deinit(&phases); +} diff --git a/16/part1 b/16/part1 @@ -0,0 +1,95 @@ +--- Day 16: Flawed Frequency Transmission --- + +You're 3/4ths of the way through the gas giants. Not only do roundtrip signals to Earth take five +hours, but the signal quality is quite bad as well. You can clean up the signal with the Flawed +Frequency Transmission algorithm, or FFT. + +As input, FFT takes a list of numbers. In the signal you received (your puzzle input), each number +is a single digit: data like 15243 represents the sequence 1, 5, 2, 4, 3. + +FFT operates in repeated phases. In each phase, a new list is constructed with the same length as +the input list. This new list is also used as the input for the next phase. + +Each element in the new list is built by multiplying every value in the input list by a value in a +repeating pattern and then adding up the results. So, if the input list were 9, 8, 7, 6, 5 and the +pattern for a given element were 1, 2, 3, the result would be 9*1 + 8*2 + 7*3 + 6*1 + 5*2 (with each +input element on the left and each value in the repeating pattern on the right of each +multiplication). Then, only the ones digit is kept: 38 becomes 8, -17 becomes 7, and so on. + +While each element in the output array uses all of the same input array elements, the actual +repeating pattern to use depends on which output element is being calculated. The base pattern is 0, +1, 0, -1. Then, repeat each value in the pattern a number of times equal to the position in the +output list being considered. Repeat once for the first element, twice for the second element, three +times for the third element, and so on. So, if the third element of the output list is being +calculated, repeating the values would produce: 0, 0, 0, 1, 1, 1, 0, 0, 0, -1, -1, -1. + +When applying the pattern, skip the very first value exactly once. (In other words, offset the whole +pattern left by one.) So, for the second element of the output list, the actual pattern used would +be: 0, 1, 1, 0, 0, -1, -1, 0, 0, 1, 1, 0, 0, -1, -1, .... + +After using this process to calculate each element of the output list, the phase is complete, and +the output list of this phase is used as the new input list for the next phase, if any. + +Given the input signal 12345678, below are four phases of FFT. Within each phase, each output digit +is calculated on a single line with the result at the far right; each multiplication operation shows +the input digit on the left and the pattern value on the right: + +Input signal: 12345678 + +1*1 + 2*0 + 3*-1 + 4*0 + 5*1 + 6*0 + 7*-1 + 8*0 = 4 +1*0 + 2*1 + 3*1 + 4*0 + 5*0 + 6*-1 + 7*-1 + 8*0 = 8 +1*0 + 2*0 + 3*1 + 4*1 + 5*1 + 6*0 + 7*0 + 8*0 = 2 +1*0 + 2*0 + 3*0 + 4*1 + 5*1 + 6*1 + 7*1 + 8*0 = 2 +1*0 + 2*0 + 3*0 + 4*0 + 5*1 + 6*1 + 7*1 + 8*1 = 6 +1*0 + 2*0 + 3*0 + 4*0 + 5*0 + 6*1 + 7*1 + 8*1 = 1 +1*0 + 2*0 + 3*0 + 4*0 + 5*0 + 6*0 + 7*1 + 8*1 = 5 +1*0 + 2*0 + 3*0 + 4*0 + 5*0 + 6*0 + 7*0 + 8*1 = 8 + +After 1 phase: 48226158 + +4*1 + 8*0 + 2*-1 + 2*0 + 6*1 + 1*0 + 5*-1 + 8*0 = 3 +4*0 + 8*1 + 2*1 + 2*0 + 6*0 + 1*-1 + 5*-1 + 8*0 = 4 +4*0 + 8*0 + 2*1 + 2*1 + 6*1 + 1*0 + 5*0 + 8*0 = 0 +4*0 + 8*0 + 2*0 + 2*1 + 6*1 + 1*1 + 5*1 + 8*0 = 4 +4*0 + 8*0 + 2*0 + 2*0 + 6*1 + 1*1 + 5*1 + 8*1 = 0 +4*0 + 8*0 + 2*0 + 2*0 + 6*0 + 1*1 + 5*1 + 8*1 = 4 +4*0 + 8*0 + 2*0 + 2*0 + 6*0 + 1*0 + 5*1 + 8*1 = 3 +4*0 + 8*0 + 2*0 + 2*0 + 6*0 + 1*0 + 5*0 + 8*1 = 8 + +After 2 phases: 34040438 + +3*1 + 4*0 + 0*-1 + 4*0 + 0*1 + 4*0 + 3*-1 + 8*0 = 0 +3*0 + 4*1 + 0*1 + 4*0 + 0*0 + 4*-1 + 3*-1 + 8*0 = 3 +3*0 + 4*0 + 0*1 + 4*1 + 0*1 + 4*0 + 3*0 + 8*0 = 4 +3*0 + 4*0 + 0*0 + 4*1 + 0*1 + 4*1 + 3*1 + 8*0 = 1 +3*0 + 4*0 + 0*0 + 4*0 + 0*1 + 4*1 + 3*1 + 8*1 = 5 +3*0 + 4*0 + 0*0 + 4*0 + 0*0 + 4*1 + 3*1 + 8*1 = 5 +3*0 + 4*0 + 0*0 + 4*0 + 0*0 + 4*0 + 3*1 + 8*1 = 1 +3*0 + 4*0 + 0*0 + 4*0 + 0*0 + 4*0 + 3*0 + 8*1 = 8 + +After 3 phases: 03415518 + +0*1 + 3*0 + 4*-1 + 1*0 + 5*1 + 5*0 + 1*-1 + 8*0 = 0 +0*0 + 3*1 + 4*1 + 1*0 + 5*0 + 5*-1 + 1*-1 + 8*0 = 1 +0*0 + 3*0 + 4*1 + 1*1 + 5*1 + 5*0 + 1*0 + 8*0 = 0 +0*0 + 3*0 + 4*0 + 1*1 + 5*1 + 5*1 + 1*1 + 8*0 = 2 +0*0 + 3*0 + 4*0 + 1*0 + 5*1 + 5*1 + 1*1 + 8*1 = 9 +0*0 + 3*0 + 4*0 + 1*0 + 5*0 + 5*1 + 1*1 + 8*1 = 4 +0*0 + 3*0 + 4*0 + 1*0 + 5*0 + 5*0 + 1*1 + 8*1 = 9 +0*0 + 3*0 + 4*0 + 1*0 + 5*0 + 5*0 + 1*0 + 8*1 = 8 + +After 4 phases: 01029498 + +Here are the first eight digits of the final output list after 100 phases for some larger inputs: + + + - 80871224585914546619083218645595 becomes 24176176. + + - 19617804207202209144916044189917 becomes 73745418. + + - 69317163492948606335995924319873 becomes 52432133. + + +After 100 phases of FFT, what are the first eight digits in the final output list? + + diff --git a/16/part2 b/16/part2 @@ -0,0 +1,32 @@ +--- Part Two --- + +Now that your FFT is working, you can decode the real signal. + +The real signal is your puzzle input repeated 10000 times. Treat this new signal as a single input +list. Patterns are still calculated as before, and 100 phases of FFT are still applied. + +The first seven digits of your initial input signal also represent the message offset. The message +offset is the location of the eight-digit message in the final output list. Specifically, the +message offset indicates the number of digits to skip before reading the eight-digit message. For +example, if the first seven digits of your initial input signal were 1234567, the eight-digit +message would be the eight digits after skipping 1,234,567 digits of the final output list. Or, if +the message offset were 7 and your final output list were 98765432109876543210, the eight-digit +message would be 21098765. (Of course, your real message offset will be a seven-digit number, not a +one-digit number like 7.) + +Here is the eight-digit message in the final output list after 100 phases. The message offset given +in each input has been highlighted. (Note that the inputs given below are repeated 10000 times to +find the actual starting input lists.) + + + - 03036732577212944063491565474664 becomes 84462026. + + - 02935109699940807407585447034323 becomes 78725270. + + - 03081770884921959731165446850517 becomes 53553731. + + +After repeating your input signal 10000 times and running 100 phases of FFT, what is the eight-digit +message embedded in the final output list? + + diff --git a/16/test1 b/16/test1 @@ -0,0 +1 @@ +80871224585914546619083218645595 diff --git a/16/test2 b/16/test2 @@ -0,0 +1 @@ +03036732577212944063491565474664