Make day 13 much much quicker
[advent-of-code-2021.git] / day13 / fold.sh
1 #!/bin/bash
2
3 set -u
4
5 declare -a points=()
6 declare -a folds=()
7
8 filename="${1:-example.txt}"
9 exec 3<"$filename"
10
11 max_x=0
12 max_y=0
13
14 while read -u 3 line; do
15     if [ "$line" == "" ]; then
16         break
17     fi
18     x=${line%,*}
19     y=${line#*,}
20     if [ $x -gt $max_x ]; then
21         max_x=$x
22     fi
23     if [ $y -gt $max_y ]; then
24         max_y=$y
25     fi
26     points+=($line)
27 done
28
29 ((max_x+=1))
30 ((max_y+=1))
31
32 while read -u 3 line; do
33     folds+=(${line#fold along })
34 done
35
36 display_map() {
37     for (( y=0; y<$max_y; y++ )); do
38         for (( x=0; x<$max_x; x++ )); do
39             case "${map[$x,$y]}" in
40                 0)
41                     echo -n "."
42                     ;;
43                 1)
44                     echo -n "#"
45                     ;;
46             esac
47         done
48         echo
49     done
50 }
51
52 declare -A map
53
54 # now build a map
55 for (( y=0; y<$max_y; y++ )); do
56     for (( x=0; x<$max_x; x++ )); do
57         map["$x,$y"]=0
58     done
59 done
60
61 for point in "${points[@]}"; do
62     x=${point%,*}
63     y=${point#*,}
64     map["$x,$y"]=1
65 done
66
67 fold() {
68     local line="$1"
69     local axis=${line%=*}
70     local point=${line#*=}
71
72     declare -A new_map=()
73
74     case $axis in
75         x)
76             local new_max_x=$(($max_x - $point - 1))
77             if [ $point -gt $new_max_x ]; then
78                 new_max_x=$point
79             fi
80             for (( y=0; y<$max_y; y++ )); do
81                 for (( x=0; x<$new_max_x; x++ )); do
82                     # be sensible instead of insane, work from the middle out
83                     x_1=$(($point-$x-1)) # always one left of the point
84                     x_2=$(($point+$x+1)) # always one right of the point
85                     if [ $x_1 -lt 0 ]; then
86                         x_1=$x_2
87                     fi
88                     if [ $x_2 -ge $max_x  ]; then
89                         x_2=$x_1
90                     fi
91                     new_x=$(($new_max_x-$x-1)) # work from the right of the new image, left
92                     new_map["$new_x,$y"]=$((${map["$x_1,$y"]} | ${map["$x_2,$y"]}))
93                 done
94             done
95             max_x=$new_max_x
96             ;;
97         y)
98             local new_max_y=$(($max_y - $point - 1))
99             if [ $point -gt $new_max_y ]; then
100                 new_max_y=$point
101             fi
102             for (( y=0; y<$new_max_y; y++ )); do
103                 y_1=$(($point-$y-1)) # always above the fold
104                 y_2=$(($point+$y+1)) # always below the fold
105                 if [ $y_1 -lt 0 ]; then
106                     y_1=$y_2
107                 fi
108                 if [ $y_2 -ge $max_y  ]; then
109                     y_2=$y_1
110                 fi
111                 new_y=$(($new_max_y-$y-1)) # work from the bottom of the new image, up
112                 for (( x=0; x<$max_x; x++ )); do
113                     new_map["$x,$new_y"]=$((${map["$x,$y_1"]} | ${map["$x,$y_2"]}))
114                 done
115             done
116             max_y=$new_max_y
117             ;;
118     esac
119
120     for k in "${!new_map[@]}"; do
121         map[$k]=${new_map[$k]}
122     done
123 }
124
125 get_points_count() {
126     local count=0
127     for (( y=0; y<$max_y; y++ )); do
128         for (( x=0; x<$max_x; x++ )); do
129             ((count+=${map[$x,$y]}))
130         done
131     done
132
133     echo $count
134 }
135
136 # do first fold
137 echo "Doing first fold"
138 fold "${folds[0]}"
139 echo "There are $(get_points_count) dots visible after first fold"
140 for (( f=1; f<${#folds[@]}; f++ )); do
141     echo "Doing fold $((f+1)) of ${#folds[@]}"
142     fold "${folds[$f]}"
143 done
144 echo
145 echo "After all folds:"
146 display_map