Skip to content

Commit f6f8739

Browse files
committed
2020: Cleanup and deuglify
Use globs when possible, and avoid pipes/subshells. 3, 9 and 16 had small errors that could result in the wrong answer for part 2. 19 speeded up 15x by using named variables instead of subshells. No subshells, shorter regex, and cache hits are 6x better.
1 parent 49d94c1 commit f6f8739

File tree

12 files changed

+75
-73
lines changed

12 files changed

+75
-73
lines changed

01.sh

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#! /usr/bin/env bash
2-
input=${1:-1.txt}
3-
A=($(sort -n "$input"));
4-
for a in "${A[@]}"; do grep -q -- ^$((2020-a))$ "$input" && break; done
5-
echo "1A: $((2020-a)) + $a = $(((2020-a)*a))"
6-
b=:; for a in "${A[@]}";do for i in "${A[@]}"; do grep -q -- ^$((2020-a-i))$ "$input" && b=break; $b; done; $b; done
7-
echo "1B: $((2020-a-i)) + $a + $i = $(((2020-a-i)*a*i))"
2+
A=($(sort -n "${1:-1.txt}"))
3+
for i in "${A[@]}"; do B[i]=1; done
4+
for a in "${A[@]}"; do ((b=2020-a, B[b] > 0)) && break; done
5+
echo "1A: $b + $a = $((b*a))"
6+
for i in "${!A[@]}";do for b in "${A[@]:i+1}"; do
7+
((a=A[i], c=2020-a-b, c > 0 && B[c] > 0)) && break 2;
8+
done; done
9+
echo "1B: $c + $a + $b = $((c*a*b))"

