diff --git a/2022/day11/common.bash b/2022/day11/common.bash old mode 100755 new mode 100644 diff --git a/2022/day12/Makefile b/2022/day12/Makefile new file mode 100644 index 0000000..e0add74 --- /dev/null +++ b/2022/day12/Makefile @@ -0,0 +1,111 @@ +# AOC daily Makefile - GNU make only. +# +# Copyright (C) 2021-2022 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 +# + +INPUT := input/input.txt +SHELL := /bin/bash + +CC := gcc +BEAR := bear +CCLSFILE:= compile_commands.json + +LIB := aoc_$(shell uname -m) +INCDIR := ../include +LIBDIR := ../lib +LDFLAGS := -L$(LIBDIR) +#LDLIB := -l$(LIB) -lm +LDLIB := -l$(LIB) + +export LD_LIBRARY_PATH = $(LIBDIR) + +CFLAGS += -std=gnu11 +CFLAGS += -O2 +CFLAGS += -g +# for gprof +# CFLAGS += -pg +CFLAGS += -Wall +CFLAGS += -Wextra +CFLAGS += -march=native +# Next one may be useful for valgrind (some invalid instructions) +# CFLAGS += -mno-tbm +CFLAGS += -Wmissing-declarations +CFLAGS += -Wno-unused-result + +CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c) +CFLAGS += -DDEBUG_POOL # memory pools management + +VALGRIND := valgrind +VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \ + --sigill-diagnostics=yes --quiet --show-error-list=yes + + +TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n" +export PATH := .:$(PATH) + +.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 part1 part2 ccls bear org + +all: README.org ccls part1 part2 + +memcheck: memcheck1 memcheck2 + +memcheck1: aoc-c + @$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT) + +memcheck2: aoc-c + @$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT) + @#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT) + +compile: aoc-c + +cpp: aoc-c.i + +assembly: aoc-c.s + +part1: aoc-c + @$(TIME) aoc.bash -p 1 < $(INPUT) 2>&1 + @$(TIME) aoc-c -p 1 < $(INPUT) + +part2: aoc-c + @$(TIME) aoc.bash -p 2 < $(INPUT) 2>&1 + @$(TIME) aoc-c -p 2 < $(INPUT) + +ccls: $(CCLSFILE) + +clean: + @rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html compile_commands.json + +aoc-c: aoc-c.c common.c + @echo compiling $< + $(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $^ $(LDLIB) -o $@ + +# generate pre-processed file (.i) and assembler (.s) +%.i: %.c + @echo generating $@ + @$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@ + +%.s: %.c + @echo generating $@ + @$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@ + +# generate README.org from README.html (must cleanup !) +org: README.org + +%.org: %.html + @echo generating $@. Cleanup before commit ! + @pandoc $< -o $@ + +# generate compile_commands.json +$(CCLSFILE): aoc-c.c Makefile + $(BEAR) -- make clean compile + +bear: clean + @touch .ccls-root + @$(BEAR) -- make compile diff --git a/2022/day12/README.org b/2022/day12/README.org new file mode 100644 index 0000000..4dd4b76 --- /dev/null +++ b/2022/day12/README.org @@ -0,0 +1,100 @@ +** --- Day 12: Hill Climbing Algorithm --- +You try contacting the Elves using your handheld device, but the river +you're following must be too low to get a decent signal. + +You ask the device for a heightmap of the surrounding area (your puzzle +input). The heightmap shows the local area from above broken into a +grid; the elevation of each square of the grid is given by a single +lowercase letter, where =a= is the lowest elevation, =b= is the +next-lowest, and so on up to the highest elevation, =z=. + +Also included on the heightmap are marks for your current position (=S=) +and the location that should get the best signal (=E=). Your current +position (=S=) has elevation =a=, and the location that should get the +best signal (=E=) has elevation =z=. + +You'd like to reach =E=, but to save energy, you should do it in /as few +steps as possible/. During each step, you can move exactly one square +up, down, left, or right. To avoid needing to get out your climbing +gear, the elevation of the destination square can be /at most one +higher/ than the elevation of your current square; that is, if your +current elevation is =m=, you could step to elevation =n=, but not to +elevation =o=. (This also means that the elevation of the destination +square can be much lower than the elevation of your current square.) + +For example: + +#+begin_example +Sabqponm +abcryxxl +accszExk +acctuvwj +abdefghi +#+end_example + +Here, you start in the top-left corner; your goal is near the middle. +You could start by moving down or right, but eventually you'll need to +head toward the =e= at the bottom. From there, you can spiral around to +the goal: + +#+begin_example +v..v<<<< +>v.vv<<^ +.>vv>E^^ +..v>>>^^ +..>>>>>^ +#+end_example + +In the above diagram, the symbols indicate whether the path exits each +square moving up (=^=), down (=v=), left (=<=), or right (=>=). The +location that should get the best signal is still =E=, and =.= marks +unvisited squares. + +This path reaches the goal in =31= steps, the fewest possible. + +/What is the fewest steps required to move from your current position to +the location that should get the best signal?/ + +Your puzzle answer was =408=. + +** --- Part Two --- +As you walk up the hill, you suspect that the Elves will want to turn +this into a hiking trail. The beginning isn't very scenic, though; +perhaps you can find a better starting point. + +To maximize exercise while hiking, the trail should start as low as +possible: elevation =a=. The goal is still the square marked =E=. +However, the trail should still be direct, taking the fewest steps to +reach its goal. So, you'll need to find the shortest path from /any +square at elevation =a=/ to the square marked =E=. + +Again consider the example from above: + +#+begin_example +Sabqponm +abcryxxl +accszExk +acctuvwj +abdefghi +#+end_example + +Now, there are six choices for starting position (five marked =a=, plus +the square marked =S= that counts as being at elevation =a=). If you +start at the bottom-left square, you can reach the goal most quickly: + +#+begin_example +...v<<<< +...vv<<^ +...v>E^^ +.>v>>>^^ +>^>>>>>^ +#+end_example + +This path reaches the goal in only =29= steps, the fewest possible. + +/What is the fewest steps required to move starting from any square with +elevation =a= to the location that should get the best signal?/ + +Your puzzle answer was =399=. + +Both parts of this puzzle are complete! They provide two gold stars: ** diff --git a/2022/day12/aoc.bash b/2022/day12/aoc.bash new file mode 100755 index 0000000..2288d90 --- /dev/null +++ b/2022/day12/aoc.bash @@ -0,0 +1,200 @@ +#!/usr/bin/env bash +# +# aoc.bash: Advent of Code 2022, day 12 +# +# Copyright (C) 2022 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 + +. common.bash + +#declare -a map map2 +declare -A height map visited +declare -i X Y +declare start end push=push1 +declare -a queue + +printmap() { + local -i x y + for (( y = 0; y < Y; ++y )); do + for (( x = 0; x < X; ++x )); do + printf "%2d " "${map["$x,$y"]}" + done + echo + done +} + +printvis() { + local -i x y + for (( y = 0; y < Y; ++y )); do + for (( x = 0; x < X; ++x )); do + printf "%2d " "${visited["$x,$y"]}" + done + echo + done +} + +push1() { # push part 1 + local -i _d="$1" _x="$2" _y="$3" _h="$4" + local _c="$_x,$_y" + printf "push d=%d x=%d y=%d h=%d nh=%d... " "$_d" "$_x" "$_y" "$_h" \ + "${map[$_c]}" + if (( !visited[$_c] && map[$_c] <= (_h + 1) )); then + (( _d++ )) + visited["$_c"]=$_d + queue+=("$_d:$_c") + echo "$_d:$_c" pushed. + else + echo not pushed. + fi + #local str="$_d:$_x-$_y" + #queue+=("$1") +} + +push2() { # push part 2 + local -i _d="$1" _x="$2" _y="$3" _h="$4" + local _c="$_x,$_y" + printf "push d=%d x=%d y=%d h=%d nh=%d... " "$_d" "$_x" "$_y" "$_h" \ + "${map[$_c]}" + if (( !visited[$_c] && map[$_c] >= (_h - 1) )); then + (( _d++ )) + visited["$_c"]=$_d + queue+=("$_d:$_c") + echo "$_d:$_c" pushed. + else + echo not pushed. + fi + #local str="$_d:$_x-$_y" + #queue+=("$1") +} + +pop() { + local -n _d="$1" _x="$2" _y="$3" + local head + ((!${#queue[@]})) && echo pop: queue empty. && return 1 + head="${queue[0]}" + #echo "Q=${#queue[@]}=${queue[*]} head=$head" + # shellcheck disable=2034 + printf "pop: %s\t" "$head" + _d=${head%:*} + # shellcheck disable=2034 + head=${head#*:} + _x=${head%,*} + _y=${head#*,} + unset 'queue[0]' + queue=("${queue[@]}") + printf "pop: d=%d x=%d y=%d remain=%d\n" "$_d" "$_x" "$_y" "${#queue[@]}" + #echo "Q=${#queue[@]}=${queue[*]} head=$head" + return 0 +} + +# initialize height values +init() { + declare -i i=1 + for c in {a..z}; do + (( height[$c] = i++ )) + #echo + done + height[S]=1 + height[E]=26 +} + +parse() { + local -i part="$1" + local -a _map + local -i x y + local c + ((part == 2)) && push=push2 + + init + readarray -t _map + X=${#_map[0]} + Y=${#_map[@]} + echo "X=$X Y=$Y" + # create array map[x,y] + for (( y = 0; y < Y; ++y )); do + for (( x = 0; x < X; ++x )); do + c=${_map[$y]:x:1} + # printf "y=%d x=%d c=%s h=%d " "$y" "$x" "$c" "${height[$c]}" + map["$x,$y"]=${height[$c]} + # printf "M=%s\n" "${map["$x,$y"]}" + case "$c" in + S) start="$x,$y" + ((part == 1)) && $push 0 "$x" "$y" 1 + #printf "\tstart\n" + ;; + E) end="$x,$y" + ((part == 2)) && $push 0 "$x" "$y" 1 + #printf "\tend\n" + ;; + esac + done + done + printf "start=%s end=%s\n" "$start" "$end" + printmap +} + +solve() { + #local depth coord + local -i h d x y + + + #push 0 ${start%-*} ${start#*-} 1 + #push "11:46-55" + while pop d x y; do + (( h=${map["$x,$y"]} )) + if [[ $part == 1 ]]; then + if [[ "$x,$y" == "$end" ]]; then + res=$((d-1)) + printmap + echo + printvis + return + fi + else + if [[ "${map["$x,$y"]}" == 1 ]]; then + res=$((d-1)) + printmap + echo + printvis + return + fi + fi + if ((y > 0)); then # north + $push "$d" "$x" "$((y-1))" "$h" + fi + if ((x+1 < X)); then # east + $push "$d" "$((x+1))" "$y" "$h" + fi + if ((y+1 < Y)); then # south + $push "$d" "$x" "$((y+1))" "$h" + fi + if ((x > 0)); then # west + $push "$d" "$((x-1))" "$y" "$h" + fi + #echo "d=$d x=$x y=$y" + echo + done + #push "10:45-54" + # push "11:46-55" + # pop dep x y + # echo "d=$d x=$x y=$y" + # pop dep x y + # echo "d=$d x=$x y=$y" + # push "78:1-2" + # pop dep x y + # echo "d=$d x=$x y=$y" + # #pop d c + # #echo "d=$d c=$c" + + # : + # #(( part == 2 )) && (( _loops = 10000, divisor = 1 )) +} + +main "$@" +exit 0 diff --git a/2022/day12/aoc.h b/2022/day12/aoc.h new file mode 100644 index 0000000..2ef8361 --- /dev/null +++ b/2022/day12/aoc.h @@ -0,0 +1,17 @@ +/* aoc.c: Advent of Code 2022 + * + * Copyright (C) 2022 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 + */ +#ifndef _AOC_H_ +#define _AOC_H_ + +extern int parseargs(int ac, char**av); + +#endif /* _AOC_H_ */ diff --git a/2022/day12/common.bash b/2022/day12/common.bash new file mode 100644 index 0000000..5af1e54 --- /dev/null +++ b/2022/day12/common.bash @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# +# common.bash: Advent of Code 2022, common bash functions +# +# Copyright (C) 2022 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 + +# shellcheck disable=2034 +export cmdname=${0##*/} +export debug=0 +export res +export LANG=C + +shopt -s extglob +set -o noglob + +usage() { + printf "usage: %s [-d DEBUG] [-p PART]\n" "$cmdname" + exit 1 +} + +checkargs() { + local part=1 + while getopts p:d: todo; do + case "$todo" in + d) + if [[ "$OPTARG" =~ ^[[:digit:]+]$ ]]; then + debug="$OPTARG" + else + printf "%s: illegal [%s] debug level.\n" "$CMD" "$OPTARG" + exit 1 + fi + ;; + p) + if [[ "$OPTARG" =~ ^[12]$ ]]; then + part="$OPTARG" + else + printf "%s: illegal [%s] part.\n" "$CMD" "$OPTARG" + exit 1 + fi + ;; + *) + usage + ;; + esac + done + # Now check remaining argument (backup directory) + shift $((OPTIND - 1)) + + (( $# > 1 )) && usage + return "$part" +} + +main() { + local -i part + + checkargs "$@" + part=$? + parse "$part" + solve "$part" + printf "%s: res=%s\n" "$cmdname" "$res" +} diff --git a/2022/day12/common.c b/2022/day12/common.c new file mode 100644 index 0000000..a3827b6 --- /dev/null +++ b/2022/day12/common.c @@ -0,0 +1,49 @@ +/* common.c: Advent of Code 2022, common functions + * + * Copyright (C) 2022 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 "aoc.h" +#include "debug.h" + +static int usage(char *prg) +{ + fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg); + return 1; +} + +int parseargs(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; + case 'i': + + default: + return usage(*av); + } + } + if (optind < ac) + return usage(*av); + return part; +} diff --git a/2022/day12/input/example.txt b/2022/day12/input/example.txt new file mode 100644 index 0000000..86e9cac --- /dev/null +++ b/2022/day12/input/example.txt @@ -0,0 +1,5 @@ +Sabqponm +abcryxxl +accszExk +acctuvwj +abdefghi diff --git a/2022/day12/input/input.txt b/2022/day12/input/input.txt new file mode 100644 index 0000000..bb083e9 --- /dev/null +++ b/2022/day12/input/input.txt @@ -0,0 +1,41 @@ +abaaaaaccccccccccccccccccaaaaaaaaaaaaaccccaaaaaaaccccccccccccccccccccccccccccaaaaaa +abaaaaaaccaaaacccccccccccaaaaaaaaacaaaacaaaaaaaaaacccccccccccccccccccccccccccaaaaaa +abaaaaaacaaaaaccccccccccaaaaaaaaaaaaaaacaaaaaaaaaacccccccccccccaacccccccccccccaaaaa +abaaaaaacaaaaaacccccccccaaaaaaaaaaaaaaccaaacaaaccccccccccccccccaacccccccccccccccaaa +abccaaaccaaaaaacccaaaaccaaaaaaaaaaaaaccccaacaaacccccccccaacaccccacccccccccccccccaaa +abcccccccaaaaaccccaaaacccccaaaaacccaaaccaaaaaaccccccccccaaaaccccccccccccccccccccaac +abcccccccccaaaccccaaaacccccaaaaacccccccccaaaaaccccccccccklllllccccccccccccccccccccc +abcccccccccccccccccaaccccccccaaccccccccaaaaaaaccccccccckklllllllcccccddccccaacccccc +abaccccccccccccccccccccccccccaaccccccccaaaaaaaaccccccckkkklslllllcccddddddaaacccccc +abacccccccccccccccccccccccccccccccaaaccaaaaaaaaccccccckkkssssslllllcddddddddacccccc +abaccccccccccccccccccccccccccccccccaaaaccaaacaccccccckkksssssssslllmmmmmdddddaacccc +abcccccccccccccccaaacccccccccccccaaaaaaccaacccccccccckkkssssusssslmmmmmmmdddddacccc +abcccccccaaccccaaaaacccccccccccccaaaaaccccccaaaaaccckkkrssuuuussssqmmmmmmmmdddccccc +abcccccccaaccccaaaaaacccccccaaccccaaaaacccccaaaaacckkkkrruuuuuussqqqqqqmmmmdddccccc +abccccaaaaaaaacaaaaaacccccccaaaaccaaccaccccaaaaaacjkkkrrruuuxuuusqqqqqqqmmmmeeccccc +abcaaaaaaaaaaacaaaaaccccccaaaaaacccccaaccccaaaaajjjjrrrrruuuxxuvvvvvvvqqqmmmeeccccc +abcaacccaaaaccccaaaaaaacccaaaaacccacaaaccccaaaajjjjrrrrruuuxxxxvvvvvvvqqqmmeeeccccc +abaaaaccaaaaacccccccaaaccccaaaaacaaaaaaaacccaajjjjrrrrtuuuuxxxyvyyyvvvqqqnneeeccccc +abaaaaaaaaaaacccaaaaaaaccccaacaacaaaaaaaacccccjjjrrrttttuxxxxxyyyyyvvvqqnnneeeccccc +abaaaaaaaccaacccaaaaaaaaacccccccccaaaaaaccccccjjjrrrtttxxxxxxxyyyyyvvvqqnnneeeccccc +SbaaaaaacccccccccaaaaaaaaaccccccccaaaaacccccccjjjrrrtttxxxEzzzzyyyvvrrrnnneeecccccc +abaaaaacccccccccccaaaaaaacccccccccaaaaaaccccccjjjqqqtttxxxxxyyyyyvvvrrrnnneeecccccc +abaaacccccccccccaaaaaaaccaaccccccccccaaccaaaaajjjqqqttttxxxxyyyyyyvvrrrnnneeecccccc +abaaacccccccccccaaaaaaaccaaacaaacccccccccaaaaajjjjqqqtttttxxyywyyyywvrrnnnfeecccccc +abcaaacccccccaaaaaaaaaaacaaaaaaaccccccccaaaaaaciiiiqqqqtttxwyywwyywwwrrrnnfffcccccc +abcccccccccccaaaaaaaaaaccaaaaaacccccccccaaaaaacciiiiqqqqttwwywwwwwwwwrrrnnfffcccccc +abccccccccccccaaaaaacccaaaaaaaacccccccccaaaaaaccciiiiqqqttwwwwwswwwwrrrrnnfffcccccc +abccccccccccccaaaaaacccaaaaaaaaacccccccccaaacccccciiiqqqtswwwwssssrrrrrroofffcccccc +abccccccaaaaacaaaaaacccaaaaaaaaaaccccccccccccccccciiiqqqssswsssssssrrrrooofffaccccc +abccccccaaaaacaaccaaccccccaaacaaacccccccccccccccccciiiqqssssssspoorrrooooofffaacccc +abcccccaaaaaacccccccccccccaaacccccccccccccccccccccciiiqppssssspppooooooooffffaacccc +abcccccaaaaaacccccccccccccaacccccccccccccccccccccccciipppppppppppoooooooffffaaccccc +abcccccaaaaaaccccccccccccccccccccccccccccccccccccccciihppppppppgggggggggfffaaaccccc +abccccccaaacccccccccccccccccccccccaccccccccccccccccchhhhpppppphggggggggggfaaaaccccc +abaaaccccccccccccccccccccccaccccaaacccccccccccccccccchhhhhhhhhhgggggggggcaacccccccc +abaaccaaaccaccccccccccccccaaacccaaacaacccaaaaacccccccchhhhhhhhhgaaccccccccccccccccc +abaaacaaacaacccccccccaaaccaaaacaaaaaaaaccaaaaaccccccccchhhhhhaaaaacccccccccccccccca +abaaaccaaaaaccccccccccaaacaaaaaaaacaaaaccaaaaaaccccccccccaaacccaaaacccccccccccaccca +abcccaaaaaaccccccccccaaaaaaaaaaaaacaaaaccaaaaaaccccccccccaaaccccaaaccccccccccaaaaaa +abcccaaaaaaaacccccccaaaaaaaaaaaaaaaaaccccaaaaaacccccccccccccccccccccccccccccccaaaaa +abcccaacaaaaaccccccaaaaaaaaaaaaaaaaaaacccccaacccccccccccccccccccccccccccccccccaaaaa diff --git a/2022/include/pjwhash-inline.h b/2022/include/pjwhash-inline.h index 75c2bcb..81dabb7 100644 --- a/2022/include/pjwhash-inline.h +++ b/2022/include/pjwhash-inline.h @@ -24,6 +24,16 @@ #define _pjw_inline static inline #endif +/** + * unsigned int pjwhash - PJW hash function + * @key: the key address. + * @length: the length of key. + * + * This hash was created by Peter Jay Weinberger (AT&T Bell Labs): + * https://en.wikipedia.org/wiki/PJW_hash_function + * + * Return: the PJW hash. + */ _pjw_inline unsigned int pjwhash(const void* key, uint length) { uint hash = 0, high;