Skip to content

Commit 49d94c1

Browse files
committed
2015/06: 40x speedup in part 2, 2x in part 1.
Subshell calls are slow. Collect all the changes for each round and do a single call to $(tr ...), instead of doing one per line. From +5 minutes to under 10 seconds for both parts, so it's now faster than awk.
1 parent 06bf336 commit 49d94c1

File tree

2 files changed

+13
-9
lines changed

2 files changed

+13
-9
lines changed

2015/06.sh

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ while read -r action x y _ X Y; do
1111
AA[i]=${AA[i]:0:x}${one:x:X-x+1}${AA[i]:X+1}; done;;
1212
off) for i in "${idx[@]:y:Y-y+1}"; do
1313
AA[i]=${AA[i]:0:x}${zero:x:X-x+1}${AA[i]:X+1}; done;;
14-
toggle) for i in "${idx[@]:y:Y-y+1}"; do # swap using "t" as tmp
15-
T=${AA[i]:x:X-x+1};T=${T//0/t}; T=${T//1/0}; T=${T//t/1};
16-
AA[i]=${AA[i]:0:x}${T}${AA[i]:X+1}; done;;
14+
toggle) PART="";
15+
for i in "${idx[@]:y:Y-y+1}"; do PART+="${AA[i]:x:X-x+1} "; done
16+
TMP=($(tr '01' '10' <<< "$PART"))
17+
for i in "${idx[@]:y:Y-y+1}"; do AA[i]=${AA[i]:0:x}${TMP[i-y]}${AA[i]:X+1}; done;;
1718
esac
1819
done < <(sed "s/turn.//" "$input")
1920
IFS='' ANS=${AA[*]//0}
@@ -23,14 +24,14 @@ if [[ -n ${2:-$PUREBASH} ]]; then
2324
IFS=$' ,\n'
2425
AA=($(printf "%.s$zero\n" "${idx[@]}"))
2526
while read -r action x y _ X Y; do
27+
PART=""
28+
for i in "${idx[@]:y:$Y-y+1}"; do PART+="${AA[i]:x:X-x+1} "; done
2629
case $action in
27-
on) for i in "${idx[@]:$y:$Y-y+1}"; do # shift up by 1. '?' means overflow
28-
AA[i]=${AA[i]:0:x}$(tr '0-9a-zA-Z' '1-9a-zA-Z?' <<< "${AA[i]:x:X-x+1}")${AA[i]:X+1}; done;;
29-
off) for i in "${idx[@]:y:Y-y+1}"; do # shift down by 1
30-
AA[i]=${AA[i]:0:x}$(tr '1-9a-zA-Z' '0-9a-zA-Y' <<< "${AA[i]:x:X-x+1}")${AA[i]:X+1}; done;;
31-
toggle) for i in "${idx[@]:y:Y-y+1}"; do # shift up by 2
32-
AA[i]=${AA[i]:0:x}$(tr '0-9a-zA-Z' '2-9a-zA-Z??' <<< "${AA[i]:x:X-x+1}")${AA[i]:X+1}; done;;
30+
on) TMP=($(tr '0-9a-zA-Z' '1-9a-zA-Z?' <<< "$PART"));; # shift up by 1. '?' means overflow
31+
off) TMP=($(tr '1-9a-zA-Z' '0-9a-zA-Y' <<< "$PART"));; # shift down by 1
32+
toggle) TMP=($(tr '0-9a-zA-Z' '2-9a-zA-Z??' <<< "$PART"));; # shift up by 2
3333
esac
34+
for i in "${idx[@]:y:Y-y+1}"; do AA[i]=${AA[i]:0:x}${TMP[i-y]}${AA[i]:X+1}; done
3435
done < <(sed "s/turn.//" "$input")
3536
#ANS=$(printf "%s" "${AA[@]//0}" | grep -o . | sort | uniq -c | sed "s/^ */+/;s/ /*/")
3637
ANS=$(printf "%s" "${AA[@]//0}" | sed "s/./+&/g" )

2015/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ This is where bash sucks. The best I could do was an array of strings, and subst
2929
1. Switch to select what to do. Use substring index magic. Fixed strings of 1000 ones and zeros to make life easier. Swap is a bother, and uses string substitution.
3030
2. A million countable items in bash are always a bother. Using $(tr ...) allows me to store 62 values per character in a string, but it's extremely slow. Awk is around 30 times faster.
3131

32+
*Update:* By collecting all the changes in an array and doing single $(tr ...) subshell call per input line, part 1 is over 2x faster.
33+
Part 2 is 40x faster, and outperforms awk.
34+
3235
### 07.sh
3336
1. After setting up, loop through all values and evaluate it to a number if all parameters have been evaluated.
3437
Takes about 100 iterations through all values. Run in a subshell to keep the namespace clean for part 2.

0 commit comments

Comments
 (0)