From b37a204b4f6db8154543b04849e7e7e19ac87ecc Mon Sep 17 00:00:00 2001 From: Einar Jon Gunnarsson Date: Sat, 4 Dec 2021 21:06:18 +0100 Subject: [PATCH 01/10] 2021: I can't stop I need help --- .gitignore | 2 +- 2021/01.sh | 7 +++++++ 2021/02.sh | 19 +++++++++++++++++++ 2021/03.sh | 29 +++++++++++++++++++++++++++++ 2021/04.sh | 43 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 1 deletion(-) create mode 100755 2021/01.sh create mode 100755 2021/02.sh create mode 100755 2021/03.sh create mode 100755 2021/04.sh diff --git a/.gitignore b/.gitignore index 2dd43d8..54a115b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ ./*.txt* 201[6-9]/ -202[1-9]/ +202[2-9]/ diff --git a/2021/01.sh b/2021/01.sh new file mode 100755 index 0000000..37cb768 --- /dev/null +++ b/2021/01.sh @@ -0,0 +1,7 @@ +#! /usr/bin/env bash +A=($(< "${1:-1.txt}")); a=${A[0]}; ANS=0 +for b in "${A[@]:1}"; do ((b>a && ++ANS)); a=$b; done +echo "1A: ${ANS}" +a=$((A[0]+A[1]+A[2])); b=$a; idx=(${!A[@]}); ANS2=0 +for i in "${idx[@]:3}"; do ((b+=A[i]-A[i-3], b>a && ++ANS2)); a=$b; done +echo "1B: ${ANS2}" diff --git a/2021/02.sh b/2021/02.sh new file mode 100755 index 0000000..d9ed869 --- /dev/null +++ b/2021/02.sh @@ -0,0 +1,19 @@ +#! /usr/bin/env bash +declare -i X=0 Y=0 y=0 +while read -r dir n; do + case $dir in + up) Y+=-$n;; + down) Y+=$n;; + forward) X+=$n; y+=$((Y*n));; + esac +done < "${1:-2.txt}" +echo "12A: $X*$Y = $((X*Y))" +echo "12B: $X*$y = $((X*y))" +# golfed with awk +#awk 'n=$2 /u/{Y-=n}/n/{Y+=n}/f/{X+=n;y+=n*Y}END{print X*Y,X*y}' ${1:-2.txt} +#paste -d"*" <(paste -sd+ <(rg ^f input.txt | rev | cut -c 1) | bc) <(paste -sd+ <(rg '^[du]' input.txt | sed 's/down/1\*/;s/up/-1\*/g' | bc) | bc) | bc + +#paste -d"*" <(paste -sd+ <(paste -d* <(cut -c 1 input.txt) <(rev input.txt | cut -c -1) <(sed 's/down/1\*/;s/up/-1\*/;s/forward/0\*/g' input.txt | bc | awk '{total += $0; $0 = total}1') | rg f | tr f 1 | bc ) | bc) <(paste -sd+ <(rg ^f input.txt | rev | cut -c 1) | bc) | bc +# /u/obluff +paste -d"*" <(paste -sd+ <(sed -n 's/f.* //p' input.txt )|bc) <(paste -sd+ <(sed 's/down //;s/up /-/g;/f/d' input.txt)|bc) | bc +paste -d"*" <(paste -sd+ <(paste -d* <(cut -c1 input.txt) <(tr -dc '0-9\n' < input.txt) <(x=0 && sed 's/down //;s/up/-/;s/f.*/0/' input.txt | while read a;do echo $((x+=a));done) | sed -n s/f.//p | bc) | bc) <(paste -sd+ <(sed -n 's/f.* //p' input.txt) | bc) | bc diff --git a/2021/03.sh b/2021/03.sh new file mode 100755 index 0000000..883b557 --- /dev/null +++ b/2021/03.sh @@ -0,0 +1,29 @@ +#! /usr/bin/env bash +nextchar() { + local -n most=$1 least=$2 in=$3 + local all=$(printf "%s\n" "${in[@]}" | cut -c"$4" | tr -d '\n' ) + local ones=${all//0} zeros=${all//1} + if (( ${#ones} >= ${#zeros} )); then + most+=1; least+=0 + else most+=0; least+=1; fi +} +A=($(< "${1:-3.txt}")) +idx=(${!A[@]}) len=${#A[0]} g="" e="" +time for i in "${idx[@]:1:len}"; do + nextchar g e A $i +done +echo "3A: $g*$e = $(($((2#$g))*$((2#$e))))" +time { +O=(${A[@]}) C=(${A[@]}) c=${e:0:1} o=${g:0:1} +for i in "${idx[@]:2:len}"; do + O=($(printf "%s\n" "${O[@]}" | grep "^$o")) + (( ${#O[@]} <= 1 )) && break + nextchar o _ O $i +done +for i in "${idx[@]:2:len}"; do + C=($(printf "%s\n" "${C[@]}" | grep "^$c")) + (( ${#C[@]} <= 1 )) && break + nextchar _ c C $i +done +} +echo "3B: $O*$C = $(($((2#$O))*$((2#$C))))" diff --git a/2021/04.sh b/2021/04.sh new file mode 100755 index 0000000..1e9222e --- /dev/null +++ b/2021/04.sh @@ -0,0 +1,43 @@ +#! /usr/bin/env bash +declare -i i +while read -r a b c d e; do + if (( ${#NUMBERS[@]} == 0 )); then NUMBERS=(${a//,/ }); + elif [[ -n $a ]]; then + C[i++]="-$a--$b--$c--$d--$e-" # rows + j=$((10*(i/10))) # columns + C[j+5]+="-$a-";C[j+6]+="-$b-";C[j+7]+="-$c-";C[j+8]+="-$d-";C[j+9]+="-$e-"; + ((i%5==0)) && i+=5 + fi +done < "${1:-4.txt}" +idx=(${!C[@]}) +for k in "${!NUMBERS[@]}"; do + n=${NUMBERS[k]} + C=("${C[@]//-$n-}") + B=(${C[@]}) # lazy "find empty" + (( ${#B[@]} != ${#C[@]} )) && break +done +for i in "${idx[@]}"; do [[ -z ${C[i]} ]] && break; done +j=$((10*(i/10))) # columns +printf -v sum "%s" "${C[@]:j:5}" +sum=${sum//--/+}; sum=${sum//-} +echo "12A: $n*$sum = $((n*(sum)))" +printf -v WON "=%d=" {0..990..10} +WON=${WON/=$j=} # only do each card once +for i in "${idx[@]:j:10}"; do C[i]=DONE; done +for k in "${!NUMBERS[@]}"; do + n=${NUMBERS[k]} + C=("${C[@]//-$n-}") + B=(${C[@]}) + if (( ${#B[@]} != ${#C[@]} )); then + for i in "${idx[@]}"; do + if [[ -z ${C[i]} ]]; then + j=$((10*(i/10))) + WON=${WON/=$j=}; [[ -z $WON ]] && break 2 + for l in "${idx[@]:j:10}"; do C[l]=DONE; done + fi + done + fi +done +printf -v sum "%s" "${C[@]:j:5}" +sum=${sum//--/+}; sum=${sum//-} +echo "12B: $n*$sum = $((n*(sum)))" From 72e9ca2ac79fafce98677c2951f96bff473aa99c Mon Sep 17 00:00:00 2001 From: Einar Jon Gunnarsson Date: Tue, 7 Dec 2021 20:44:06 +0100 Subject: [PATCH 02/10] 2021: Days 5-7 and README.md --- 2021/05.sh | 25 +++++++++++++++++++++++++ 2021/06.sh | 16 ++++++++++++++++ 2021/07.sh | 20 ++++++++++++++++++++ 2021/README.md | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+) create mode 100755 2021/05.sh create mode 100755 2021/06.sh create mode 100755 2021/07.sh create mode 100644 2021/README.md diff --git a/2021/05.sh b/2021/05.sh new file mode 100755 index 0000000..edf493d --- /dev/null +++ b/2021/05.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +input=${1:-5.txt} +swap(){ + local -n _x=$1 _y=$2 + local tmp=$_x; _x=$_y; _y=$tmp +} +IFS=$' ,\n'; ANS=0; ANS2=0; declare -Ai C=() D=() +while read -r x y _ X Y; do + if (( x == X )); then + (( y > Y )) && swap y Y + while ((y<=Y)); do C[$x.$y]+=1; ((y++));done + elif (( y == Y )); then + (( x > X )) && swap x X + while ((x<=X)); do C[$x.$y]+=1; ((x++));done + elif (( (X-x) == (Y-y) || (X-x) == -(Y-y) )); then + (( x > X )) && swap x X && swap y Y + if (( y > Y )); then i=-1; else i=1; fi + while ((x<=X)); do D[$x.$y]+=1; ((x++,y+=i));done + fi +done < "$input" +ANS=(${C[@]//1}) # Lazy count. Fails if there are 11 crossings +echo "5A: ${#ANS[@]}" +for i in "${!C[@]}"; do D[$i]+=${C[$i]}; done +ANS2=(${D[@]//1}) +echo "5B: ${#ANS2[@]}" diff --git a/2021/06.sh b/2021/06.sh new file mode 100755 index 0000000..9a845d3 --- /dev/null +++ b/2021/06.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +A=$(< "${1:-6.txt}") +A=${A//,} +solve() { + for ((; n < $1; ++n)); do + #births=${A//[^0]}; births=${births//0/8} + births=$(tr -cd 0 <<< "$A" | tr 0 8) + B=$(echo -n "$A" | tr 876543210 765432106 ) + A[i]="${B[i]}${births}" + done +} +n=0 +solve 80 +echo "6A: ${#A}" +#solve 256 +#echo "6B: ${#A}" diff --git a/2021/07.sh b/2021/07.sh new file mode 100755 index 0000000..610358b --- /dev/null +++ b/2021/07.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +A=($(tr , '\n' < "${1:-7.txt}" | sort -n )) +MIN=(99999999 0) MIN2=(9999999999999 0) +N=${#A[@]} +for ((i=A[N/4]; isum)) && MIN=($sum $i) +done +echo "7A: ${MIN[0]}" + +for ((i=A[N/4]; isum2)) && MIN2=($sum2 $i) +done +echo "7B: ${MIN2[0]}" diff --git a/2021/README.md b/2021/README.md new file mode 100644 index 0000000..f923854 --- /dev/null +++ b/2021/README.md @@ -0,0 +1,37 @@ +# adventofcode.sh +Advent of Code 2021, done in bash. Because I can't stop +https://adventofcode.com/2021/ + +Input can be given on the command line. +Defaults to *number*.txt in the same folder (no leading 0). +Added my input files in input/ folder. +Setting env variable PUREBASH to any value (or giving a second argument) will use slow bash instead of using faster awk when needed. + +Description of what I'm doing. Contains spoilers.... + +### 01.sh + 1. Dumb looping through all variables. + 2. Use a sliding window. 2/3 of the values in the windows are the same, but this is fine. + +### 02.sh + Simple switch to handle all cases. Both parts handled at once. + +### 03.sh + 1. Slightly tricky. Use a function to find the most/least common number in each position. + 2. Same function, but change the input for every char. + +### 04.sh + 1. Use an array to store all lines/rows of a bingo card. Delete numbers from all lines until a line is empty. + 2. Remove a card when a line is empty. Keep going until all cards are gone. + +### 05.sh + 1. Mark all points on the grid in a hash table. Return a count of points that are != 1. + 2. Mark diagonals on a second hash table. Add the first hash table to it and return a count of points that are != 1. + +### 06.sh + 1. String manipulation. Bad O(), but finishes part 1 in half a second. + 2. Too slow... + +### 07.sh + 1. Brute force search. + 2. More brute force. From b25ff15879b6eb2d174555cd2a43c5888cf968a5 Mon Sep 17 00:00:00 2001 From: Einar Jon Gunnarsson Date: Tue, 7 Dec 2021 20:49:36 +0100 Subject: [PATCH 03/10] 2021: Improvements on days 6 and 7 --- 2021/06.sh | 20 +++++++++----------- 2021/07.sh | 29 ++++++++++++----------------- 2 files changed, 21 insertions(+), 28 deletions(-) diff --git a/2021/06.sh b/2021/06.sh index 9a845d3..3d1047b 100755 --- a/2021/06.sh +++ b/2021/06.sh @@ -1,16 +1,14 @@ #!/usr/bin/env bash -A=$(< "${1:-6.txt}") -A=${A//,} +declare -i A=(0 0 0 0 0 0 0 0 0) n=0 +while read freq age; do A[age]=$freq; done < <(grep -o [0-9] "${1:-6.txt}" | sort | uniq -c) solve() { - for ((; n < $1; ++n)); do - #births=${A//[^0]}; births=${births//0/8} - births=$(tr -cd 0 <<< "$A" | tr 0 8) - B=$(echo -n "$A" | tr 876543210 765432106 ) - A[i]="${B[i]}${births}" + while ((n < $1)); do + i=$((n++%9)) + A[i-2]+=${A[i]} done + sum=0; for i in "${!A[@]}"; do ((sum+=A[i])); done } -n=0 solve 80 -echo "6A: ${#A}" -#solve 256 -#echo "6B: ${#A}" +echo "6A: $sum" +solve 256 +echo "6B: $sum" diff --git a/2021/07.sh b/2021/07.sh index 610358b..797e178 100755 --- a/2021/07.sh +++ b/2021/07.sh @@ -1,20 +1,15 @@ -#!/usr/bin/env bash -A=($(tr , '\n' < "${1:-7.txt}" | sort -n )) +#!/bin/bash +input=$(< ${1:-7.txt}) +A=($(echo -e "${input//,/\\n}" | sort -n)) MIN=(99999999 0) MIN2=(9999999999999 0) N=${#A[@]} -for ((i=A[N/4]; isum)) && MIN=($sum $i) +avg=$(((${input//,/+})/N)) +n=""; for k in ${A[@]};do n+=+$((k-A[N/2])); done +sum=$((${n//-})) # lazy abs() +echo "7A: $sum" +declare -i sum2=0 +for k in ${A[@]}; do + dist=$((k-avg)); dist=${dist/-} + sum2+=$((dist*(dist+1)/2)) done -echo "7A: ${MIN[0]}" - -for ((i=A[N/4]; isum2)) && MIN2=($sum2 $i) -done -echo "7B: ${MIN2[0]}" +echo "7B: $sum2" From e33aaaddbc4d0bba7b3dd000f55db5064e18d784 Mon Sep 17 00:00:00 2001 From: Einar Jon Gunnarsson Date: Wed, 8 Dec 2021 16:03:00 +0100 Subject: [PATCH 04/10] 2021: Day 8. Update README.md --- 2021/08.sh | 42 ++++++++++++++++++++++++++++++++++++++++++ 2021/README.md | 11 +++++++---- 2 files changed, 49 insertions(+), 4 deletions(-) create mode 100755 2021/08.sh diff --git a/2021/08.sh b/2021/08.sh new file mode 100755 index 0000000..e578042 --- /dev/null +++ b/2021/08.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +input=${1:-8.txt} +printf "8A: " +cut -d\| -f 2 "$input" | grep -Eo "[a-g]+" | grep -cE "^([a-g]{2,4}|[a-g]{7})$" +sum="" +while read -r -a A; do + T=() P235=() P690=() n="" + for i in "${A[@]:0:10}"; do + case ${#i} in + 2) T[1]=$i;; + 3) T[7]=$i;; + 4) T[4]=$i;; + 5) P235+=($i);; + 6) P690+=($i);; + 7) T[8]=$i;; + esac + done + for i in "${P235[@]}"; do + if [[ ${i//[${T[4]}]} == ??? ]]; then T[2]=$i + elif [[ ${i//[${T[7]}]} == ?? ]]; then T[3]=$i + else T[5]=$i + fi + done + for i in "${P690[@]}"; do + if [[ ${i//[${T[7]}]} == ???? ]]; then T[6]=$i + elif [[ ${i//[${T[4]}]} == ?? ]]; then T[9]=$i + else T[0]=$i + fi + done + for i in "${A[@]:11}"; do + case ${#i} in + 2) n+=1;; + 3) n+=7;; + 4) n+=4;; + 5) for k in 2 3 5 ?; do [[ -z ${i//[${T[k]}]} ]] && break; done; n+=$k;; + 6) for k in 6 9 0 ?; do [[ -z ${i//[${T[k]}]} ]] && break; done; n+=$k;; + 7) n+=8;; + esac + done + sum+=+$((10#$n)) # leading 0 means octal. A '?' will throw an error here +done < "${input}" +echo "8B: $((sum))" diff --git a/2021/README.md b/2021/README.md index f923854..1e08e53 100644 --- a/2021/README.md +++ b/2021/README.md @@ -29,9 +29,12 @@ Description of what I'm doing. Contains spoilers.... 2. Mark diagonals on a second hash table. Add the first hash table to it and return a count of points that are != 1. ### 06.sh - 1. String manipulation. Bad O(), but finishes part 1 in half a second. - 2. Too slow... + Store a count of the fishes each day in a circular buffer, with the current 0-day at n%9. Bash arrays are circular by default. ### 07.sh - 1. Brute force search. - 2. More brute force. + 1. Use the median. + 2. Use the mean. + +### 07.sh + 1. Simple grep to fish out the output digits and isolate the ones with 2-4 or 7 digits. + 2. A damn bother, since the letters were scrambled. Assigned the numbers based on length. The 5-6 length ones got special handling, by checking the length after removing the letters that make up 4 and 7. That was enough to identify every one. From 31a5721d4de69ea150a8c71bb41c79f175572b3a Mon Sep 17 00:00:00 2001 From: Einar Jon Gunnarsson Date: Wed, 8 Dec 2021 16:34:40 +0100 Subject: [PATCH 05/10] 2021: Shellcheck fixes and minor cleanup --- 2021/02.sh | 11 ++++++----- 2021/03.sh | 13 ++++++------- 2021/04.sh | 5 +++-- 2021/06.sh | 2 +- 2021/07.sh | 7 +++---- 2021/README.md | 2 +- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/2021/02.sh b/2021/02.sh index d9ed869..3ccc8f5 100755 --- a/2021/02.sh +++ b/2021/02.sh @@ -1,4 +1,5 @@ #! /usr/bin/env bash +input=${1:-2.txt} declare -i X=0 Y=0 y=0 while read -r dir n; do case $dir in @@ -6,14 +7,14 @@ while read -r dir n; do down) Y+=$n;; forward) X+=$n; y+=$((Y*n));; esac -done < "${1:-2.txt}" +done < "${input}" echo "12A: $X*$Y = $((X*Y))" echo "12B: $X*$y = $((X*y))" # golfed with awk #awk 'n=$2 /u/{Y-=n}/n/{Y+=n}/f/{X+=n;y+=n*Y}END{print X*Y,X*y}' ${1:-2.txt} -#paste -d"*" <(paste -sd+ <(rg ^f input.txt | rev | cut -c 1) | bc) <(paste -sd+ <(rg '^[du]' input.txt | sed 's/down/1\*/;s/up/-1\*/g' | bc) | bc) | bc +#paste -d"*" <(paste -sd+ <(rg ^f "${input}" | rev | cut -c 1) | bc) <(paste -sd+ <(rg '^[du]' "${input}" | sed 's/down/1\*/;s/up/-1\*/g' | bc) | bc) | bc -#paste -d"*" <(paste -sd+ <(paste -d* <(cut -c 1 input.txt) <(rev input.txt | cut -c -1) <(sed 's/down/1\*/;s/up/-1\*/;s/forward/0\*/g' input.txt | bc | awk '{total += $0; $0 = total}1') | rg f | tr f 1 | bc ) | bc) <(paste -sd+ <(rg ^f input.txt | rev | cut -c 1) | bc) | bc +#paste -d"*" <(paste -sd+ <(paste -d* <(cut -c 1 "${input}") <(rev "${input}" | cut -c -1) <(sed 's/down/1\*/;s/up/-1\*/;s/forward/0\*/g' "${input}" | bc | awk '{total += $0; $0 = total}1') | rg f | tr f 1 | bc ) | bc) <(paste -sd+ <(rg ^f "${input}" | rev | cut -c 1) | bc) | bc # /u/obluff -paste -d"*" <(paste -sd+ <(sed -n 's/f.* //p' input.txt )|bc) <(paste -sd+ <(sed 's/down //;s/up /-/g;/f/d' input.txt)|bc) | bc -paste -d"*" <(paste -sd+ <(paste -d* <(cut -c1 input.txt) <(tr -dc '0-9\n' < input.txt) <(x=0 && sed 's/down //;s/up/-/;s/f.*/0/' input.txt | while read a;do echo $((x+=a));done) | sed -n s/f.//p | bc) | bc) <(paste -sd+ <(sed -n 's/f.* //p' input.txt) | bc) | bc +paste -d"*" <(paste -sd+ <(sed -n 's/f.* //p' "${input}" )|bc) <(paste -sd+ <(sed 's/down //;s/up /-/g;/f/d' "${input}")|bc) | bc +paste -d"*" <(paste -sd+ <(paste -d* <(cut -c1 "${input}") <(tr -dc '0-9\n' < "${input}") <(x=0 && sed 's/down //;s/up/-/;s/f.*/0/' "${input}" | while read -r a;do echo $((x+=a));done) | sed -n s/f.//p | bc) | bc) <(paste -sd+ <(sed -n 's/f.* //p' "${input}") | bc) | bc diff --git a/2021/03.sh b/2021/03.sh index 883b557..65604ce 100755 --- a/2021/03.sh +++ b/2021/03.sh @@ -1,7 +1,7 @@ #! /usr/bin/env bash nextchar() { local -n most=$1 least=$2 in=$3 - local all=$(printf "%s\n" "${in[@]}" | cut -c"$4" | tr -d '\n' ) + local all; all=$(printf "%s\n" "${in[@]}" | cut -c"$4" | tr -d '\n' ) local ones=${all//0} zeros=${all//1} if (( ${#ones} >= ${#zeros} )); then most+=1; least+=0 @@ -9,21 +9,20 @@ nextchar() { } A=($(< "${1:-3.txt}")) idx=(${!A[@]}) len=${#A[0]} g="" e="" -time for i in "${idx[@]:1:len}"; do - nextchar g e A $i +for i in "${idx[@]:1:$len}"; do + nextchar g e A "$i" done echo "3A: $g*$e = $(($((2#$g))*$((2#$e))))" -time { O=(${A[@]}) C=(${A[@]}) c=${e:0:1} o=${g:0:1} for i in "${idx[@]:2:len}"; do O=($(printf "%s\n" "${O[@]}" | grep "^$o")) (( ${#O[@]} <= 1 )) && break - nextchar o _ O $i + nextchar o _ O "$i" done for i in "${idx[@]:2:len}"; do C=($(printf "%s\n" "${C[@]}" | grep "^$c")) (( ${#C[@]} <= 1 )) && break - nextchar _ c C $i + nextchar _ c C "$i" done -} +# shellcheck disable=SC2128 echo "3B: $O*$C = $(($((2#$O))*$((2#$C))))" diff --git a/2021/04.sh b/2021/04.sh index 1e9222e..5f44540 100755 --- a/2021/04.sh +++ b/2021/04.sh @@ -20,7 +20,8 @@ for i in "${idx[@]}"; do [[ -z ${C[i]} ]] && break; done j=$((10*(i/10))) # columns printf -v sum "%s" "${C[@]:j:5}" sum=${sum//--/+}; sum=${sum//-} -echo "12A: $n*$sum = $((n*(sum)))" +echo "12A: $((n*(sum)))" + printf -v WON "=%d=" {0..990..10} WON=${WON/=$j=} # only do each card once for i in "${idx[@]:j:10}"; do C[i]=DONE; done @@ -40,4 +41,4 @@ for k in "${!NUMBERS[@]}"; do done printf -v sum "%s" "${C[@]:j:5}" sum=${sum//--/+}; sum=${sum//-} -echo "12B: $n*$sum = $((n*(sum)))" +echo "12B: $((n*(sum)))" diff --git a/2021/06.sh b/2021/06.sh index 3d1047b..afbc848 100755 --- a/2021/06.sh +++ b/2021/06.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash declare -i A=(0 0 0 0 0 0 0 0 0) n=0 -while read freq age; do A[age]=$freq; done < <(grep -o [0-9] "${1:-6.txt}" | sort | uniq -c) +while read -r freq age; do A[age]=$freq; done < <(grep -o "[0-9]" "${1:-6.txt}" | sort | uniq -c) solve() { while ((n < $1)); do i=$((n++%9)) diff --git a/2021/07.sh b/2021/07.sh index 797e178..952e9f4 100755 --- a/2021/07.sh +++ b/2021/07.sh @@ -1,14 +1,13 @@ #!/bin/bash -input=$(< ${1:-7.txt}) +input=$(< "${1:-7.txt}") A=($(echo -e "${input//,/\\n}" | sort -n)) -MIN=(99999999 0) MIN2=(9999999999999 0) N=${#A[@]} avg=$(((${input//,/+})/N)) -n=""; for k in ${A[@]};do n+=+$((k-A[N/2])); done +n=""; for k in "${A[@]}";do n+=+$((k-A[N/2])); done sum=$((${n//-})) # lazy abs() echo "7A: $sum" declare -i sum2=0 -for k in ${A[@]}; do +for k in "${A[@]}"; do dist=$((k-avg)); dist=${dist/-} sum2+=$((dist*(dist+1)/2)) done diff --git a/2021/README.md b/2021/README.md index 1e08e53..1c29df0 100644 --- a/2021/README.md +++ b/2021/README.md @@ -35,6 +35,6 @@ Description of what I'm doing. Contains spoilers.... 1. Use the median. 2. Use the mean. -### 07.sh +### 08.sh 1. Simple grep to fish out the output digits and isolate the ones with 2-4 or 7 digits. 2. A damn bother, since the letters were scrambled. Assigned the numbers based on length. The 5-6 length ones got special handling, by checking the length after removing the letters that make up 4 and 7. That was enough to identify every one. From 5f8848844ba89aa93a1bcf4cd2239cc75d87b27c Mon Sep 17 00:00:00 2001 From: Einar Jon Gunnarsson Date: Sun, 12 Dec 2021 21:34:02 +0100 Subject: [PATCH 06/10] 2021: Days 9-12 --- 2021/09.sh | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2021/10.sh | 17 +++++++++++++ 2021/11.sh | 29 +++++++++++++++++++++ 2021/12.sh | 27 ++++++++++++++++++++ 2021/README.md | 23 +++++++++++++++-- 5 files changed, 163 insertions(+), 2 deletions(-) create mode 100755 2021/09.sh create mode 100755 2021/10.sh create mode 100755 2021/11.sh create mode 100755 2021/12.sh diff --git a/2021/09.sh b/2021/09.sh new file mode 100755 index 0000000..c82023e --- /dev/null +++ b/2021/09.sh @@ -0,0 +1,69 @@ +#! /usr/bin/env bash +A=($(< "${1:-9.txt}")) +B=(9${A//?/9}9); for i in "${A[@]}"; do B+=(9${i}9); done; B+=($B); C=("${B[@]}"); +n=${#A} N=${#A[@]} +declare -A LOWS +for ((y=1; y<=N; ++y)); do + for ((x=1; x<=n; ++x)); do + while (( ${B[y]:x:1} > ${B[y]:x+1:1} )); do ((++x)); done + low=${B[y]:x:1} + if (( low < ${B[y]:x-1:1} && low < ${B[y]:x+1:1} + && low < ${B[y-1]:x:1} && low < ${B[y+1]:x:1})); then + LOWS[$y,$x]=$low + fi + done +done +printf -v sum "+%s" "${LOWS[@]}" +echo "9A: $((sum + ${#LOWS[@]}))" + +C=(${C[@]//[0-8]/-}) c=0 +F=({a..z} {A..Z} {0..8} + _ / =) +idx=($(printf "%s\n" "${!LOWS[@]}" | sort -n)) +for i in "${idx[@]}"; do + LOWS[$i]=${F[c]} + x=${i/*,} y=${i/,*} + C[y]=${C[y]:0:x}${F[c]}${C[y]:x+1} + for k in 1 -1; do + j=$k + while [[ ${C[y+j]:x:1} != 9 ]]; do + C[y+j]=${C[y+j]:0:x}${F[c]}${C[y+j]:x+1} + ((j+=k)); + done + done + (( ++c >= ${#F[@]} && ++d)) && c=0 +done +# Terrible "grow" +for i in {1..6}; do + C=($(printf "%s\n" "${C[@]}" | sed -e "s/-\([^9-]\)/\1\1/g;s/\([^9-]\)-/\1\1/g")) +done +while [[ "${C[*]}" == *-* ]]; do + #echo "round $((++round))" + for y in ${!C[@]}; do + [[ ${C[y]} != *-* ]] && continue + minus=($(sed "s/./&\n/g" <<< ${C[y]:1} | grep -n '-')) + for x in ${minus[@]//:*}; do + for j in 1 -1; do + k=$j + while [[ ${C[y+k]:x:1} == - ]]; do ((k+=j)); done + p=${C[y+k]:x:1} + if [[ $p != 9 ]]; then + while ((k+=-j)); do C[y+k]=${C[y+k]:0:x}$p${C[y+k]:x+1}; done + C[y]=${C[y]:0:x}$p${C[y]:x+1} + break + fi + done + done + done + for i in {1..2}; do + C=($(printf "%s\n" "${C[@]}" | sed -e "s/-\([^9-]\)/\1\1/g;s/\([^9-]\)-/\1\1/g")) + done +done + +AREA=() +for i in ${F[@]}; do + while read -r A;do + AREA+=(${#A}:$A) + done < <(printf "%s\n" "${C[@]}" | grep -a1 $i | tr -cd "$i-" | tr -s '-' '\n') +done +BIG=($(printf "%s\n" "${AREA[@]//:*}" | sort -nr)) +echo "9B: $((BIG[0]*BIG[1]*BIG[2]))" diff --git a/2021/10.sh b/2021/10.sh new file mode 100755 index 0000000..1b17a0c --- /dev/null +++ b/2021/10.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +A=($(tr '()[]{}<>' '1a2b3c4d' < "${1:-10.txt}")) +while [[ ${A[*]} =~ (1a|2b|3c|4d) ]]; do + A=(${A[@]//1a}); A=(${A[@]//2b}); A=(${A[@]//3c}); A=(${A[@]//4d}) +done +# shellcheck disable=SC2034 +a=3 b=57 c=1197 d=25137 TMP=(${A[@]//[1234]}) C=() +printf -v sum "+%.1s" "${TMP[@]}" # TMP only contains closing brackets. Print first char +echo "10A: $((sum))" +while read -r -a B; do + sum=0 + for i in "${B[@]}"; do sum=$((sum*5+i)); done + C+=($sum) +done < <( printf "%s\n" "${A[@]}" | grep -v -E '[a-d]' | rev | sed 's/./ &/g') +C=($(printf "%s\n" "${C[@]}" | sort -n )) +N=${#C[@]} +echo "10B: ${C[N/2]}" diff --git a/2021/11.sh b/2021/11.sh new file mode 100755 index 0000000..7b36649 --- /dev/null +++ b/2021/11.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +A=($(sed -e 's/^/X/;s/./& /g' "${1:-11.txt}")) +Zeros=${A[*]//*/0} flashes=0 last=0 idx=(${!A[@]}) +A+=(X X X X X X X X X X X X) +A=(${A[@]//X/-999999999}) +flash(){ + local n=$1 j cur + ((++flashes)) + for j in -12 -11 -10 -1 1 10 11 12; do + cur=$((n+j)) + ((++A[cur] >= 10 && F[cur]++ == 0 )) && flash $cur + done +} +round(){ + F=(${Zeros}) + for i in ${idx[@]}; do ((++A[i] >= 10 && F[i]++ == 0)) && flash $i ; done + A=(${A[@]//1?/0}) + #A=(${A[@]//-99??/-9999}) +} +for rounds in {1..100}; do + round +done +echo "11A: $flashes" +while ((flashes-last != 100)); do + ((last=flashes,rounds++)) + round +done +echo "11B: $rounds" diff --git a/2021/12.sh b/2021/12.sh new file mode 100755 index 0000000..4d76009 --- /dev/null +++ b/2021/12.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +declare -A Next=() +IFS=$' -\n' +while read -r a b; do + [[ $a != start ]] && Next[$b]+="$a " + [[ $b != start ]] && Next[$a]+="$b " +done < "${1:-12.txt}" +#for i in "${!Next[@]}"; do echo "$i: '${Next[$i]}'"; done + +r() { + local route=$1 cur=$2 visited=$3 k deeper=false + if [[ $cur == end ]]; then + PATHS+=("$route:$cur") + elif [[ $cur != "${cur,,}" || $route != *:${cur}:* + || ($cur == "${cur,,}" && $((visited++)) == 0) ]]; then + for k in ${Next[$cur]}; do + r "$route:$cur" "$k" $visited + done + fi +} + +PATHS=() +r "" start 1 +echo "12A: ${#PATHS[@]}" +PATHS=() +r "" start 0 +echo "12B: ${#PATHS[@]}" diff --git a/2021/README.md b/2021/README.md index 1c29df0..2eaa285 100644 --- a/2021/README.md +++ b/2021/README.md @@ -21,7 +21,7 @@ Description of what I'm doing. Contains spoilers.... 2. Same function, but change the input for every char. ### 04.sh - 1. Use an array to store all lines/rows of a bingo card. Delete numbers from all lines until a line is empty. + 1. Use an array to store all lines/rows of a bingo card. Delete numbers from all lines until a line is empty. 2. Remove a card when a line is empty. Keep going until all cards are gone. ### 05.sh @@ -29,7 +29,8 @@ Description of what I'm doing. Contains spoilers.... 2. Mark diagonals on a second hash table. Add the first hash table to it and return a count of points that are != 1. ### 06.sh - Store a count of the fishes each day in a circular buffer, with the current 0-day at n%9. Bash arrays are circular by default. + 80 rounds can be done in half a second with string shenaningans, but 256 days would take terabytes of RAM, and lots of time. + Instead store a count of the fishes each day in a circular buffer, with the current 0-day at n%9. Bash arrays are circular by default. ### 07.sh 1. Use the median. @@ -38,3 +39,21 @@ Description of what I'm doing. Contains spoilers.... ### 08.sh 1. Simple grep to fish out the output digits and isolate the ones with 2-4 or 7 digits. 2. A damn bother, since the letters were scrambled. Assigned the numbers based on length. The 5-6 length ones got special handling, by checking the length after removing the letters that make up 4 and 7. That was enough to identify every one. + +### 09.sh + 1. For each line, go forward in the string while the next char is lower. Once you reach that, add a low point if all 4 neighbours are higher. + 2. Clean out the map so that all numbers except edges and 9s are empty. Add each low point from part 1 with a different symbol. + Use terrible bash to grow the symbols until the whole map is filled. Count the size of each symbol block. + +### 10.sh + Renamed the brackets for easier grok-ing, and so that I could assign values to each one. + 1. Keep removing "innermost" bracket pairs until none remains, then remove opening brackets and sum up the values in the first column, if any. + 2. Remove any string containing a closing bracket, reverse the rest. Instead of adding a closing bracket, add the value for each opening bracket at a time. + +### 11.sh + 1. Convert the map to a 1D array, and add -9999999 to the sides so I don\'t need to think about edges. Recursve function to flash the octopi. + 2. Run until all fields flash at once. + +### 12.sh + 1. Brute force. Simplified version of the recursive functions of 2015 (9 and 13). Collect a hashmap wit the destinations for each cave. Remove "start" from the destinations to simplify coding. + 2. Add a dumb check to allow the first lowercase cave twice. Takes way too long to run. From a3a8c5d12670d514f5b1c1be783beb3f03f5144a Mon Sep 17 00:00:00 2001 From: Einar Jon Gunnarsson Date: Sun, 12 Dec 2021 21:40:15 +0100 Subject: [PATCH 07/10] 2021/08: Simplify logic No need to collect every number to the T array. Just identify 4 and 7, and use those to find the differences between 2,3,5 and 6,9,0. --- 2021/08.sh | 45 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/2021/08.sh b/2021/08.sh index e578042..31579d7 100755 --- a/2021/08.sh +++ b/2021/08.sh @@ -4,39 +4,28 @@ printf "8A: " cut -d\| -f 2 "$input" | grep -Eo "[a-g]+" | grep -cE "^([a-g]{2,4}|[a-g]{7})$" sum="" while read -r -a A; do - T=() P235=() P690=() n="" + T4="" T7="" n="" for i in "${A[@]:0:10}"; do - case ${#i} in - 2) T[1]=$i;; - 3) T[7]=$i;; - 4) T[4]=$i;; - 5) P235+=($i);; - 6) P690+=($i);; - 7) T[8]=$i;; + case ${#i} in # Just find 4 and 7, ignore the rest + 3) T7=$i; [[ -n $T4 ]] && break;; + 4) T4=$i; [[ -n $T7 ]] && break;; esac done - for i in "${P235[@]}"; do - if [[ ${i//[${T[4]}]} == ??? ]]; then T[2]=$i - elif [[ ${i//[${T[7]}]} == ?? ]]; then T[3]=$i - else T[5]=$i - fi - done - for i in "${P690[@]}"; do - if [[ ${i//[${T[7]}]} == ???? ]]; then T[6]=$i - elif [[ ${i//[${T[4]}]} == ?? ]]; then T[9]=$i - else T[0]=$i - fi - done for i in "${A[@]:11}"; do - case ${#i} in - 2) n+=1;; - 3) n+=7;; - 4) n+=4;; - 5) for k in 2 3 5 ?; do [[ -z ${i//[${T[k]}]} ]] && break; done; n+=$k;; - 6) for k in 6 9 0 ?; do [[ -z ${i//[${T[k]}]} ]] && break; done; n+=$k;; - 7) n+=8;; + case ${#i},${i//[$T4]},${i//[$T7]} in + 2,*) n+=1;; + 3,*) n+=7;; + 4,*) n+=4;; + 5,???,*) n+=2;; + 5,*,??) n+=3;; + 5,*) n+=5;; + 6,*,????) n+=6;; + 6,??,*) n+=9;; + 6,*) n+=0;; + 7,*) n+=8;; + *) echo ERROR: ${#i},${i//[$T4]},${i//[$T7]}; break 2;; esac done - sum+=+$((10#$n)) # leading 0 means octal. A '?' will throw an error here + sum+=+$((10#$n)) done < "${input}" echo "8B: $((sum))" From ec029a8c23d38676ebe83e91d0013ad27ccbfe7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Einar=20J=C3=B3n?= Date: Sun, 12 Dec 2021 22:07:11 +0100 Subject: [PATCH 08/10] 2021: Update README.md --- 2021/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/2021/README.md b/2021/README.md index 2eaa285..42ec021 100644 --- a/2021/README.md +++ b/2021/README.md @@ -51,9 +51,9 @@ Description of what I'm doing. Contains spoilers.... 2. Remove any string containing a closing bracket, reverse the rest. Instead of adding a closing bracket, add the value for each opening bracket at a time. ### 11.sh - 1. Convert the map to a 1D array, and add -9999999 to the sides so I don\'t need to think about edges. Recursve function to flash the octopi. + 1. Convert the map to a 1D array, and add -9999999 to the sides so I don\'t need to think about edges. Recursive function to flash the octopi. 2. Run until all fields flash at once. ### 12.sh - 1. Brute force. Simplified version of the recursive functions of 2015 (9 and 13). Collect a hashmap wit the destinations for each cave. Remove "start" from the destinations to simplify coding. + 1. Brute force. Simplified version of the recursive functions of 2015 (9 and 13). Collect a hashmap with the destinations for each cave. Remove "start" from the destinations to simplify coding. 2. Add a dumb check to allow the first lowercase cave twice. Takes way too long to run. From 4d1498400603bb20b9c1c01b2ad7d205dc8b4cca Mon Sep 17 00:00:00 2001 From: Einar Jon Gunnarsson Date: Tue, 14 Dec 2021 21:55:44 +0100 Subject: [PATCH 09/10] 2021: Days 13 and 14 --- 2021/13.sh | 36 ++++++++++++++++++++++++++++++++++++ 2021/14.sh | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2021/README.md | 8 ++++++++ 3 files changed, 88 insertions(+) create mode 100755 2021/13.sh create mode 100755 2021/14.sh diff --git a/2021/13.sh b/2021/13.sh new file mode 100755 index 0000000..c1c29a3 --- /dev/null +++ b/2021/13.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# Oneliner for part 1. First fold hardcoded. +#echo "13A: $(while read x y; do ((x >655)) && x=$((2*655-x)); echo $x,$y; done < <(grep , 13.txt| tr , ' ') | sort -u | wc -l)" + +fold_x() { + local n=$1 C=(${DOTS[@]}) i + for i in "${!C[@]}"; do + x=${C[i]//,*} + ((x>n)) && C[i]=$(((2*n-x))),${C[i]/*,} + done + DOTS=($(printf "%s\n" "${C[@]}"| sort -n | uniq)) +} +fold_y() { + local n=$1 C=(${DOTS[@]}) i + for i in "${!C[@]}"; do + y=${C[i]//*,} + ((y>n)) && C[i]=${C[i]/,*},$(((2*n-y))) + done + DOTS=($(printf "%s\n" "${C[@]}"| sort -n | uniq)) +} + +DOTS=($(grep , "${1:-13.txt}")) +FOLDS=($(grep -o '.=.*' "${1:-13.txt}")) +fold_"${FOLDS[0]/=*}" "${FOLDS[0]:2}" +echo "13A: ${#DOTS[@]}" +for line in "${FOLDS[@]:1}"; do + xy=${line/=*} + "fold_$xy" "${line:2}" +done +TEXT=() spaces=" " +for i in "${!DOTS[@]}"; do + x=${DOTS[i]//,*} y=${DOTS[i]//*,} len=${#TEXT[y]} + TEXT[y]+="${spaces:0:x-len}#" +done +echo "13B:" +printf "%s\n" "${TEXT[@]}" diff --git a/2021/14.sh b/2021/14.sh new file mode 100755 index 0000000..f07d8e2 --- /dev/null +++ b/2021/14.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +input=${1:-14.txt} +declare -A SET=() +declare -iA COUNT=() +POL=$(head -1 "${input}") +while read -r a _ b;do + SET[$a]="${a:0:1}$b $b${a:1}"; +done < <( grep ' -> ' "${input}") +for ((i=0; i<${#POL}-1;i++)); do + j=${POL:i:2} + COUNT[$j]+=1; +done + +solve() { + for ((; round < $1; round++)); do + local -iA NEW_COUNT=() + for j in "${!COUNT[@]}"; do + for k in ${SET[$j]}; do + NEW_COUNT[$k]+=${COUNT[$j]} + done + done + COUNT=() + for j in "${!NEW_COUNT[@]}"; do COUNT[$j]=${NEW_COUNT[$j]}; done + done +} +diff() { + local -n ans=$1 + local -Ai ALPHA=([${POL:0:1}]=1 [${POL: -1}]=1) # ends are only counted once + for k in "${!COUNT[@]}"; do + ALPHA[${k:0:1}]+=$((COUNT["$k"])) + ALPHA[${k:1}]+=$((COUNT["$k"])) + done + FREQ=($(printf "%s\n" "${ALPHA[@]}" | sort -n)) + #shellcheck disable=SC2034 + ans=$((FREQ[-1]/2-FREQ[0]/2)) +} + +round=0 +for i in 10 40;do + solve $i + diff "ANS[n++]" +done +echo "14A: ${ANS[0]}" +echo "14B: ${ANS[1]}" diff --git a/2021/README.md b/2021/README.md index 42ec021..1bc1077 100644 --- a/2021/README.md +++ b/2021/README.md @@ -57,3 +57,11 @@ Description of what I'm doing. Contains spoilers.... ### 12.sh 1. Brute force. Simplified version of the recursive functions of 2015 (9 and 13). Collect a hashmap with the destinations for each cave. Remove "start" from the destinations to simplify coding. 2. Add a dumb check to allow the first lowercase cave twice. Takes way too long to run. + +### 13.sh + 1. Functions fold_x/fold_y for easier handling. Fold and remove duplicates for first line. + 2. Repeat for rest of the lines. Collect space-delimited dots in an array of strings. Print the array. + +### 14.sh + Collect the conversions in an array. Count the number of pairs in the initial polymer. For each polymer, convert the input to 2 outputs. + For the final count, every char is part of 2 pairs except the ends, so add 1 to the ends and then divide by 2 for the final number. From 9410a802cdd8773ba04a67d2253f4839154436cc Mon Sep 17 00:00:00 2001 From: Einar Jon Gunnarsson Date: Wed, 12 Jan 2022 09:15:52 +0100 Subject: [PATCH 10/10] 2021: Shellcheck fixes and cleanup Minor cleanup in 4, 7 and 9-12 --- 2021/01.sh | 2 +- 2021/02.sh | 2 +- 2021/03.sh | 2 +- 2021/04.sh | 16 +++++++--------- 2021/07.sh | 13 ++++++------- 2021/08.sh | 2 +- 2021/09.sh | 16 ++++++++-------- 2021/10.sh | 8 +++++--- 2021/11.sh | 11 ++++++----- 2021/12.sh | 19 ++++++++++--------- 10 files changed, 46 insertions(+), 45 deletions(-) diff --git a/2021/01.sh b/2021/01.sh index 37cb768..42251a4 100755 --- a/2021/01.sh +++ b/2021/01.sh @@ -1,4 +1,4 @@ -#! /usr/bin/env bash +#!/usr/bin/env bash A=($(< "${1:-1.txt}")); a=${A[0]}; ANS=0 for b in "${A[@]:1}"; do ((b>a && ++ANS)); a=$b; done echo "1A: ${ANS}" diff --git a/2021/02.sh b/2021/02.sh index 3ccc8f5..534158c 100755 --- a/2021/02.sh +++ b/2021/02.sh @@ -1,4 +1,4 @@ -#! /usr/bin/env bash +#!/usr/bin/env bash input=${1:-2.txt} declare -i X=0 Y=0 y=0 while read -r dir n; do diff --git a/2021/03.sh b/2021/03.sh index 65604ce..3937153 100755 --- a/2021/03.sh +++ b/2021/03.sh @@ -1,4 +1,4 @@ -#! /usr/bin/env bash +#!/usr/bin/env bash nextchar() { local -n most=$1 least=$2 in=$3 local all; all=$(printf "%s\n" "${in[@]}" | cut -c"$4" | tr -d '\n' ) diff --git a/2021/04.sh b/2021/04.sh index 5f44540..0044255 100755 --- a/2021/04.sh +++ b/2021/04.sh @@ -1,12 +1,11 @@ -#! /usr/bin/env bash -declare -i i +#!/usr/bin/env bash +declare -i i j=0 while read -r a b c d e; do if (( ${#NUMBERS[@]} == 0 )); then NUMBERS=(${a//,/ }); elif [[ -n $a ]]; then C[i++]="-$a--$b--$c--$d--$e-" # rows - j=$((10*(i/10))) # columns C[j+5]+="-$a-";C[j+6]+="-$b-";C[j+7]+="-$c-";C[j+8]+="-$d-";C[j+9]+="-$e-"; - ((i%5==0)) && i+=5 + ((i%5==0)) && i+=5 j+=10 fi done < "${1:-4.txt}" idx=(${!C[@]}) @@ -17,16 +16,15 @@ for k in "${!NUMBERS[@]}"; do (( ${#B[@]} != ${#C[@]} )) && break done for i in "${idx[@]}"; do [[ -z ${C[i]} ]] && break; done -j=$((10*(i/10))) # columns +j=$((10*(i/10))) # card number printf -v sum "%s" "${C[@]:j:5}" sum=${sum//--/+}; sum=${sum//-} -echo "12A: $((n*(sum)))" +echo "12A: $((n*sum))" printf -v WON "=%d=" {0..990..10} WON=${WON/=$j=} # only do each card once for i in "${idx[@]:j:10}"; do C[i]=DONE; done -for k in "${!NUMBERS[@]}"; do - n=${NUMBERS[k]} +for n in "${NUMBERS[@]:k+1}"; do C=("${C[@]//-$n-}") B=(${C[@]}) if (( ${#B[@]} != ${#C[@]} )); then @@ -41,4 +39,4 @@ for k in "${!NUMBERS[@]}"; do done printf -v sum "%s" "${C[@]:j:5}" sum=${sum//--/+}; sum=${sum//-} -echo "12B: $((n*(sum)))" +echo "12B: $((n*sum))" diff --git a/2021/07.sh b/2021/07.sh index 952e9f4..9efd043 100755 --- a/2021/07.sh +++ b/2021/07.sh @@ -1,14 +1,13 @@ -#!/bin/bash +#!/usr/bin/env bash input=$(< "${1:-7.txt}") A=($(echo -e "${input//,/\\n}" | sort -n)) -N=${#A[@]} -avg=$(((${input//,/+})/N)) -n=""; for k in "${A[@]}";do n+=+$((k-A[N/2])); done -sum=$((${n//-})) # lazy abs() -echo "7A: $sum" -declare -i sum2=0 +N=${#A[@]} n="" +declare -i avg=$(((${input//,/+})/N)) sum2=0 for k in "${A[@]}"; do + n+=+$((k-A[N/2])); dist=$((k-avg)); dist=${dist/-} sum2+=$((dist*(dist+1)/2)) done +sum=${n//-} # lazy abs() +echo "7A: $((sum))" echo "7B: $sum2" diff --git a/2021/08.sh b/2021/08.sh index 31579d7..fd71b08 100755 --- a/2021/08.sh +++ b/2021/08.sh @@ -23,7 +23,7 @@ while read -r -a A; do 6,??,*) n+=9;; 6,*) n+=0;; 7,*) n+=8;; - *) echo ERROR: ${#i},${i//[$T4]},${i//[$T7]}; break 2;; + *) echo "ERROR: ${#i},${i//[$T4]},${i//[$T7]}"; break 2;; esac done sum+=+$((10#$n)) diff --git a/2021/09.sh b/2021/09.sh index c82023e..4b4a9a9 100755 --- a/2021/09.sh +++ b/2021/09.sh @@ -1,6 +1,6 @@ -#! /usr/bin/env bash +#!/usr/bin/env bash A=($(< "${1:-9.txt}")) -B=(9${A//?/9}9); for i in "${A[@]}"; do B+=(9${i}9); done; B+=($B); C=("${B[@]}"); +B=(9${A//?/9}9); for i in "${A[@]}"; do B+=(9${i}9); done; B+=(${B[0]}); C=("${B[@]}"); n=${#A} N=${#A[@]} declare -A LOWS for ((y=1; y<=N; ++y)); do @@ -17,7 +17,7 @@ printf -v sum "+%s" "${LOWS[@]}" echo "9A: $((sum + ${#LOWS[@]}))" C=(${C[@]//[0-8]/-}) c=0 -F=({a..z} {A..Z} {0..8} + _ / =) +F=({a..z} {A..Z} {0..8} + _ / "=") idx=($(printf "%s\n" "${!LOWS[@]}" | sort -n)) for i in "${idx[@]}"; do LOWS[$i]=${F[c]} @@ -38,10 +38,10 @@ for i in {1..6}; do done while [[ "${C[*]}" == *-* ]]; do #echo "round $((++round))" - for y in ${!C[@]}; do + for y in "${!C[@]}"; do [[ ${C[y]} != *-* ]] && continue - minus=($(sed "s/./&\n/g" <<< ${C[y]:1} | grep -n '-')) - for x in ${minus[@]//:*}; do + minus=($(sed "s/./&\n/g" <<< "${C[y]:1}" | grep -n '-')) + for x in "${minus[@]//:*}"; do for j in 1 -1; do k=$j while [[ ${C[y+k]:x:1} == - ]]; do ((k+=j)); done @@ -60,10 +60,10 @@ while [[ "${C[*]}" == *-* ]]; do done AREA=() -for i in ${F[@]}; do +for i in "${F[@]}"; do while read -r A;do AREA+=(${#A}:$A) - done < <(printf "%s\n" "${C[@]}" | grep -a1 $i | tr -cd "$i-" | tr -s '-' '\n') + done < <(printf "%s\n" "${C[@]}" | grep -a1 "$i" | tr -cd "$i-" | tr -s '-' '\n') done BIG=($(printf "%s\n" "${AREA[@]//:*}" | sort -nr)) echo "9B: $((BIG[0]*BIG[1]*BIG[2]))" diff --git a/2021/10.sh b/2021/10.sh index 1b17a0c..f7613c5 100755 --- a/2021/10.sh +++ b/2021/10.sh @@ -2,16 +2,18 @@ A=($(tr '()[]{}<>' '1a2b3c4d' < "${1:-10.txt}")) while [[ ${A[*]} =~ (1a|2b|3c|4d) ]]; do A=(${A[@]//1a}); A=(${A[@]//2b}); A=(${A[@]//3c}); A=(${A[@]//4d}) + echo $((++i)) done +# P1 only contains closing brackets. P2 only contains lines with no closing brackets # shellcheck disable=SC2034 -a=3 b=57 c=1197 d=25137 TMP=(${A[@]//[1234]}) C=() -printf -v sum "+%.1s" "${TMP[@]}" # TMP only contains closing brackets. Print first char +a=3 b=57 c=1197 d=25137 P1=(${A[@]//[1234]}) P2=(${A[@]/*[^1234]*}) C=() +printf -v sum "+%.1s" "${P1[@]}" # Only print first char echo "10A: $((sum))" while read -r -a B; do sum=0 for i in "${B[@]}"; do sum=$((sum*5+i)); done C+=($sum) -done < <( printf "%s\n" "${A[@]}" | grep -v -E '[a-d]' | rev | sed 's/./ &/g') +done < <(printf "%s\n" "${P2[@]}" | rev | sed 's/./ &/g') C=($(printf "%s\n" "${C[@]}" | sort -n )) N=${#C[@]} echo "10B: ${C[N/2]}" diff --git a/2021/11.sh b/2021/11.sh index 7b36649..34865de 100755 --- a/2021/11.sh +++ b/2021/11.sh @@ -1,22 +1,23 @@ #!/usr/bin/env bash A=($(sed -e 's/^/X/;s/./& /g' "${1:-11.txt}")) -Zeros=${A[*]//*/0} flashes=0 last=0 idx=(${!A[@]}) +flashes=0 last=0 idx=(${!A[@]}) A+=(X X X X X X X X X X X X) A=(${A[@]//X/-999999999}) flash(){ local n=$1 j cur ((++flashes)) + # hardcoded neighbours. There's an X on one side, so Y-offset is cols+1 for j in -12 -11 -10 -1 1 10 11 12; do cur=$((n+j)) - ((++A[cur] >= 10 && F[cur]++ == 0 )) && flash $cur + ((++A[cur] >= 10 && FLASHED[cur]++ == 0 )) && flash $cur done } round(){ - F=(${Zeros}) - for i in ${idx[@]}; do ((++A[i] >= 10 && F[i]++ == 0)) && flash $i ; done - A=(${A[@]//1?/0}) + FLASHED=() + for i in "${idx[@]}"; do ((++A[i] >= 10 && FLASHED[i]++ == 0)) && flash "$i"; done #A=(${A[@]//-99??/-9999}) + A=(${A[@]//1?/0}) } for rounds in {1..100}; do round diff --git a/2021/12.sh b/2021/12.sh index 4d76009..1a60946 100755 --- a/2021/12.sh +++ b/2021/12.sh @@ -1,27 +1,28 @@ #!/usr/bin/env bash -declare -A Next=() +declare -A Next=() BIG=() IFS=$' -\n' while read -r a b; do [[ $a != start ]] && Next[$b]+="$a " [[ $b != start ]] && Next[$a]+="$b " done < "${1:-12.txt}" +for i in "${!Next[@]}"; do [[ -z ${i//[A-Z]} ]] && BIG[$i]=1; done #for i in "${!Next[@]}"; do echo "$i: '${Next[$i]}'"; done r() { - local route=$1 cur=$2 visited=$3 k deeper=false + local route=$1 cur=$2 visited=$3 k if [[ $cur == end ]]; then - PATHS+=("$route:$cur") - elif [[ $cur != "${cur,,}" || $route != *:${cur}:* - || ($cur == "${cur,,}" && $((visited++)) == 0) ]]; then + PATHS+=1 + elif [[ -n ${BIG[$cur]} || $route != *:${cur}:* ]] \ + || ((visited++ == 0)); then for k in ${Next[$cur]}; do r "$route:$cur" "$k" $visited done fi } -PATHS=() +declare -i PATHS=0 r "" start 1 -echo "12A: ${#PATHS[@]}" -PATHS=() +echo "12A: ${PATHS}" +PATHS=0 r "" start 0 -echo "12B: ${#PATHS[@]}" +echo "12B: ${PATHS}"