|
2 | 2 |
|
3 | 3 | . ../../misc/vardump |
4 | 4 |
|
| 5 | +mkdir -p cache |
| 6 | + |
5 | 7 | FILE="$1" |
6 | 8 |
|
7 | | -do_the_math() { |
8 | | - while IFS=, read -a arr; do |
9 | | - max=0 |
10 | | - total=0 |
11 | | - for ((i=0; i<${#arr[@]}; i++)); do |
12 | | - el=${arr[i]} |
13 | | - if [[ el -gt max ]]; then |
14 | | - max=$el |
15 | | - fi |
16 | | - ((total+=el)) |
17 | | - done |
18 | | - echo "$((total-max)) ($max-$total)" |
19 | | - done |
20 | | -} |
| 9 | +D2B=({0..1}{0..1}{0..1}{0..1}) |
21 | 10 |
|
22 | 11 | shwoop() { |
23 | 12 | while read -a stuff; do |
24 | | - local tmp=${stuff[0]} |
| 13 | + local tmp=${stuff[1]} |
25 | 14 | local len="${#stuff[@]}" |
26 | | - stuff[0]="${stuff[len-1]}" |
| 15 | + stuff[1]="${stuff[len-1]}" |
27 | 16 | stuff[len-1]="${tmp}" |
28 | 17 | echo "${stuff[@]}" |
29 | 18 | done |
30 | 19 | } |
31 | 20 |
|
32 | | -make_buckets() { |
| 21 | +gauss() { |
| 22 | + solved=0 |
| 23 | + total=0 |
33 | 24 | while read -a row; do |
34 | | - requirements="${row[0]}" |
35 | | - buttons=("${row[@]:1}") |
| 25 | + idx="${row[0]}" |
| 26 | + cache_key="cache/${FILE}-$idx" |
| 27 | + ((idx--)) |
| 28 | + if [[ -f "$cache_key" ]]; then |
| 29 | + ans=$(cat "$cache_key") |
| 30 | + echo "solved $idx from cache: $ans" |
| 31 | + ((total+=ans)) |
| 32 | + continue |
| 33 | + fi |
| 34 | + # buncha parsing bulllllllogna |
| 35 | + requirements="${row[1]}" |
| 36 | + buttons=("${row[@]:2}") |
| 37 | + echo "requirements:" |
| 38 | + vardump requirements |
| 39 | + echo "buttons" |
| 40 | + vardump buttons |
36 | 41 | IFS=, read -a reqs <<< $requirements |
37 | | - unset buckets |
38 | | - local -a buckets |
39 | | - for ((i=0; i<${#reqs[@]}; i++)); do |
40 | | - for ((j=0; j<${#buttons[@]}; j++)); do |
41 | | - IFS=, read -a wires <<< "${buttons[j]}" |
| 42 | + unset rows |
| 43 | + local -a rows |
| 44 | + for ((i=0; i<${#reqs[@]}; ++i)); do |
| 45 | + r=() |
| 46 | + for ((j=0; j<${#buttons[@]}; ++j)); do |
| 47 | + IFS=, read -a button <<< "${buttons[j]}" |
42 | 48 | contains=0 |
43 | | - for ((k=0; k<${#wires[@]}; k++)); do |
44 | | - if [[ ${wires[k]} -eq i ]]; then |
| 49 | + for ((k=0; k<${#button[@]}; ++k)); do |
| 50 | + if [[ "${button[k]}" == $i ]]; then |
45 | 51 | contains=1 |
| 52 | + break |
46 | 53 | fi |
47 | 54 | done |
48 | | - [[ contains -eq 0 ]] && continue |
49 | | - if [[ -z "${buckets[i]}" ]]; then |
50 | | - buckets[i]=${buttons[j]} |
51 | | - else |
52 | | - buckets[i]="${buckets[i]} ${buttons[j]}" |
53 | | - fi |
| 55 | + r+=($contains) |
54 | 56 | done |
| 57 | + rows[i]="${r[@]} ${reqs[i]}" |
55 | 58 | done |
56 | | - min=10000 |
57 | | - key=0 |
58 | | - for ((i=0;i<${#buckets[@]};++i)); do |
59 | | - arr=(${buckets[i]}) |
60 | | - length=${#arr[@]} |
61 | | - if [[ length -lt min ]]; then |
62 | | - key=$i |
63 | | - min=$length |
| 59 | + |
| 60 | + local h=0 |
| 61 | + local k=0 |
| 62 | + local m=${#rows[@]} |
| 63 | + local n=${#r[@]} |
| 64 | + ((n++)) |
| 65 | + # wikipedia row echelon form algorithm |
| 66 | + while ((h<m && k<n)); do |
| 67 | + local i_max=0 |
| 68 | + local max=0 |
| 69 | + for ((i=h;i<m;++i)); do |
| 70 | + r=(${rows[i]}) |
| 71 | + local v=${r[k]} |
| 72 | + v=${v//-/} |
| 73 | + if [[ v -gt max ]]; then |
| 74 | + max=$v |
| 75 | + i_max=$i |
| 76 | + fi |
| 77 | + done |
| 78 | + if [[ max -eq 0 ]]; then |
| 79 | + ((k++)) |
| 80 | + else |
| 81 | + # swap rows(h, i_max) |
| 82 | + local tmp="${rows[h]}" |
| 83 | + rows[h]="${rows[i_max]}" |
| 84 | + rows[i_max]="$tmp" |
| 85 | + for ((i=0;i<m;++i)); do |
| 86 | + [[ i -eq h ]] && continue |
| 87 | + local row_i=(${rows[i]}) |
| 88 | + local row_h=(${rows[h]}) |
| 89 | + num=$((row_i[k])) |
| 90 | + denom=$((row_h[k])) |
| 91 | + for ((j=k+1;j<n;++j)); do |
| 92 | + local tnum=${num//-/} |
| 93 | + ((tnum*=row_h[j])) |
| 94 | + # we can't safely divide, so we scale |
| 95 | + # the whole row up to compensate |
| 96 | + if (((tnum%${denom//-/}) != 0)); then |
| 97 | + for((l=0;l<n;++l)); do |
| 98 | + ((row_i[l]*=denom)) |
| 99 | + done |
| 100 | + denom=1 |
| 101 | + break |
| 102 | + fi |
| 103 | + done |
| 104 | + for ((j=k+1;j<n;++j)); do |
| 105 | + row_i[j]=$((row_i[j]-row_h[j]*num/denom)) |
| 106 | + done |
| 107 | + row_i[k]=0 |
| 108 | + rows[i]="${row_i[@]}" |
| 109 | + done |
| 110 | + ((h++)) |
| 111 | + ((k++)) |
64 | 112 | fi |
65 | 113 | done |
66 | | - echo "$min buckets, ${reqs[key]} presses" |
| 114 | + |
| 115 | + # now the fun begins |
| 116 | + zero=0 |
| 117 | + |
| 118 | + # account for fully zero'd rows |
| 119 | + for((i=0;i<m;i++)); do |
| 120 | + all_zeroes=yes |
| 121 | + for((j=0;j<n;j++)); do |
| 122 | + r=(${rows[i]}) |
| 123 | + [[ ${r[j]} == 0 ]] || all_zeroes= |
| 124 | + done |
| 125 | + [[ -n $all_zeroes ]] && ((zero++)) |
| 126 | + done |
| 127 | + |
| 128 | + # calculate remaining free variables |
| 129 | + free=$((n-m-1+zero)) |
| 130 | + if [[ free -le 0 ]]; then |
| 131 | + # this puzzle is already solved for us! |
| 132 | + ans=0 |
| 133 | + for((i=0;i<n-1;i++)); do |
| 134 | + r=(${rows[i]}) |
| 135 | + ((ans+=r[n-1]/r[i])) |
| 136 | + done |
| 137 | + ((solved++)) |
| 138 | + ((total+=ans)) |
| 139 | + echo "$ans" > "$cache_key" |
| 140 | + else # we have free variables to worry about |
| 141 | + echo "Line number: $((idx+1))" |
| 142 | + echo "Free: $free" |
| 143 | + vardump -r rows |
| 144 | + # we need to unfuck the columns |
| 145 | + for((i=0;i<n-1;i++)); do |
| 146 | + nonzero=0 |
| 147 | + for((j=0;j<m;j++)); do |
| 148 | + r=(${rows[j]}) |
| 149 | + c=${r[i]} |
| 150 | + if [[ $c != 0 ]]; then |
| 151 | + ((nonzero++)) |
| 152 | + col=$j |
| 153 | + row=$i |
| 154 | + fi |
| 155 | + done |
| 156 | + if [[ $nonzero == 1 ]]; then |
| 157 | + if [[ $row -gt $col ]]; then |
| 158 | + # uh oh, its fucked |
| 159 | + for((j=0;j<m;j++)); do |
| 160 | + r=(${rows[j]}) |
| 161 | + # swaperoo the column-aroo |
| 162 | + tmp=${r[row]} |
| 163 | + r[row]=${r[col]} |
| 164 | + r[col]=${tmp} |
| 165 | + rows[j]="${r[@]}" |
| 166 | + done |
| 167 | + fi |
| 168 | + fi |
| 169 | + done |
| 170 | + vardump -r rows |
| 171 | + # find the free variables |
| 172 | + free_cols=() |
| 173 | + index=0 |
| 174 | + for((i=0;i<n-1;i++)); do |
| 175 | + nonzero=0 |
| 176 | + for((j=0;j<m;j++)); do |
| 177 | + r=(${rows[j]}) |
| 178 | + c=${r[i]} |
| 179 | + [[ $c == 0 ]] || ((nonzero++)) |
| 180 | + done |
| 181 | + if [[ nonzero -gt 1 ]]; then |
| 182 | + [[ index -eq 0 ]] && fstart=$i |
| 183 | + ((free_cols[i]=index++)) |
| 184 | + fi |
| 185 | + done |
| 186 | + # find the max req |
| 187 | + max=0 |
| 188 | + for((i=0;i<m;i++)); do |
| 189 | + req=${reqs[i]} |
| 190 | + [[ req -gt max ]] && max=$req |
| 191 | + done |
| 192 | + echo MAX: $max |
| 193 | + |
| 194 | + fend=$((fstart+free)) |
| 195 | + smallest=100000000000 |
| 196 | + # welcome to hell |
| 197 | + for ((p=0;p<=max;++p)); do |
| 198 | + for ((x=0;x<=(free==3?p:0);++x)); do |
| 199 | + for ((y=0;y<=(free>=2?p-x:0);++y)); do |
| 200 | + valid=1 |
| 201 | + ans=$p |
| 202 | + z=$((p-x-y)) |
| 203 | + guesses=($z $y $x) |
| 204 | + for((ro=0;ro<m-zero;ro++)); do |
| 205 | + r=(${rows[ro]}) |
| 206 | + div=${r[ro]} |
| 207 | + num=${r[n-1]} |
| 208 | + for((co=fstart;co<fend;co++)); do |
| 209 | + guess="${guesses[co-fstart]}" |
| 210 | + thing=${r[co]} |
| 211 | + ((num-=guess*thing)) |
| 212 | + done |
| 213 | + # check if num divisible by thing |
| 214 | + abs_num=${num//-/} |
| 215 | + abs_div=${div//-/} |
| 216 | + wtf=${num:0:1}${div:0:1} |
| 217 | + wtf=${wtf//[0-9]/} |
| 218 | + if [[ $num != 0 && $wtf == '-' ]]; then |
| 219 | + valid= |
| 220 | + break |
| 221 | + fi |
| 222 | + if ((abs_num%abs_div != 0)); then |
| 223 | + valid= |
| 224 | + break |
| 225 | + fi |
| 226 | + ((ans+=num/div)) |
| 227 | + done |
| 228 | + |
| 229 | + # we should track a min here |
| 230 | + if [[ -n $valid && $ans -lt $smallest ]]; then |
| 231 | + smallest=$ans |
| 232 | + fi |
| 233 | + done |
| 234 | + done |
| 235 | + done |
| 236 | + ((solved++)) |
| 237 | + ((total+=smallest)) |
| 238 | + echo "$smallest" > "$cache_key" |
| 239 | + fi |
67 | 240 | done |
| 241 | + echo SOLVED: $solved / $idx |
| 242 | + echo TOTAL: $total |
68 | 243 | } |
69 | 244 |
|
70 | | -FILE=input.txt |
71 | | -cat $FILE \ |
72 | | - | cut -d' ' -f2- \ |
| 245 | +cat -n "$FILE" \ |
| 246 | + | tr '\t' ' ' \ |
| 247 | + | tr -s ' ' \ |
| 248 | + | cut -d' ' -f2,4- \ |
73 | 249 | | shwoop \ |
74 | 250 | | tr -d '{}()' \ |
75 | | - | make_buckets \ |
76 | | - | sort -n |
| 251 | + | gauss |
0 commit comments