From befb71ed2253a7de21cecb59a48a3268d1b62d53 Mon Sep 17 00:00:00 2001 From: Bruno Raoult Date: Sun, 19 Dec 2021 14:59:52 +0100 Subject: [PATCH] day 15 part 1 --- 2021/day15/README.txt | 127 ++++++++++++++++++++++++ 2021/day15/aoc-c.c | 219 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 346 insertions(+) create mode 100644 2021/day15/aoc-c.c diff --git a/2021/day15/README.txt b/2021/day15/README.txt index 2f7f1a6..93c6b1b 100644 --- a/2021/day15/README.txt +++ b/2021/day15/README.txt @@ -33,3 +33,130 @@ Your goal is to find a path with the lowest total risk. In this example, a path The total risk of this path is 40 (the starting position is never entered, so its risk is not counted). What is the lowest total risk of any path from the top left to the bottom right? + +Your puzzle answer was 435. + +The first half of this puzzle is complete! It provides one gold star: * +--- Part Two --- + +Now that you know how to find low-risk paths in the cave, you can try to find your way out. + +The entire cave is actually five times larger in both dimensions than you thought; the area you originally scanned is just one tile in a 5x5 tile area that forms the full map. Your original map tile repeats to the right and downward; each time the tile repeats to the right or downward, all of its risk levels are 1 higher than the tile immediately up or left of it. However, risk levels above 9 wrap back around to 1. So, if your original map had some position with a risk level of 8, then that same position on each of the 25 total tiles would be as follows: + +8 9 1 2 3 +9 1 2 3 4 +1 2 3 4 5 +2 3 4 5 6 +3 4 5 6 7 + +Each single digit above corresponds to the example position with a value of 8 on the top-left tile. Because the full map is actually five times larger in both dimensions, that position appears a total of 25 times, once in each duplicated tile, with the values shown above. + +Here is the full five-times-as-large version of the first example above, with the original map in the top left corner highlighted: + +11637517422274862853338597396444961841755517295286 +13813736722492484783351359589446246169155735727126 +21365113283247622439435873354154698446526571955763 +36949315694715142671582625378269373648937148475914 +74634171118574528222968563933317967414442817852555 +13191281372421239248353234135946434524615754563572 +13599124212461123532357223464346833457545794456865 +31254216394236532741534764385264587549637569865174 +12931385212314249632342535174345364628545647573965 +23119445813422155692453326671356443778246755488935 +22748628533385973964449618417555172952866628316397 +24924847833513595894462461691557357271266846838237 +32476224394358733541546984465265719557637682166874 +47151426715826253782693736489371484759148259586125 +85745282229685639333179674144428178525553928963666 +24212392483532341359464345246157545635726865674683 +24611235323572234643468334575457944568656815567976 +42365327415347643852645875496375698651748671976285 +23142496323425351743453646285456475739656758684176 +34221556924533266713564437782467554889357866599146 +33859739644496184175551729528666283163977739427418 +35135958944624616915573572712668468382377957949348 +43587335415469844652657195576376821668748793277985 +58262537826937364893714847591482595861259361697236 +96856393331796741444281785255539289636664139174777 +35323413594643452461575456357268656746837976785794 +35722346434683345754579445686568155679767926678187 +53476438526458754963756986517486719762859782187396 +34253517434536462854564757396567586841767869795287 +45332667135644377824675548893578665991468977611257 +44961841755517295286662831639777394274188841538529 +46246169155735727126684683823779579493488168151459 +54698446526571955763768216687487932779859814388196 +69373648937148475914825958612593616972361472718347 +17967414442817852555392896366641391747775241285888 +46434524615754563572686567468379767857948187896815 +46833457545794456865681556797679266781878137789298 +64587549637569865174867197628597821873961893298417 +45364628545647573965675868417678697952878971816398 +56443778246755488935786659914689776112579188722368 +55172952866628316397773942741888415385299952649631 +57357271266846838237795794934881681514599279262561 +65719557637682166874879327798598143881961925499217 +71484759148259586125936169723614727183472583829458 +28178525553928963666413917477752412858886352396999 +57545635726865674683797678579481878968159298917926 +57944568656815567976792667818781377892989248891319 +75698651748671976285978218739618932984172914319528 +56475739656758684176786979528789718163989182927419 +67554889357866599146897761125791887223681299833479 + +Equipped with the full map, you can now find a path from the top left corner to the bottom right corner with the lowest total risk: + +11637517422274862853338597396444961841755517295286 +13813736722492484783351359589446246169155735727126 +21365113283247622439435873354154698446526571955763 +36949315694715142671582625378269373648937148475914 +74634171118574528222968563933317967414442817852555 +13191281372421239248353234135946434524615754563572 +13599124212461123532357223464346833457545794456865 +31254216394236532741534764385264587549637569865174 +12931385212314249632342535174345364628545647573965 +23119445813422155692453326671356443778246755488935 +22748628533385973964449618417555172952866628316397 +24924847833513595894462461691557357271266846838237 +32476224394358733541546984465265719557637682166874 +47151426715826253782693736489371484759148259586125 +85745282229685639333179674144428178525553928963666 +24212392483532341359464345246157545635726865674683 +24611235323572234643468334575457944568656815567976 +42365327415347643852645875496375698651748671976285 +23142496323425351743453646285456475739656758684176 +34221556924533266713564437782467554889357866599146 +33859739644496184175551729528666283163977739427418 +35135958944624616915573572712668468382377957949348 +43587335415469844652657195576376821668748793277985 +58262537826937364893714847591482595861259361697236 +96856393331796741444281785255539289636664139174777 +35323413594643452461575456357268656746837976785794 +35722346434683345754579445686568155679767926678187 +53476438526458754963756986517486719762859782187396 +34253517434536462854564757396567586841767869795287 +45332667135644377824675548893578665991468977611257 +44961841755517295286662831639777394274188841538529 +46246169155735727126684683823779579493488168151459 +54698446526571955763768216687487932779859814388196 +69373648937148475914825958612593616972361472718347 +17967414442817852555392896366641391747775241285888 +46434524615754563572686567468379767857948187896815 +46833457545794456865681556797679266781878137789298 +64587549637569865174867197628597821873961893298417 +45364628545647573965675868417678697952878971816398 +56443778246755488935786659914689776112579188722368 +55172952866628316397773942741888415385299952649631 +57357271266846838237795794934881681514599279262561 +65719557637682166874879327798598143881961925499217 +71484759148259586125936169723614727183472583829458 +28178525553928963666413917477752412858886352396999 +57545635726865674683797678579481878968159298917926 +57944568656815567976792667818781377892989248891319 +75698651748671976285978218739618932984172914319528 +56475739656758684176786979528789718163989182927419 +67554889357866599146897761125791887223681299833479 + +The total risk of this path is 315 (the starting position is still never entered, so its risk is not counted). + +Using the full map, what is the lowest total risk of any path from the top left to the bottom right? diff --git a/2021/day15/aoc-c.c b/2021/day15/aoc-c.c new file mode 100644 index 0000000..944676a --- /dev/null +++ b/2021/day15/aoc-c.c @@ -0,0 +1,219 @@ +/* aoc-c.c: Advent of Code 2021, day 15 parts 1 & 2 + * + * Copyright (C) 2021 Bruno Raoult ("br") + * Licensed under the GNU General Public License v3.0 or later. + * Some rights reserved. See COPYING. + * + * You should have received a copy of the GNU General Public License along with this + * program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "pool.h" +#include "bits.h" +#include "list.h" + +#define MAX_SIZE 128 + +int a[] = { + ['a'] = 0, + ['b'] = 1, + ['c'] = 2 +}; + +typedef struct square { + uchar cost; + u32 totcost;; + uchar visited; +} square_t; + +typedef struct priority_queue { + int l; + int c; + u32 cost; + struct list_head list; +} pqueue_t; + +static LIST_HEAD(plist_head); +static struct square array[MAX_SIZE][MAX_SIZE]; +static int asize; +static pool_t *pool; + +#define VALID(x, y) ((x) >= 0 && (x) < size && (y) >= 0 && (y) < size ) + +static void print_array() +{ + log(3, "array (%dx%d):\n", asize, asize); + for (int i = 0; i < asize; ++i) { + for (int j = 0; j < asize; ++j) + log(3, "%1d/%2d ", array[i][j].cost, array[i][j].totcost); + log(3, "\n"); + } +} + +static void print_queue() +{ + log(3, "queue:\n", asize, asize); + pqueue_t *tmp; + int i = 1; + + list_for_each_entry(tmp, &plist_head, list) { + int l = tmp->l, c = tmp->c; + u32 cost = array[l][c].cost; + u32 acc = array[l][c].totcost; + log(3, "%d: (%d,%d): cost=%u acc=%lu\n", i, l, c, cost, acc); + i++; + } +} + +/* insert l,c in queue, keeping cost sorted */ +static pqueue_t *push(int l, int c, u32 parentcost) +{ + pqueue_t *queue; + u32 newcost; + + if (l >= asize || c >= asize || array[l][c].visited) + return NULL; + newcost = parentcost + array[l][c].cost; + if (newcost > array[l][c].totcost) + return NULL; + + queue = pool_get(pool); + queue->l = l; + queue->c = c; + queue->cost = newcost; + array[l][c].totcost = newcost; + + log_f(3, "(%d,%d) pcost=%u\n", l, c, newcost); + list_add_tail(&queue->list, &plist_head); + return queue; +} + +static pqueue_t *pop() +{ + pqueue_t *tmp, *cur; + + list_for_each_entry_safe(cur, tmp, &plist_head, list) { + int l = cur->l, c = cur->c; + + list_del(&cur->list); + if (array[l][c].visited) { + pool_add(pool, cur); + continue; + } + log_f(3, "(%d,%d) cost=%u\n", l, c, array[l][c].totcost); + return cur; + } + return NULL; +} + +/* read data and create graph. + */ +static int read_input() +{ + size_t alloc = 0; + char *buf; + ssize_t len; + int l = 0, c; + + /* get points list */ + while ((len = getline(&buf, &alloc, stdin)) > 0) { + buf[--len] = 0; + + //printf("%d: size=%d [%s]\n", l, asize, buf); + for (c = 0; buf[c]; ++c) { + array[l][c].cost = buf[c] - '0'; + array[l][c].totcost = UINT32_MAX; + array[l][c].visited = 0; + } + l++; + } + free(buf); + asize = l; + //print_array(); + return asize; +} + + +static u32 part1() +{ + pqueue_t *pqueue; + u32 best = UINT32_MAX; + + push(0, 0, 0); + + while ((pqueue = pop())) { + int l = pqueue->l, c = pqueue->c; + u32 acc = array[l][c].totcost; + + if (l == (asize - 1) && c == (asize - 1)) { + if (acc < best) { + best = acc; + log_f(3, "New best: %u\n", best); + } + } + push(l, c + 1, acc); + push(l + 1, c, acc); + array[l][c].visited = 1; + + pool_add(pool, pqueue); /* recycle pqueue in memory pool */ + } + + /* as we accounted [0][0] cost, we must substract it */ + return best - array[0][0].cost; +} + +static u32 part2() +{ + return 2; +} + +static u32 doit(int part) +{ + read_input(); + return part == 1? part1(): part2(); +} + +static int usage(char *prg) +{ + fprintf(stderr, "Usage: %s [-d debug_level] [-p part]\n", prg); + return 1; +} + +int main(int ac, char **av) +{ + int opt, part = 1; + + while ((opt = getopt(ac, av, "d:p:")) != -1) { + switch (opt) { + case 'd': + debug_level_set(atoi(optarg)); + break; + case 'p': /* 1 or 2 */ + part = atoi(optarg); + if (part < 1 || part > 2) + return usage(*av); + break; + default: + return usage(*av); + } + } + if (optind < ac) + return usage(*av); + + if (!(pool = pool_init("stack", 1024, sizeof (pqueue_t)))) + return -1; + + printf("%s : res=%d\n", *av, doit(part)); + exit (0); +}