aoc-2019-c

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

commit 9c4f72ce260acc6398632cd9e396a54b0e494151
parent 49318906acb244e5ca4038d75ff383941efef9d4
Author: Louis Burda <quent.burda@gmail.com>
Date:   Mon,  3 Apr 2023 10:19:35 -0400

Add day 22

Diffstat:
A22/info.mk | 3+++
A22/input | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A22/part1 | 166+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A22/part1.c | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A22/part2 | 22++++++++++++++++++++++
A22/part2.c | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A22/test1 | 3+++
A22/test2 | 3+++
A22/test3 | 3+++
A22/test4 | 10++++++++++
A22/test5 | 6++++++
11 files changed, 547 insertions(+), 0 deletions(-)

diff --git a/22/info.mk b/22/info.mk @@ -0,0 +1,3 @@ +22_SRC = 22/part1.c 22/part2.c common/main.c common/aoc.c common/util.c +22_SRC += lib/liballoc/build/liballoc.a lib/libdvec/build/libdvec.a +22_HDR = common/aoc.h common/util.h diff --git a/22/input b/22/input @@ -0,0 +1,101 @@ +deal with increment 13 +cut 5485 +deal with increment 50 +cut 9877 +deal with increment 8 +cut 4323 +deal with increment 6 +cut 2478 +deal with increment 32 +cut 299 +deal with increment 72 +cut 5108 +deal with increment 10 +cut -1774 +deal with increment 24 +cut -8840 +deal with increment 34 +cut 7488 +deal with increment 74 +cut 1851 +deal into new stack +deal with increment 60 +cut -6016 +deal into new stack +deal with increment 49 +cut -8082 +deal with increment 54 +deal into new stack +deal with increment 15 +deal into new stack +deal with increment 38 +cut -4112 +deal with increment 13 +deal into new stack +cut 4372 +deal into new stack +deal with increment 75 +cut -5702 +deal with increment 65 +cut 4979 +deal with increment 39 +cut 1967 +deal with increment 55 +cut 8554 +deal with increment 50 +deal into new stack +cut 1337 +deal with increment 53 +cut 426 +deal with increment 7 +cut 8947 +deal with increment 58 +cut 8826 +deal with increment 52 +cut 6167 +deal with increment 18 +cut -4305 +deal with increment 20 +cut 7168 +deal with increment 10 +cut 422 +deal with increment 41 +cut -1601 +deal with increment 72 +deal into new stack +deal with increment 27 +cut -3921 +deal with increment 47 +cut 4024 +deal into new stack +cut 7800 +deal with increment 10 +cut -3742 +deal with increment 35 +deal into new stack +deal with increment 72 +cut 7456 +deal with increment 29 +cut -6731 +deal with increment 57 +cut -6162 +deal into new stack +deal with increment 26 +cut -4817 +deal with increment 48 +cut 9420 +deal into new stack +deal with increment 8 +cut -7408 +deal into new stack +cut -3479 +deal with increment 31 +cut 5246 +deal with increment 12 +cut -9275 +deal with increment 37 +cut -4512 +deal with increment 15 +cut -8511 +deal with increment 8 + diff --git a/22/part1 b/22/part1 @@ -0,0 +1,166 @@ +--- Day 22: Slam Shuffle --- + +There isn't much to do while you wait for the droids to repair your ship. At least you're drifting +in the right direction. You decide to practice a new card shuffle you've been working on. + +Digging through the ship's storage, you find a deck of space cards! Just like any deck of space +cards, there are 10007 cards in the deck numbered 0 through 10006. The deck must be new - they're +still in factory order, with 0 on the top, then 1, then 2, and so on, all the way through to 10006 +on the bottom. + +You've been practicing three different techniques that you use while shuffling. Suppose you have a +deck of only 10 cards (numbered 0 through 9): + +To deal into new stack, create a new stack of cards by dealing the top card of the deck onto the top +of the new stack repeatedly until you run out of cards: + +Top Bottom +0 1 2 3 4 5 6 7 8 9 Your deck + New stack + + 1 2 3 4 5 6 7 8 9 Your deck + 0 New stack + + 2 3 4 5 6 7 8 9 Your deck + 1 0 New stack + + 3 4 5 6 7 8 9 Your deck + 2 1 0 New stack + +Several steps later... + + 9 Your deck + 8 7 6 5 4 3 2 1 0 New stack + + Your deck +9 8 7 6 5 4 3 2 1 0 New stack + +Finally, pick up the new stack you've just created and use it as the deck for the next technique. + +To cut N cards, take the top N cards off the top of the deck and move them as a single unit to the +bottom of the deck, retaining their order. For example, to cut 3: + +Top Bottom +0 1 2 3 4 5 6 7 8 9 Your deck + + 3 4 5 6 7 8 9 Your deck +0 1 2 Cut cards + +3 4 5 6 7 8 9 Your deck + 0 1 2 Cut cards + +3 4 5 6 7 8 9 0 1 2 Your deck + +You've also been getting pretty good at a version of this technique where N is negative! In that +case, cut (the absolute value of) N cards from the bottom of the deck onto the top. For example, to +cut -4: + +Top Bottom +0 1 2 3 4 5 6 7 8 9 Your deck + +0 1 2 3 4 5 Your deck + 6 7 8 9 Cut cards + + 0 1 2 3 4 5 Your deck +6 7 8 9 Cut cards + +6 7 8 9 0 1 2 3 4 5 Your deck + +To deal with increment N, start by clearing enough space on your table to lay out all of the cards +individually in a long line. Deal the top card into the leftmost position. Then, move N positions +to the right and deal the next card there. If you would move into a position past the end of the +space on your table, wrap around and keep counting from the leftmost card again. Continue this +process until you run out of cards. + +For example, to deal with increment 3: + + +0 1 2 3 4 5 6 7 8 9 Your deck +. . . . . . . . . . Space on table +^ Current position + +Deal the top card to the current position: + + 1 2 3 4 5 6 7 8 9 Your deck +0 . . . . . . . . . Space on table +^ Current position + +Move the current position right 3: + + 1 2 3 4 5 6 7 8 9 Your deck +0 . . . . . . . . . Space on table + ^ Current position + +Deal the top card: + + 2 3 4 5 6 7 8 9 Your deck +0 . . 1 . . . . . . Space on table + ^ Current position + +Move right 3 and deal: + + 3 4 5 6 7 8 9 Your deck +0 . . 1 . . 2 . . . Space on table + ^ Current position + +Move right 3 and deal: + + 4 5 6 7 8 9 Your deck +0 . . 1 . . 2 . . 3 Space on table + ^ Current position + +Move right 3, wrapping around, and deal: + + 5 6 7 8 9 Your deck +0 . 4 1 . . 2 . . 3 Space on table + ^ Current position + +And so on: + +0 7 4 1 8 5 2 9 6 3 Space on table + +Positions on the table which already contain cards are still counted; they're not skipped. Of +course, this technique is carefully designed so it will never put two cards in the same position or +leave a position empty. + +Finally, collect the cards on the table so that the leftmost card ends up at the top of your deck, +the card to its right ends up just below the top card, and so on, until the rightmost card ends up +at the bottom of the deck. + +The complete shuffle process (your puzzle input) consists of applying many of these techniques. +Here are some examples that combine techniques; they all start with a factory order deck of 10 +cards: + +deal with increment 7 +deal into new stack +deal into new stack +Result: 0 3 6 9 2 5 8 1 4 7 + +cut 6 +deal with increment 7 +deal into new stack +Result: 3 0 7 4 1 8 5 2 9 6 + +deal with increment 7 +deal with increment 9 +cut -2 +Result: 6 3 0 7 4 1 8 5 2 9 + +deal into new stack +cut -2 +deal with increment 7 +cut 8 +cut -4 +deal with increment 7 +cut 3 +deal with increment 9 +deal with increment 3 +cut -1 +Result: 9 2 5 8 1 4 7 0 3 6 + +Positions within the deck count from 0 at the top, then 1 for the card immediately below the top +card, and so on to the bottom. (That is, cards start in the position matching their number.) + +After shuffling your factory order deck of 10007 cards, what is the position of card 2019? + + diff --git a/22/part1.c b/22/part1.c @@ -0,0 +1,130 @@ +#include "allocator.h" +#include "aoc.h" +#include "dvec_s.h" +#include "util.h" + +#include <assert.h> +#include <stdlib.h> + +static void +deck_cut(struct dvec *deck, struct dvec *table, ssize_t in) +{ + int *src, *dst; + size_t i, split, n; + + n = deck->len; + split = in < 0 ? (size_t) ((ssize_t) deck->len + in) : (size_t) in; + src = deck->data; + dst = table->data; + + for (i = 0; i < split; i++) + dst[i + n - split] = src[i]; + for (i = split; i < n; i++) + dst[i - split] = src[i]; + + dvec_swap(deck, table); +} + +static void +deal_increment(struct dvec *deck, struct dvec *table, size_t inc) +{ + int *src, *dst; + size_t i, n, p; + + n = deck->len; + src = deck->data; + dst = table->data; + + p = 0; + for (i = 0; i < n; i++) { + dst[p] = src[i]; + p = (p + inc) % n; + } + + dvec_swap(deck, table); +} + +static void +deal_new_stack(struct dvec *deck, struct dvec *table) +{ + int *src, *dst; + size_t i, n; + + n = deck->len - 1; + src = deck->data; + dst = table->data; + + for (i = 0; i <= n; i++) + dst[n - i] = src[i]; + + dvec_swap(deck, table); +} + +static size_t +find_card(struct dvec *deck, int card) +{ + int *data; + size_t i, n; + + n = deck->len; + data = deck->data; + for (i = 0; i < n; i++) { + if (data[i] == card) + return i; + } + return 0; +} + +void +part1(void) +{ + char line[256]; + const char *lpos, *lend; + struct dvec deck, table; + size_t i, count; + size_t answer; + ssize_t val; + int target; + int *data; + + if (!strcmp(aoc.inputfile, "input")) { + count = 10007; + target = 2019; + } else { + count = 10; + target = 9; + } + + dvec_init(&deck, sizeof(int), count, &stdlib_strict_heap_allocator); + dvec_init(&table, sizeof(int), count, &stdlib_strict_heap_allocator); + + dvec_add_slots(&deck, count); + dvec_add_slots(&table, count); + data = deck.data; + for (i = 0; i < count; i++) + data[i] = (int) i; + + lpos = aoc.input; + lend = lpos + aoc.input_size; + while (readtok(line, sizeof(line), '\n', &lpos, lend)) { + if (sscanf(line, "deal with increment %li", &val) == 1) { + deal_increment(&deck, &table, (size_t) val); + } else if (sscanf(line, "cut %li", &val) == 1) { + deck_cut(&deck, &table, val); + } else if (!strcmp(line, "deal into new stack")) { + deal_new_stack(&deck, &table); + } else if (strspn(line, " \n\r\t\v") == strlen(line)) { + continue; + } else { + assert(false); + } + aoc_debug("%i pos: %lu\n", target, find_card(&deck, target)); + } + + answer = find_card(&deck, target); + aoc.answer = aprintf("%lu", answer); + aoc.solution = "7171"; + + dvec_deinit(&table); + dvec_deinit(&deck); +} diff --git a/22/part2 b/22/part2 @@ -0,0 +1,22 @@ +--- Part Two --- + +After a while, you realize your shuffling skill won't improve much more with merely a single deck of +cards. You ask every 3D printer on the ship to make you some more cards while you check on the ship +repairs. While reviewing the work the droids have finished so far, you think you see Halley's Comet +fly past! + +When you get back, you discover that the 3D printers have combined their power to create for you a +single, giant, brand new, factory order deck of 119315717514047 space cards. + +Finally, a deck of cards worthy of shuffling! + +You decide to apply your complete shuffle process (your puzzle input) to the deck 101741582076661 +times in a row. + +You'll need to be careful, though - one wrong move with this many cards and you might overflow your +entire ship! + +After shuffling your new, giant, factory order deck that many times, what number is on the card that +ends up in position 2020? + + diff --git a/22/part2.c b/22/part2.c @@ -0,0 +1,100 @@ +#include "allocator.h" +#include "aoc.h" +#include "dvec_s.h" +#include "util.h" + +#include <assert.h> +#include <stddef.h> +#include <stdlib.h> + +size_t +imul(size_t a, size_t b, size_t n) +{ + size_t i, out; + + out = 0; + for (i = 0; i < sizeof(size_t) * 8; i++, b <<= 1) { + out = (2 * out) % n; + if (b & (1ULL << 63)) + out = (out + a) % n; + } + + return out; +} + +size_t +ipow(size_t a, size_t b, size_t n) +{ + size_t i, out; + + out = 1; + for (i = 0; i < sizeof(size_t) * 8; i++, b <<= 1) { + out = imul(out, out, n); + if (b & (1ULL << 63)) + out = imul(out, a, n); + } + + return out; +} + +size_t +modinv(size_t a, size_t n) +{ + return ipow(a, n - 2, n); +} + +void +part2(void) +{ + char line[256]; + const char *lpos, *lend; + size_t answer; + size_t count; + size_t times; + size_t target; + ssize_t sval; + size_t mul, off; + size_t _mul, _off; + size_t val; + + times = 101741582076661; + count = 119315717514047; + target = 2020; + + /* reduce operations to a single multiplication and + * addition under modulus 'count' */ + mul = 1; + off = 0; + lpos = aoc.input; + lend = lpos + aoc.input_size; + while (readtok(line, sizeof(line), '\n', &lpos, lend)) { + if (sscanf(line, "deal with increment %lu", &val) == 1) { + /* multiplication : pos = val * pos */ + _mul = val; + _off = 0; + } else if (sscanf(line, "cut %li", &sval) == 1) { + /* addition : pos = pos + val */ + _mul = 1; + _off = ((size_t) ((ssize_t) count - sval)) % count; + } else if (!strcmp(line, "deal into new stack")) { + /* invert : pos = - pos + n - 1 */ + _mul = count - 1; + _off = count - 1; + } else if (strspn(line, " \n\r\t\v") == strlen(line)) { + continue; + } else { + assert(false); + } + mul = imul(mul, _mul, count); + off = (imul(off, _mul, count) + _off) % count; + } + + /* apply multiplication and addition 'times' times.. */ + val = (ipow(mul, times, count) + count - 1) % count; + val = imul(val, modinv(mul + count - 1, count), count); + off = imul(off, val, count); /* b' = b * ((a^n - 1) / (a - 1)) */ + mul = ipow(mul, times, count); /* a' = a^n */ + + answer = imul((target + count - off) % count, modinv(mul, count), count); + aoc.answer = aprintf("%lu", answer); +} diff --git a/22/test1 b/22/test1 @@ -0,0 +1,3 @@ +deal with increment 7 +deal into new stack +deal into new stack diff --git a/22/test2 b/22/test2 @@ -0,0 +1,3 @@ +cut 6 +deal with increment 7 +deal into new stack diff --git a/22/test3 b/22/test3 @@ -0,0 +1,3 @@ +deal with increment 7 +deal with increment 9 +cut -2 diff --git a/22/test4 b/22/test4 @@ -0,0 +1,10 @@ +deal into new stack +cut -2 +deal with increment 7 +cut 8 +cut -4 +deal with increment 7 +cut 3 +deal with increment 9 +deal with increment 3 +cut -1 diff --git a/22/test5 b/22/test5 @@ -0,0 +1,6 @@ +cut 6 +deal with increment 7 +deal into new stack +cut 6 +deal with increment 7 +deal into new stack