Skip to content

Commit 71fedd4

Browse files
committed
20: Finally get the last star
The lack of 2D arrays is terrible. Named functions variables kind of work to bypass that. Lots of subshells and calls to tac/rev because I got lazy.
1 parent ac5c056 commit 71fedd4

File tree

2 files changed

+142
-19
lines changed

2 files changed

+142
-19
lines changed

20.sh

Lines changed: 141 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,145 @@
11
#! /usr/bin/env bash
2+
rotate() {
3+
local -n in=$1 out=$2
4+
local len=${#in[0]}
5+
for i in "${idx[@]:1:len}"; do
6+
out[len-i]=$(printf "%s\n" "${in[@]}" | cut -c"$i" | tr -d '\n' )
7+
done
8+
}
9+
210
IFS=$'\n'
3-
A=($(tr '.' '_' < "${1:-20.txt}"))
4-
T=($(printf "%s\n" "${A[@]}" | grep -o "[0-9]*" ))
5-
U=($(printf "%s\n" "${A[@]}" | grep -A1 T | grep -E "[_#]" ))
6-
D=($(printf "%s\n" "${A[@]}" T | grep -B1 T | grep -E "[_#]" ))
7-
IFS=$' T' L=($(printf "%s\n" "${A[@]}" | cut -c1 | tail +2 | tr -d '\n '))
8-
IFS=$' :' R=($(printf "%s\n" "${A[@]}" | cut -c${#U[1]} | tail +2 | tr -d '\n '))
9-
IFS=$'\n'
10-
Ur=($(printf "%s\n" "${U[*]}" | rev))
11-
Dr=($(printf "%s\n" "${D[*]}" | rev))
12-
Lr=($(printf "%s\n" "${L[*]}" | rev))
13-
Rr=($(printf "%s\n" "${R[*]}" | rev))
14-
ENDS=() x=0
11+
A=($(tr '.' '_' < "${1:-20.txt}")) # . is a wildcard
12+
idx=(${!A[@]})
13+
rotate A A270
14+
ENDS=() NUM=() D=() U=() len=${#A[1]}
15+
for ((i=0;i<${#A[@]};i+=len+1)); do
16+
NUM+=(${A[i]//[^0-9]})
17+
U+=(${A[i+1]})
18+
D+=(${A[i+len]})
19+
done
20+
IFS=$' \n'
21+
L=(${A270[-1]//[^_#]/ })
22+
R=(${A270[0]//[^_#]/ })
23+
Ur=($(printf "%s\n" "${U[@]}" | rev))
24+
Dr=($(printf "%s\n" "${D[@]}" | rev))
25+
Lr=($(printf "%s\n" "${L[@]}" | rev))
26+
Rr=($(printf "%s\n" "${R[@]}" | rev))
27+
N="${#U[@]}"
28+
for n in "${idx[@]:2:N}";do ((n*n==N)) && break; done
29+
printf -v ALL "%s\n" "${U[@]}" "${R[@]}" "${Dr[@]}" "${Lr[@]}"
30+
IFS=$' :\n'
1531
for i in "${!U[@]}"; do
16-
x=$(printf "%s\n" "${U[*]}" "${Ur[*]}" "${D[*]}" "${Dr[*]}" "${L[*]}" "${Lr[*]}" "${R[*]}" "${Rr[*]}" | grep -c -e "${U[i]}" -e "${Dr[i]}" -e "${Lr[i]}" -e "${R[i]}" )
17-
[ "$x" = 6 ] && ENDS+=("${T[i]}")
32+
x=()
33+
while read -r k _; do
34+
(((--k%N)!=i)) && x+=("$((k/N)):$((k%N))")
35+
done < <(echo "$ALL" | grep -n -E -x "(${U[i]}|${R[i]}|${Dr[i]}|${Lr[i]}|${Ur[i]}|${Rr[i]}|${D[i]}|${L[i]})")
36+
PIC[i]=${x[*]}
37+
case ${#x[*]} in
38+
2) ENDS[i]="${NUM[i]}";;
39+
3|4) : ;;
40+
*) echo "ERROR($i): ${x[*]}"; break;;
41+
esac
42+
done
43+
IFS=$' \n'
44+
printf -v prod "*%s" "${ENDS[@]}"; prod=${prod:1}
45+
echo "20A: $prod=$((prod))"
46+
GRID=() FOUND=() ROT=() s1=() s2=()
47+
index=(${!ENDS[@]})
48+
next=${index[0]}
49+
50+
# Top row. Rotation is based on neighbors, so that has to wait
51+
FOUND[next]=0; GRID[0]=$next
52+
for i in "${idx[@]:1:n-1}"; do
53+
for k in ${PIC[next]//?:}; do
54+
[[ -n ${FOUND[k]} || ${PIC[k]} == *:*:*:*:* ]] && continue
55+
next=$k; FOUND[k]=$i; GRID[i]=$k; break
56+
done
57+
done
58+
#Rows 2-12. Exactly one side should not be done already
59+
for i in "${idx[@]:n:N-n}"; do
60+
for j in ${PIC[GRID[i-n]]}; do
61+
k=${j/?:}; [[ -n ${FOUND[k]} ]] && continue
62+
FOUND[k]=$i; GRID[i]=$k; ROT[i]=${j/:*}; break
63+
done
64+
done
65+
# Circle back to the first row
66+
for i in "${idx[@]:0:n-1}"; do
67+
if [[ ${PIC[GRID[i+n]]} =~ ([0-9]):${GRID[i]} ]]; then
68+
ROT[i]=$(( BASH_REMATCH[1]+2 ))
69+
fi
70+
done
71+
72+
edges=(R Dr Lr U L Ur Rr D)
73+
segde=(L Ur Rr D R Dr Lr U) # flipped
74+
get_edges() {
75+
local -n both=$1 left=${edges[$3]} right=${segde[$3]}
76+
both=(${left[$2]} ${right[$2]})
77+
}
78+
# Make sure the left/right sides match
79+
for ((i=1 ; i < N; i+=2)); do
80+
get_edges s1 "${GRID[i-1]}" ${ROT[i-1]}
81+
get_edges s2 "${GRID[i]}" ${ROT[i]}
82+
if [[ ${s1[0]} == "${s2[1]}" ]]; then ((ROT[i]-=4, ROT[i-1]-=4)) # flip both
83+
elif [[ ${s1[1]} == "${s2[1]}" ]]; then ((ROT[i]-=4)) # flip right
84+
elif [[ ${s1[0]} == "${s2[0]}" ]]; then ((ROT[i-1]-=4)) # flip left
85+
elif [[ ${s1[1]} == "${s2[0]}" ]]; then : # no flip
86+
else echo "ERROR: idx $((i-1)) and $i don't match: ${s1[*]} != ${s2[*]}"
87+
fi
88+
done
89+
90+
rot0(){
91+
local X=() offset=$((11*$1))
92+
for i in {1..8}; do X+=(${A[offset+i+1]:1:8}); done
93+
printf "%s\n" "${X[@]}"
94+
}
95+
rot270() {
96+
local X=() offset=$((11*$1))
97+
for i in {1..8}; do X+=(${A270[i]:offset+2:8}); done
98+
printf "%s\n" "${X[@]}"
99+
}
100+
rot180(){ rot0 "$@" | tac | rev; }
101+
rot90(){ rot270 "$@" | tac | rev; }
102+
flip0() { rot0 "$@" | rev; }
103+
flip270() { rot270 "$@" | rev; }
104+
flip180() { rot0 "$@" | tac; }
105+
flip90() { rot270 "$@" | tac; }
106+
TOTAL=() FINAL=() FINAL270=()
107+
TRANSFORM=(flip0 flip270 flip180 flip90 rot0 rot270 rot180 rot90)
108+
for i in "${!GRID[@]}"; do
109+
TOTAL+=($(${TRANSFORM[ROT[i]]} "${GRID[i]}"))
110+
done
111+
112+
# Assemble image
113+
for ((i=0; i < n; ++i)); do
114+
for ((j=0; j < 8; ++j)); do
115+
for ((k=0; k < n; ++k)); do
116+
FINAL[8*i+j]+=${TOTAL[8*n*i+j+k*8]}
117+
done
118+
done
119+
done
120+
rotate FINAL FINAL270
121+
monster="..................(#..{77}#....##....##....###.{77}.#..#..#..#..#..#...)"
122+
monsterlen=${monster//[^\#]}; monsterlen=${#monsterlen}
123+
regex=${monster/................../[_\#]\{18\}} # no newline at start
124+
i=0
125+
printf -v "MAP[i++]" "%s\n" "${FINAL[@]}"
126+
MAP[i++]=$(printf "%s\n" "${FINAL[@]}" | tac)
127+
MAP[i++]=$(printf "%s\n" "${FINAL[@]}" | rev| tac)
128+
MAP[i++]=$(printf "%s\n" "${FINAL[@]}" | rev)
129+
printf -v "MAP[i++]" "%s\n" "${FINAL270[@]}"
130+
MAP[i++]=$(printf "%s\n" "${FINAL270[@]}" | tac)
131+
MAP[i++]=$(printf "%s\n" "${FINAL270[@]}" | rev| tac)
132+
MAP[i++]=$(printf "%s\n" "${FINAL270[@]}" | rev)
133+
hashes=${MAP[0]//[^#]}; total=${#hashes} found=0
134+
for map in "${MAP[@]}"; do
135+
if [[ $map =~ $regex ]]; then
136+
break
137+
fi
138+
done
139+
140+
# Change the head of the monster so it is only found once
141+
while [[ $map =~ $regex ]]; do
142+
((++found < 200)) || { echo "Error: replace is failing ($found monsters)"; break; }
143+
map=${map/"${BASH_REMATCH[1]}"/"O${BASH_REMATCH[1]:1}"}
18144
done
19-
printf -v sum "*%s" "${ENDS[@]}"; sum=${sum:1}
20-
echo "20A: $sum=$((sum))"
145+
echo "20B: $total-$monsterlen*$found = $((total-monsterlen*found))"

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ Description of what I'm doing. Contains spoilers....
102102

103103
### 20.sh
104104
1. Slice and dice all permutations of the edges into arrays. Grep each tile against all permutations of edges. Convert line number to index/rotation. The ones with only 2 matches are corners. The ones with 3 are edges. Use that to assemble the image.
105-
2. Not done yet: Once the picture is assembled, use a multi-line regex to find the monsters. Then count.
105+
2. Almost impossible in bash. The grep gave me the rotation, but not which tiles needed flipping. A second step compares left and right sides of each pair of tiles to decide which ones must be flipped. Once the picture is assembled, use a multi-line bash regex to find a monster. Modify one char to not trigger again on that monster. Repeat until no more monsters are found. Then count.
106106

107107
### 21.sh
108108
Grep, sort, count
@@ -123,5 +123,3 @@ Description of what I'm doing. Contains spoilers....
123123

124124
### 25.sh
125125
1. While loop for 15M rounds. Yay. Awk finishes in seconds.
126-
2. I need to complete 20-2 to get this one. Nope.
127-

0 commit comments

Comments
 (0)