|
1 | 1 | #! /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 | + |
2 | 10 | 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' |
15 | 31 | 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}"} |
18 | 144 | done
|
19 |
| -printf -v sum "*%s" "${ENDS[@]}"; sum=${sum:1} |
20 |
| -echo "20A: $sum=$((sum))" |
| 145 | +echo "20B: $total-$monsterlen*$found = $((total-monsterlen*found))" |
0 commit comments