02.sh

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
#! /usr/bin/env bash
2-
ans=0
3-
IFS=$'-:\ \n'
4-
while read -r m M b c; do x=${c//[^$b]}; (( ${#x} >= m && ${#x} <= M && ++ans)); done < "${1:-2.txt}"
2+
ans=0 ans2=0
3+
IFS=$' -:\n'
4+
while read -r m M b c; do
5+
x=${c//[^$b]}; y=${c:m-1:1}; z=${c:M-1:1};
6+
(( ${#x} >= m && ${#x} <= M && ++ans ))
7+
[[ $y != "$z" ]] && [[ $b == "$y" || $b == "$z" ]] && ((++ans2))
8+
done < "${1:-2.txt}"
59
echo "2A: $ans"
6-
ans=0
7-
while read -r m M b c; do x=${c:m-1:1}; y=${c:M-1:1}; [[ $x != "$y" ]] && [[ $b == "$x" || $b == "$y" ]] && ((++ans)); done < "${1:-2.txt}"
8-
echo "2B: $ans"
10+
echo "2B: $ans2"

03.sh

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
#! /usr/bin/env bash
2-
A=($(< "${1:-3.txt}")); l=${#A[0]}; k=0; j=3; total=1; x=""
3-
for i in "${A[@]}"; do x+=${i:k:1}; ((k=(k+j)%l)); done; x=${x//\.}
4-
echo "3A: ${#x}"
5-
idx2=$(seq 0 2 $((${#A[@]}-1)))
6-
for j in 1 3 5 7; do x=""; k=0; for i in "${A[@]}"; do x+=${i:k:1}; ((k=(k+j)%l)); done; x=${x//\.}; total+="*${#x}"; done
7-
x=""; k=0; for i in $idx2; do x+=${A[i]:k:1}; ((k=(k+2)%l)); done ; x=${x//\.}; total+="*${#x}"
8-
echo "3B: ${total:2} = $((total))"
2+
A=($(< "${1:-3.txt}")); l=${#A[0]}; N=${#A[@]}; k=0; j=3; x=""
3+
for i in "${A[@]}"; do x+=${i:k:1}; ((k=(k+j)%l)); done; x=${x//\.}; total=${#x}
4+
echo "3A: $total"
5+
for j in 1 5 7; do x=""; k=0; for i in "${A[@]}"; do x+=${i:k:1}; ((k=(k+j)%l)); done; x=${x//\.}; total+="*${#x}"; done
6+
x=""; k=0; for ((i=0;i<N;i+=2)); do x+=${A[i]:k:1}; ((k=(k+1)%l)); done ; x=${x//\.}; total+="*${#x}"
7+
echo "3B: ${total} = $((total))"

08.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ solve8 || echo "8A: $acc"
2020

2121
A=("${B[@]}");
2222
for k in "${!A[@]}"; do
23-
if [ ${A[k]:0:3} = nop ]; then A[k]=${A[k]/nop/jmp};
24-
elif [ ${A[k]:0:3} = jmp ]; then A[k]=${A[k]/jmp/nop};
23+
if [[ ${A[k]} = nop* ]]; then A[k]=jmp${A[k]:3};
24+
elif [[ ${A[k]} = jmp* ]]; then A[k]=nop${A[k]:3};
2525
else continue; fi
2626
solve8 && break
2727
A=("${B[@]}")

09.sh

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,22 @@
22
A=($(< "${1:-9.txt}"))
33
idx=(${!A[@]})
44
for i in "${idx[@]:25}"; do
5-
b=:
65
for j in "${idx[@]:i-25:25-1}"; do
7-
[[ ${A[j]} -ge ${A[i]} ]] && continue
6+
((A[j] >= A[i])) && continue
87
for k in "${idx[@]:j+1:i-j-1}"; do
9-
((A[j]+A[k] == A[i])) && b=break; $b
8+
((A[j]+A[k] == A[i])) && break 2
109
done
11-
$b
1210
done
13-
[ "$b" = ":" ] && echo "9A: line $i = ${A[i]}" && break
11+
((A[j]+A[k] != A[i])) && break
1412
done
13+
echo "9A: line $i = ${A[i]}"
1514

1615
k=0; j=0; sum=${A[j++]}
1716
while [ "$sum" != "${A[i]}" ]; do
18-
if [[ $sum -lt ${A[i]} ]]; then ((sum+=A[j++]))
19-
elif [[ $sum -gt ${A[i]} ]]; then ((sum-=A[k++]))
17+
if ((sum < A[i])); then ((sum+=A[j++]))
18+
elif ((sum > A[i])); then ((sum-=A[k++]))
2019
fi
21-
[[ $j -ge $i ]] && echo NOT FOUND && break
20+
((j >= i)) && echo NOT FOUND && break
2221
done
23-
B=($(printf "%s\n" "${A[*]:k:j-k}" | sort -n))
22+
B=($(printf "%s\n" "${A[@]:k:j-k}" | sort -n))
2423
echo "9B: $k..$j = $((B[0]+B[-1]))"

14.sh

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@ printf -v sum "+%s" "${mem[@]}"
1212
echo "14A: $((sum))"
1313

1414
r() {
15-
local x=${2/X/0}
16-
if [ "$x" = "$2" ]; then
17-
mem2[$1|(2#$x)]=$3
18-
else
19-
r "$1" "$x" "$3"
15+
if [[ $2 == *X* ]]; then
16+
r "$1" "${2/X/0}" "$3"
2017
r "$1" "${2/X/1}" "$3"
18+
else
19+
mem2[$1|(2#$2)]=$3
2120
fi
2221
}
2322

16.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A=($(grep "," "$input"))
66
sum=""
77
for i in "${!A[@]}"; do
88
for j in ${A[i]//,/ }; do
9-
(( j < min || j > max )) && sum+=+$j && A[i]=""
9+
(( j < min || j > max )) && sum+=+$j A[i]=""
1010
done
1111
done
1212
echo "16A: $((sum))"
@@ -20,7 +20,7 @@ while read -r name min1 max1 _ min2 max2; do # Read min/max values and field nam
2020
Cm1[i]=$min1; CM1[i]=$max1
2121
Cm2[i]=$min2; CM2[i]=$max2
2222
C[i++]=$name
23-
done < <(sed -n -e "/ .*:/ s/ /_/;/or/p" "$input")
23+
done < <(sed -n -e "/ .*:/s/ /_/;/or/p" "$input")
2424
IFS=$' \n'
2525
idx=${!C[*]}
2626
for line in "${B[@]}"; do
@@ -38,9 +38,9 @@ total=1
3838
while [[ "$oldC" != "${Cf[*]}" ]]; do
3939
oldC="${Cf[*]}"
4040
for i in $idx; do
41-
if [ ${#Cf[i]} = 1 ] ; then
41+
if [[ ${#Cf[i]} == 1 ]]; then
4242
x=${Cf[i]}
43-
[ "${C[i]:0:3}" = dep ] && total+="*${my_ticket[36#$i]}"
43+
[[ ${C[i]} = dep* ]] && total+="*${my_ticket[36#$x]}"
4444
Cf=("${Cf[@]//$x}")
4545
fi
4646
done

18.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ c() {
66
local i sum=0 op='+'
77
# shellcheck disable=SC2048
88
for i in $*; do
9-
if [[ $i = '+' || $i = '*' ]]; then
9+
if [[ $i == [+*] ]]; then
1010
op=$i
1111
else
1212
((sum$op=i))

19.sh

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,30 @@ for i in "${A[@]}"; do
99
done
1010

1111
IFS=$' \n'
12-
REGEX=()
12+
REGEX=() regex=""
13+
# shellcheck disable=SC2034,SC2048
1314
r(){
14-
local x=""
15-
# shellcheck disable=SC2048
16-
for i in $*; do
17-
if [ -z "${i/[ab|]}" ]; then
18-
x+=$i
19-
else
20-
[[ -z "${REGEX[$i]}" ]] && REGEX[$i]="($(r "${RULE[$i]}"))"
21-
x+="${REGEX[$i]}"
22-
#x+="($(r "${RULE[$i]}"))"
23-
fi
15+
local -n rx=$1; local x="" i
16+
for i in ${*:2}; do
17+
if [ -z "${i/[ab|]}" ]; then
18+
x+=$i
19+
else
20+
[[ -z "${REGEX[i]}" ]] && r "REGEX[$i]" "${RULE[i]}"
21+
x+=${REGEX[i]}
22+
fi
2423
done
25-
echo "$x"
24+
[[ ${x} == *\|* ]] && x="($x)" # Only brackets if needed
25+
rx=$x
2626
}
27-
regex=$(r 0)
28-
echo "19A: $(grep -E -c "^${regex}$" "$input")"
27+
r regex 0
28+
printf "19A: "; grep -E -c "^${regex}$" "$input"
2929

3030
#RULE[8]="42 8"
3131
#RULE[11]="42 31 | 42 11 31"
32-
r42="$(r 42)"
33-
r31="$(r 31)"
34-
r8="${r42}{1,5}"
35-
r11="${r42}${r31}"
36-
for n in {2..5}; do r11+="|${r42}{$n}${r31}{$n}"; done
37-
echo "19B: $(grep -E -c "^($r8)($r11)$" "$input")"
32+
REGEX[8]="(${REGEX[42]}{1,5})"
33+
REGEX[11]="${REGEX[42]}${REGEX[31]}"
34+
for n in {2..5}; do REGEX[11]+="|${REGEX[42]}{$n}${REGEX[31]}{$n}"; done
35+
REGEX[11]="(${REGEX[11]})"
36+
REGEX[0]="" regex=""
37+
r regex 0
38+
printf "19B: "; grep -E -c "^${regex}$" "$input"

21.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ done
2020
IFS=$'\n'
2121
ans=$(grep -o ".*(" "$input" | grep -o "[a-z]*" | grep -v -c -F "${B[*]}")
2222
echo "21A: $ans"
23-
IFS=,
23+
IFS=$','
2424
echo "21B: ${B[*]}"

23.sh

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
A=$(<"${1:-23.txt}")
33
i=0
44
for _ in {0..99}; do
5-
c=${A:i:1}
6-
out=${A:i+1:3}
7-
A2=${A/$out}
8-
[ ${#out} -lt 3 ] && A2=${A2:3-${#out}} && out+=${A:0:3-${#out}}
9-
d=${A:i:1}; ((--d)) || d=9; while [ "${out/$d}" != "${out}" ]; do ((--d)) || d=9; done
10-
A=${A2/$d/$d${out}}
11-
#echo $A : $c : $A2-$d:$out
12-
while [ "${A:i:1}" != "$c" ]; do ((++i==9)) && i=0; done
13-
((++i==9)) && i=0
5+
c=${A:i:1}
6+
out=${A:i+1:3}
7+
A2=${A/$out}
8+
[ ${#out} -lt 3 ] && A2=${A2:3-${#out}} && out+=${A:0:3-${#out}}
9+
d=${A:i:1}; ((--d)) || d=9; while [ "${out/$d}" != "${out}" ]; do ((--d)) || d=9; done
10+
A=${A2/$d/$d${out}}
11+
#echo $A : $c : $A2-$d:$out
12+
while [ "${A:i:1}" != "$c" ]; do ((++i==9)) && i=0; done
13+
((++i==9)) && i=0
1414
done
1515
echo "23A: ${A/*1}${A/1*}"
1616
A=$(<"${1:-23.txt}") a=0 b=0 c=0

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ Setting env variable PUREBASH to any value (or giving a second argument) will us
1111
Description of what I'm doing. Contains spoilers....
1212

1313
### 01.sh
14-
1. Simple grep. Loop through all the numbers looking for 2020-i.
15-
2. Double loop through all the numbers looking for 2020-i-j.
14+
1. Use an array as a hash table. Loop through all the numbers looking for 2020-a.
15+
2. Double loop through all the numbers looking for 2020-a-b.
1616

1717
### 02.sh
1818
Simple read and string manipulation. Use IFS to split up the min/max and remove the ':'.
@@ -97,7 +97,7 @@ Description of what I'm doing. Contains spoilers....
9797
2. Just replace "\*" with ")\*(" to change the precedence. Add "(" and ")" to the ends to close off the brackets.
9898

9999
### 19.sh
100-
1. Recursive regex building. Use a cache to speed up previously built regex.
100+
1. Recursive regex building. Use a cache to only build a regex once for each rule.
101101
2. Cheat a bit and use regex{n} to denote repeated matches.
102102

103103
### 20.sh

0 commit comments

Comments
 (0)