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..42251a4 --- /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..534158c --- /dev/null +++ b/2021/02.sh @@ -0,0 +1,20 @@ +#!/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 + up) Y+=-$n;; + down) Y+=$n;; + forward) X+=$n; y+=$((Y*n));; + esac +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}" | 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}") <(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}" )|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 new file mode 100755 index 0000000..3937153 --- /dev/null +++ b/2021/03.sh @@ -0,0 +1,28 @@ +#!/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' ) + 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="" +for i in "${idx[@]:1:$len}"; do + nextchar g e A "$i" +done +echo "3A: $g*$e = $(($((2#$g))*$((2#$e))))" +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 +# shellcheck disable=SC2128 +echo "3B: $O*$C = $(($((2#$O))*$((2#$C))))" diff --git a/2021/04.sh b/2021/04.sh new file mode 100755 index 0000000..0044255 --- /dev/null +++ b/2021/04.sh @@ -0,0 +1,42 @@ +#!/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 + 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 j+=10 + 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))) # card number +printf -v sum "%s" "${C[@]:j:5}" +sum=${sum//--/+}; sum=${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 n in "${NUMBERS[@]:k+1}"; do + 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))" 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..afbc848 --- /dev/null +++ b/2021/06.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +declare -i A=(0 0 0 0 0 0 0 0 0) n=0 +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)) + A[i-2]+=${A[i]} + done + sum=0; for i in "${!A[@]}"; do ((sum+=A[i])); done +} +solve 80 +echo "6A: $sum" +solve 256 +echo "6B: $sum" diff --git a/2021/07.sh b/2021/07.sh new file mode 100755 index 0000000..9efd043 --- /dev/null +++ b/2021/07.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +input=$(< "${1:-7.txt}") +A=($(echo -e "${input//,/\\n}" | sort -n)) +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 new file mode 100755 index 0000000..fd71b08 --- /dev/null +++ b/2021/08.sh @@ -0,0 +1,31 @@ +#!/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 + T4="" T7="" n="" + for i in "${A[@]:0:10}"; do + 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 "${A[@]:11}"; do + 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)) +done < "${input}" +echo "8B: $((sum))" diff --git a/2021/09.sh b/2021/09.sh new file mode 100755 index 0000000..4b4a9a9 --- /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[0]}); 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..f7613c5 --- /dev/null +++ b/2021/10.sh @@ -0,0 +1,19 @@ +#!/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}) + 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 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" "${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 new file mode 100755 index 0000000..34865de --- /dev/null +++ b/2021/11.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +A=($(sed -e 's/^/X/;s/./& /g' "${1:-11.txt}")) +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 && FLASHED[cur]++ == 0 )) && flash $cur + done +} +round(){ + 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 +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..1a60946 --- /dev/null +++ b/2021/12.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +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 + if [[ $cur == end ]]; 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 +} + +declare -i PATHS=0 +r "" start 1 +echo "12A: ${PATHS}" +PATHS=0 +r "" start 0 +echo "12B: ${PATHS}" 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 new file mode 100644 index 0000000..1bc1077 --- /dev/null +++ b/2021/README.md @@ -0,0 +1,67 @@ +# 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 + 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. + 2. Use the mean. + +### 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. 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 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.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: