From d7aebf5784397ba85819dfbb855e56dfed1be33b Mon Sep 17 00:00:00 2001 From: Michael Adler Date: Wed, 20 Dec 2023 18:11:06 +0100 Subject: [PATCH] Day 17, Part 1 --- input/day17.txt | Bin 0 -> 20044 bytes meson.build | 1 + puzzle/day17.md | 112 ++++++++++++++++++++++ src/day17/solve.c | 205 +++++++++++++++++++++++++++++++++++++++++ src/day17/solve_test.c | 43 +++++++++ 5 files changed, 361 insertions(+) create mode 100644 input/day17.txt create mode 100644 puzzle/day17.md create mode 100644 src/day17/solve.c create mode 100644 src/day17/solve_test.c diff --git a/input/day17.txt b/input/day17.txt new file mode 100644 index 0000000000000000000000000000000000000000..82073aad001f1c89c8916fe5b4724971eeb8a590 GIT binary patch literal 20044 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 literal 0 HcmV?d00001 diff --git a/meson.build b/meson.build index 14c638b..d49f603 100644 --- a/meson.build +++ b/meson.build @@ -48,6 +48,7 @@ days = { 'day14': [ 'src/day14/solve.c' ], 'day15': [ 'src/day15/solve.c' ], 'day16': [ 'src/day16/solve.c' ], + 'day17': [ 'src/day17/solve.c' ], # XXX: marker } diff --git a/puzzle/day17.md b/puzzle/day17.md new file mode 100644 index 0000000..5535aea --- /dev/null +++ b/puzzle/day17.md @@ -0,0 +1,112 @@ + +--- Day 17: Clumsy Crucible --- + +The lava starts flowing rapidly once the Lava Production Facility is operational. As you leave, the reindeer offers you a parachute, allowing you to quickly reach Gear Island. + +As you descend, your bird's-eye view of Gear Island reveals why you had trouble finding anyone on your way up: half of Gear Island is empty, but the half below you is a giant factory city! + +You land near the gradually-filling pool of lava at the base of your new lavafall. Lavaducts will eventually carry the lava throughout the city, but to make use of it immediately, Elves are loading it into large crucibles on wheels. + +The crucibles are top-heavy and pushed by hand. Unfortunately, the crucibles become very difficult to steer at high speeds, and so it can be hard to go in a straight line for very long. + +To get Desert Island the machine parts it needs as soon as possible, you'll need to find the best way to get the crucible from the lava pool to the machine parts factory. To do this, you need to minimize heat loss while choosing a route that doesn't require the crucible to go in a straight line for too long. + +Fortunately, the Elves here have a map (your puzzle input) that uses traffic patterns, ambient temperature, and hundreds of other parameters to calculate exactly how much heat loss can be expected for a crucible entering any particular city block. + +For example: + +2413432311323 +3215453535623 +3255245654254 +3446585845452 +4546657867536 +1438598798454 +4457876987766 +3637877979653 +4654967986887 +4564679986453 +1224686865563 +2546548887735 +4322674655533 + +Each city block is marked by a single digit that represents the amount of heat loss if the crucible enters that block. The starting point, the lava pool, is the top-left city block; the destination, the machine parts factory, is the bottom-right city block. (Because you already start in the top-left block, you don't incur that block's heat loss unless you leave +that block and then return to it.) + +Because it is difficult to keep the top-heavy crucible going in a straight line for very long, it can move at most three blocks in a single direction before it must turn 90 degrees left or right. The crucible also can't reverse direction; after entering each city block, it may only turn left, continue straight, or turn right. + +One way to minimize heat loss is this path: + +2>>34^>>>1323 +32v>>>35v5623 +32552456v>>54 +3446585845v52 +4546657867v>6 +14385987984v4 +44578769877v6 +36378779796v> +465496798688v +456467998645v +12246868655 + +This path never moves more than three consecutive blocks in the same direction and incurs a heat loss of only 102. + +Directing the crucible from the lava pool to the machine parts factory, but not moving more than three consecutive blocks in the same direction, what is the least heat loss it can incur? + +Your puzzle answer was 861. + +The first half of this puzzle is complete! It provides one gold star: * + +--- Part Two --- + +The crucibles of lava simply aren't large enough to provide an adequate supply of lava to the machine parts factory. Instead, the Elves are going to upgrade to ultra crucibles. + +Ultra crucibles are even more difficult to steer than normal crucibles. Not only do they have trouble going in a straight line, but they also have trouble turning! + +Once an ultra crucible starts moving in a direction, it needs to move a minimum of four blocks in that direction before it can turn (or even before it can stop at the end). However, it will eventually start to get wobbly: an ultra crucible can move a maximum of ten consecutive blocks without turning. + +In the above example, an ultra crucible could follow this path to minimize heat loss: + +2>>>>>>>>1323 +32154535v5623 +32552456v4254 +34465858v5452 +45466578v>>>> +143859879845v +445787698776v +363787797965v +465496798688v +456467998645v +122468686556v +254654888773v +432267465553v + +In the above example, an ultra crucible would incur the minimum possible heat loss of 94. + +Here's another example: + +111111111111 +999999999991 +999999999991 +999999999991 +999999999991 + +Sadly, an ultra crucible would need to take an unfortunate path like this one: + +1>>>>>>>1111 +9999999v9991 +9999999v9991 +9999999v9991 +9999999v>>>> + +This route causes the ultra crucible to incur the minimum possible heat loss of 71. + +Directing the ultra crucible from the lava pool to the machine parts factory, what is the least heat loss it can incur? + +Answer: + +Although it hasn't changed, you can still get your puzzle input. + +You can also [Shareon Twitter Mastodon] this puzzle. + diff --git a/src/day17/solve.c b/src/day17/solve.c new file mode 100644 index 0000000..c30ae31 --- /dev/null +++ b/src/day17/solve.c @@ -0,0 +1,205 @@ +/* + * Author: Michael Adler + * + * Copyright: 2023 Michael Adler + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "solve.h" +#include "aoc/all.h" + +#define GRID_SIZE 256 +#define INFINITY INT_MAX + +typedef enum { NORTH, EAST, SOUTH, WEST } direction_t; + +typedef struct { + Point2D position; + direction_t direction; // current direction + int direction_count; // how many times we went into the current direction +} Node; + +typedef struct { + Node node; + int dist; +} State; + +#define P +#define T State +#include + +typedef struct { + Node node; // key + int distance; // value +} NodeDistance; + +#define P +#define T NodeDistance +#include + +// min queue +static int State_compare(State *lhs, State *rhs) { return lhs->dist < rhs->dist; } + +static size_t Node_hash(Node *node) { + const size_t prime = 31; + size_t hash = 17; + // Combine the hash of each struct member + hash = hash * prime + (size_t)node->position.x; + hash = hash * prime + (size_t)node->position.y; + hash = hash * prime + (size_t)node->direction; + hash = hash * prime + (size_t)node->direction_count; + return hash; +} +static int Node_equal(Node *lhs, Node *rhs) { + return Point2D_equal(&lhs->position, &rhs->position) && lhs->direction == rhs->direction && + lhs->direction_count == rhs->direction_count; +} + +static size_t NodeDistance_hash(NodeDistance *item) { return Node_hash(&item->node); } + +static int NodeDistance_equal(NodeDistance *lhs, NodeDistance *rhs) { return Node_equal(&lhs->node, &rhs->node); } + +static inline void add_node(int rows, int cols, Node node, Node *arr, int *arr_len) { + if (node.position.x < 0 || node.position.x >= cols || node.position.y < 0 || node.position.y >= rows) { return; } + int count = *arr_len; + arr[count++] = node; + *arr_len = count; +} + +static inline int find_neighbors(int rows, int cols, Node current, Node *neighbor) { + bool must_turn = current.direction_count == 3; + log_debug(">> visiting %d,%d, must_turn: %d, dir: %d, dir_count: %d", current.position.y, current.position.x, + must_turn, current.direction, current.direction_count); + + int count = 0; + Node north = {.position = (Point2D){.x = current.position.x, .y = current.position.y - 1}, + .direction = NORTH, + .direction_count = 1}; + Node south = {.position = (Point2D){.x = current.position.x, .y = current.position.y + 1}, + .direction = SOUTH, + .direction_count = 1}; + Node east = {.position = (Point2D){.x = current.position.x + 1, .y = current.position.y}, + .direction = EAST, + .direction_count = 1}; + Node west = {.position = (Point2D){.x = current.position.x - 1, .y = current.position.y}, + .direction = WEST, + .direction_count = 1}; + switch (current.direction) { + case EAST: + add_node(rows, cols, north, neighbor, &count); + add_node(rows, cols, south, neighbor, &count); + if (!must_turn) { + east.direction_count = current.direction_count + 1; + add_node(rows, cols, east, neighbor, &count); + } + break; + case WEST: + add_node(rows, cols, north, neighbor, &count); + add_node(rows, cols, south, neighbor, &count); + if (!must_turn) { + west.direction_count = current.direction_count + 1; + add_node(rows, cols, west, neighbor, &count); + } + break; + case SOUTH: + add_node(rows, cols, west, neighbor, &count); + add_node(rows, cols, east, neighbor, &count); + if (!must_turn) { + south.direction_count = current.direction_count + 1; + add_node(rows, cols, south, neighbor, &count); + } + break; + case NORTH: + add_node(rows, cols, west, neighbor, &count); + add_node(rows, cols, east, neighbor, &count); + if (!must_turn) { + north.direction_count = current.direction_count + 1; + add_node(rows, cols, north, neighbor, &count); + } + break; + } + return count; +} + +void solve(char *buf, size_t buf_size, Solution *result) { + int part1 = 0, part2 = 0; + + int grid[GRID_SIZE][GRID_SIZE]; + int rows = 0, cols = 0; + + for (int pos = 0, x = 0; pos < (int)buf_size; pos++) { + char c = buf[pos]; + switch (c) { + case '\n': + cols = x; + x = 0; + rows++; + break; + default: grid[rows][x++] = c - '0'; break; + } + } + log_debug("rows: %d, cols: %d", rows, cols); + + Point2D start = {.x = 0, .y = 0}, dest = {.x = cols - 1, .y = rows - 1}; + Node start_node_1 = {.position = start, .direction = EAST, .direction_count = 0}; + Node start_node_2 = {.position = start, .direction = SOUTH, .direction_count = 0}; + + // Dijkstra + _cleanup_(pqu_State_free) pqu_State queue = pqu_State_init(State_compare); + pqu_State_push(&queue, (State){.node = start_node_1, .dist = 0}); + pqu_State_push(&queue, (State){.node = start_node_2, .dist = 0}); + + _cleanup_(ust_NodeDistance_free) ust_NodeDistance distances = + ust_NodeDistance_init(NodeDistance_hash, NodeDistance_equal); + ust_NodeDistance_insert(&distances, (NodeDistance){.node = start_node_1, .distance = 0}); + ust_NodeDistance_insert(&distances, (NodeDistance){.node = start_node_2, .distance = 0}); + + // dijkstra + while (!pqu_State_empty(&queue)) { + State current = *pqu_State_top(&queue); + pqu_State_pop(&queue); + + if (Point2D_equal(¤t.node.position, &dest)) { + log_debug("found destination %d,%d: %d", current.node.position.y, current.node.position.x, current.dist); + part1 = current.dist; + break; + } + + Node neighbor[3]; + int neighbor_count = find_neighbors(rows, cols, current.node, neighbor); + + for (int i = 0; i < neighbor_count; i++) { + Node nb = neighbor[i]; + int alt = current.dist + grid[nb.position.y][nb.position.x]; + NodeDistance node_distance = {.node = nb, .distance = alt}; + ust_NodeDistance_node *entry = ust_NodeDistance_find(&distances, node_distance); + if (entry != NULL) { + if (entry->key.distance <= alt) { + log_debug("discarding y,x %d,%d: current best %d is better than %d", nb.position.y, nb.position.x, + entry->key.distance, alt); + continue; + } + } else { + log_debug("entry %d,%d not found in map", node_distance.node.position.y, node_distance.node.position.x); + } + log_debug("inserting new best dist for y,x %d,%d: %d", nb.position.y, nb.position.x, alt); + ust_NodeDistance_insert(&distances, node_distance); + pqu_State_push(&queue, (State){.node = nb, .dist = alt}); + } + } + + aoc_itoa(part1, result->part1, 10); + aoc_itoa(part2, result->part2, 10); +} + +int solve_input(const char *fname, Solution *result) { + char buf[1 << 15]; + int n = aoc_io_read_input(fname, buf, sizeof(buf)); + if (n <= 0) { + fprintf(stderr, "Failed to read %s\n", fname); + return -1; + } + solve(buf, n, result); + return 0; +} diff --git a/src/day17/solve_test.c b/src/day17/solve_test.c new file mode 100644 index 0000000..e74f12a --- /dev/null +++ b/src/day17/solve_test.c @@ -0,0 +1,43 @@ +/* + * Author: Michael Adler + * + * Copyright: 2023 Michael Adler + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define CTEST_MAIN + +#include "ctest.h" +#include "solve.h" + +CTEST(day17, example) { + char *buf = "2413432311323\n\ +3215453535623\n\ +3255245654254\n\ +3446585845452\n\ +4546657867536\n\ +1438598798454\n\ +4457876987766\n\ +3637877979653\n\ +4654967986887\n\ +4564679986453\n\ +1224686865563\n\ +2546548887735\n\ +4322674655533\n"; + Solution solution; + solve(buf, strlen(buf), &solution); + ASSERT_STR("102", solution.part1); + // ASSERT_STR("0", solution.part2); +} + +#ifdef HAVE_INPUTS +CTEST(day17, real) { + Solution solution; + solve_input("input/" DAY ".txt", &solution); + ASSERT_STR("861", solution.part1); + // ASSERT_STR("0", solution.part2); +} +#endif + +int main(int argc, const char *argv[]) { return ctest_main(argc, argv); }