Bash 2022 day 12 (parts 1 & 2), before cleaning code

This commit is contained in:
2022-12-22 21:33:29 +01:00
parent 11cb3c5c64
commit 6d4a8dd85b
10 changed files with 601 additions and 0 deletions

0
2022/day11/common.bash Executable file → Normal file
View File

111
2022/day12/Makefile Normal file
View File

@@ -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 <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
#
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

100
2022/day12/README.org Normal file
View File

@@ -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: **

200
2022/day12/aoc.bash Executable file
View File

@@ -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 <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
. 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

17
2022/day12/aoc.h Normal file
View File

@@ -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 <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*/
#ifndef _AOC_H_
#define _AOC_H_
extern int parseargs(int ac, char**av);
#endif /* _AOC_H_ */

68
2022/day12/common.bash Normal file
View File

@@ -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 <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
#
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
# 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"
}

49
2022/day12/common.c Normal file
View File

@@ -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 <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#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;
}

View File

@@ -0,0 +1,5 @@
Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi

View File

@@ -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

View File

@@ -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;