diff --git a/src/day17/solve.c b/src/day17/solve.c index c30ae31..8a6a533 100644 --- a/src/day17/solve.c +++ b/src/day17/solve.c @@ -122,6 +122,61 @@ static inline int find_neighbors(int rows, int cols, Node current, Node *neighbo return count; } +static inline int find_neighbors_part2(int rows, int cols, Node current, Node *neighbor) { + 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: + if (current.direction_count >= 4) { + add_node(rows, cols, north, neighbor, &count); + add_node(rows, cols, south, neighbor, &count); + } else if (current.direction_count < 10) { + east.direction_count = current.direction_count + 1; + add_node(rows, cols, east, neighbor, &count); + } + break; + case WEST: + if (current.direction_count >= 4) { + add_node(rows, cols, north, neighbor, &count); + add_node(rows, cols, south, neighbor, &count); + } else if (current.direction_count < 10) { + west.direction_count = current.direction_count + 1; + add_node(rows, cols, west, neighbor, &count); + } + break; + case SOUTH: + if (current.direction_count >= 4) { + add_node(rows, cols, west, neighbor, &count); + add_node(rows, cols, east, neighbor, &count); + } else if (current.direction_count < 10) { + south.direction_count = current.direction_count + 1; + add_node(rows, cols, south, neighbor, &count); + } + break; + case NORTH: + if (current.direction_count >= 4) { + add_node(rows, cols, west, neighbor, &count); + add_node(rows, cols, east, neighbor, &count); + } else if (current.direction_count < 10) { + 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; @@ -145,47 +200,99 @@ void solve(char *buf, size_t buf_size, Solution *result) { 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}); + // Dijkstra part 1 + { + _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}); + _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); + // 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; + 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}); + } } + } + + // Dijkstra part 2 + { + _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) && current.node.direction_count >= 4) { + log_debug("found destination %d,%d: %d", current.node.position.y, current.node.position.x, + current.dist); + part2 = current.dist; + break; + } + + Node neighbor[3]; + int neighbor_count = find_neighbors_part2(rows, cols, current.node, neighbor); - 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; + 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); } - } 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}); } - 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}); } } diff --git a/src/day17/solve_test.c b/src/day17/solve_test.c index e74f12a..19ffed8 100644 --- a/src/day17/solve_test.c +++ b/src/day17/solve_test.c @@ -28,7 +28,7 @@ CTEST(day17, example) { Solution solution; solve(buf, strlen(buf), &solution); ASSERT_STR("102", solution.part1); - // ASSERT_STR("0", solution.part2); + ASSERT_STR("94", solution.part2); } #ifdef HAVE_INPUTS