├── LICENSE ├── README.md ├── day_01 ├── solution.awk └── solution.ps ├── day_02 ├── solution.awk └── solution.ps ├── day_03 ├── solution.awk └── solution.ps ├── day_04 ├── solution.awk └── solution.ps ├── day_05 ├── solution.awk └── solution.ps ├── day_06 ├── solution.awk └── solution.ps ├── day_07 ├── solution.awk └── solution.ps ├── day_08 ├── solution.awk └── solution.ps ├── day_09 ├── solution.awk └── solution.ps ├── day_10 ├── solution.awk └── solution.ps ├── day_11 ├── solution.awk └── solution.ps ├── day_12 ├── solution.awk └── solution.ps ├── day_13 ├── solution.awk └── solution.ps ├── day_14 ├── solution.awk └── solution.ps ├── day_15 ├── solution.awk └── solution.ps ├── day_16 ├── solution.awk └── solution.ps ├── day_17 ├── solution.awk └── solution.ps ├── day_18 ├── solution.awk └── solution.ps ├── day_19 └── solution.awk ├── day_20 ├── solution.awk └── solution.ps ├── day_21 ├── solution.awk └── solution.ps ├── day_22 ├── solution.awk └── solution.ps ├── day_23 └── solution.awk ├── day_24 ├── solution.awk └── solution.ps └── day_25 ├── solution.awk └── solution.ps /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Juho Eerola 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Advent of Code 2021 2 | 3 | I solved the puzzles both in [PostScript](#postscript) and [Awk](#awk). 4 | Couple days are still missing a PostScript solution. 5 | 6 | Each day's solution solves both parts of the puzzle for that day. The answers 7 | are printed on separate lines. Input can be provided to standard in. 8 | 9 | For the problem descriptions, and to get your own input, head over to 10 | [Advent of Code](https://adventofcode.com/2021). 11 | 12 | ### PostScript 13 | 14 | I picked PostScript as a language to learn for this year's event. 15 | 16 | To run with GhostScript: 17 | 18 | ```sh 19 | gs -q- -dBATCH -dNOPAUSE solution.ps 1&&$1>x[NR-1];B+=NR>3&&$1>x[NR-3];x[NR]=$1} 4 | -------------------------------------------------------------------------------- /day_01/solution.ps: -------------------------------------------------------------------------------- 1 | %!PS 2 | 3 | /input (%stdin) (r) file def 4 | /depths [ { input token not { exit } if } loop ] def 5 | /depth@ { depths exch get } def 6 | [ 1 3 ] { 7 | 0 1 index 1 depths length 1 sub { 8 | dup depth@ exch 3 index sub depth@ gt { 1 add } if 9 | } for = pop 10 | } forall 11 | -------------------------------------------------------------------------------- /day_02/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | END {print x*y"\n"x*z} /f/ {x+=$2;z+=y*$2} /u/ {y-=$2} /n/ {y+=$2} 4 | -------------------------------------------------------------------------------- /day_02/solution.ps: -------------------------------------------------------------------------------- 1 | %!PS 2 | 3 | /input (%stdin) (r) file def 4 | /tok { input token not { exit } if } def 5 | /+= { exch 1 index load add store } def 6 | 7 | [ /h /d /d2 ] { 0 def } forall 8 | 9 | { 10 | tok tok 1 index /forward eq 11 | { dup /h += d mul /d2 += pop } 12 | { exch /up eq { -1 mul } if /d += } 13 | ifelse 14 | } loop 15 | 16 | h d mul = 17 | h d2 mul = 18 | -------------------------------------------------------------------------------- /day_03/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | bit function f(p){n=0;for(s in p){for(j=split(s,q,z);j--;)X[j]+=2*q[j+1];n++}} 4 | odd function r(p){for(x=0;f(p)n>1;x++){for(i in p)if((i~"^.{"x"}"(X[x]> def 14 | 15 | /+ { 0 exch { add } forall } def 16 | /score { 0 exch { + add } forall mul } def 17 | 18 | /mark { { 19 | { 20 | 0 1 4 { 21 | 2 copy get 3 index eq { 0 put stop } if pop 22 | } for pop 23 | } forall 24 | } stopped } def 25 | /win? { { 26 | 0 1 4 { 27 | 0 2 index { 2 index get add } forall 28 | 0 eq { pop pop stop } if pop 29 | } for 30 | { + 0 eq { stop } if } forall 31 | } stopped } def 32 | 33 | /last null def 34 | { boards { 35 | 3 2 roll 1 index mark { 36 | 1 index win? { 37 | 2 copy exch score 38 | last null eq { dup = } if /last exch store 39 | boards 3 index undef 40 | } if 41 | } if 3 1 roll pop pop 42 | } forall pop } forall 43 | last = 44 | -------------------------------------------------------------------------------- /day_05/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | BEGIN{FS=",| -> "}function l(a){for(a[x=$1,y=$2]++;x-$3||y-$4;) 4 | a[x+=($3>$1)-($3<$1),y+=($4>$2)-($4<$2)]++}$1==$3||$2==$4{l(A)} 5 | END{for(i in A)a+=A[i]>1;for(i in B)b+=B[i]>1;print a"\n"b}l(B) 6 | -------------------------------------------------------------------------------- /day_05/solution.ps: -------------------------------------------------------------------------------- 1 | %!PS 2 | 3 | /input (%stdin) (r) file def 4 | /next-line { [ 5 | input 60 string readline not { pop pop exit } if 6 | (,) search pop cvi 3 1 roll pop token pop exch 7 | (-> ) anchorsearch pop pop 8 | (,) search pop cvi 3 1 roll pop cvi 9 | ] } def 10 | 11 | /add-point { % x y dict -- 12 | exch 2 copy known 13 | { get exch 2 copy known { 1 } { 0 } ifelse } 14 | { << 4 3 roll 0 >> } 15 | ifelse put 16 | } def 17 | 18 | /no-diagonals <<>> def 19 | /all-lines <<>> def 20 | 21 | /sign { dup 0 ne { dup abs idiv } if } def 22 | /delta { line 1 index 2 add get line 3 2 roll get sub } def 23 | /len { 0 delta abs 1 delta abs max } def 24 | /diagonal? { dx dy mul 0 ne } def 25 | /add-line { 26 | line 0 get line 1 get len 1 add { 27 | 2 copy 4 index add-point 28 | exch dx add exch dy add 29 | } repeat pop pop pop 30 | } def 31 | /overlap { 0 exch { exch pop 0 exch { exch pop add } forall add } forall } def 32 | 33 | << /PageSize [ 1000 1000 ] >> setpagedevice 34 | /draw-line { 35 | diagonal? { 1 0 0 } { 0 1 0 } ifelse setrgbcolor 36 | line aload pop moveto lineto stroke 37 | } def 38 | 39 | { 40 | /line next-line def 41 | /dx 0 delta sign def 42 | /dy 1 delta sign def 43 | all-lines add-line 44 | diagonal? not { no-diagonals add-line } if 45 | draw-line 46 | } loop pop 47 | 48 | no-diagonals overlap = 49 | all-lines overlap = 50 | 51 | showpage 52 | -------------------------------------------------------------------------------- /day_06/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | !++A[$1]function D(a,y,s){for(;th&&h=x}for(;l++0&&+k>m&&m=k;s[m]--&&n--&&B*=m}print A"\n"B/3} 8 | -------------------------------------------------------------------------------- /day_09/solution.ps: -------------------------------------------------------------------------------- 1 | %!PS 2 | 3 | /input (%stdin) (r) file def 4 | /map [ { input 256 string readline not { pop exit } if } loop ] def 5 | /@ { % x y 6 | mark 3 1 roll { map exch get exch get } stopped 7 | { cleartomark 57 } { exch pop } ifelse 8 | } def 9 | 10 | /low { 11 | x y @ x 1 add y @ lt 12 | x y @ x 1 sub y @ lt and 13 | x y @ x y 1 add @ lt and 14 | x y @ x y 1 sub @ lt and 15 | } def 16 | 17 | /basin { % x y 18 | 2 copy @ 57 lt { 19 | map 1 index get 2 index 57 put 20 | /B B 1 add def 21 | 2 copy 1 add basin 22 | 2 copy 1 sub basin 23 | 2 copy exch 1 sub exch basin 24 | exch 1 add exch basin 25 | } { pop pop } ifelse 26 | } def 27 | 28 | /A 0 def 29 | /B [ 0 1 map length 1 sub { 30 | /y exch def 31 | 0 1 map y get length 1 sub { 32 | /x exch def 33 | low { 34 | /A A x y @ 47 sub add def 35 | /B 0 def x y basin B 36 | } if 37 | } for 38 | } for ] def 39 | 40 | 1 3 { 41 | /max 0 def 42 | 0 B { B max get gt { /max 1 index def } if 1 add } forall pop 43 | B max get B max 0 put 44 | mul 45 | } repeat 46 | 47 | A = = 48 | -------------------------------------------------------------------------------- /day_10/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | function f(i){for(k in B)i-(+k|\{}/,z));sub(/)/,"_3")sub(/]/, 5 | "_57")sub(/}/,"_1197")sub(/>/,"_25137")gsub(/\(/," 1")gsub(/\[/," 2")gsub(/{/, 6 | " 3")gsub(/) 0 get 25137 >> def 7 | /score { 1 (\([{<) { 2 index eq { exit } if 1 add } forall exch pop } def 8 | 9 | /A 0 def 10 | 11 | mark { 12 | next { 13 | closing 1 index known { 14 | 2 copy sub dup -1 ne exch -2 ne and { 15 | closing exch get A add /A exch def 16 | cleartomark mark exit 17 | } if pop pop 18 | } if 19 | } forall 20 | counttomark 0 exch { 5 mul exch score add } repeat 21 | dup 0 ne { dup count 1 roll } if pop 22 | } loop pop 23 | 24 | count 2 idiv { 25 | { lt gt } { /cmp exch def 26 | count { 2 copy cmp { exch } if count 1 roll } repeat pop 27 | } forall 28 | } repeat 29 | 30 | A = = 31 | -------------------------------------------------------------------------------- /day_11/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | function I(n,c){(k=y+n"\34"x+c)in G&&G[k]&&++G[k]}END{ 4 | for(;n-NR*w;++B<101&&A+=n){for(k in G)n=!++G[k];do{f=0 5 | for(y=0;y++9&&G[y,x]=I(I(1, 6 | 1),1)I(f=-1,f)I(1)I(f)I(f,1)I(!++n,f)I(1,f)}while(-f)} 7 | print A"\n"B}{for(w=i=split($0,a,z);i;)G[NR,i--]=a[i]} 8 | -------------------------------------------------------------------------------- /day_11/solution.ps: -------------------------------------------------------------------------------- 1 | %!PS 2 | 3 | /input (%stdin) (r) file def 4 | 5 | /row { 0 exch get } dup 0 6 | [ { input 256 string readline not { pop exit } if } loop ] 7 | /h 1 index length def 8 | put def 9 | /w h 0 gt { 0 row length } { 0 } ifelse def 10 | 11 | /@ { row exch get } def 12 | /++ { row exch 2 copy get 1 add put } def 13 | 14 | /zero (0) 0 get def 15 | /nine (9) 0 get def 16 | /range { 0 1 3 2 roll 1 sub } def 17 | /around [ 18 | { -1 -1 } { -1 +0 } { -1 +1 } 19 | { +0 -1 } { +0 +1 } 20 | { +1 -1 } { +1 +0 } { +1 +1 } 21 | ] def 22 | 23 | /inc { mark 3 1 roll { 2 copy @ zero ne { ++ } if } stopped cleartomark } def 24 | /step { 25 | h range { w range { 1 index ++ } for pop } for 26 | 0 { 27 | 0 28 | w range { h range { 2 copy @ nine gt { 29 | 3 2 roll 1 add 3 1 roll 30 | 2 copy row exch zero put 31 | around { exec exch 3 index add exch 2 index add inc } forall 32 | } if pop } for pop } for 33 | dup 0 eq { pop exit } if 34 | add 35 | } loop 36 | } def 37 | 38 | % To generate a gif using GhostScript and ImageMagick: 39 | % mkdir frames 40 | % gs -sDEVICE=png16 -o frames/%03d.png solution.ps > setpagedevice 45 | /Helvetica 5 selectfont 46 | /N 0 def 47 | /color { zero sub dup 0 eq { pop 1 } { 10 div } ifelse } def 48 | { 49 | size size scale 50 | h range { w range { 51 | 2 copy exch @ color setgray 52 | h 1 sub 2 index sub 1 1 rectfill 53 | } for pop } for 54 | 0 setgray 55 | 1 1 moveto N ( ) cvs show 56 | showpage 57 | /N N 1 add def 58 | } 59 | } ifelse def 60 | 61 | draw 62 | 0 100 { step draw add } repeat = 63 | 100 { 1 add step draw w h mul eq { exit } if } loop = 64 | 30 { step draw } repeat 65 | -------------------------------------------------------------------------------- /day_12/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | sub(/lime.|-/,FS){M[$2]=M[$2]FS$1;M[$1]=M[$1]FS$2} 4 | function P(a,t,h,s){a~/end/&&++n||a~/[a-z]/&&h~a&& 5 | t++||split(M[a],s);for(k in s)s[k]~/star/||P(s[k], 6 | t,h a)}END{print P("start",1)n"\n"P("start",n=0)n} 7 | -------------------------------------------------------------------------------- /day_12/solution.ps: -------------------------------------------------------------------------------- 1 | %!PS 2 | 3 | /input (%stdin) (r) file def 4 | 5 | /map <<>> def 6 | /connect { 7 | dup (start) ne 2 index (end) ne and { 8 | map 2 index known { map 2 index get } { [] } ifelse 9 | [ 3 1 roll aload pop ] map 3 1 roll put 10 | } { pop pop } ifelse 11 | } def 12 | 13 | { 14 | input 20 string readline not { pop exit } if 15 | (-) search pop exch pop 2 copy connect exch connect 16 | } loop 17 | 18 | /vis << map { pop 0 } forall >> def 19 | /leave { dup (^) gt { vis 1 index 2 copy get 1 sub put } if } def 20 | /visit { 21 | dup (^) gt { 22 | vis 1 index 2 copy get 1 add put 23 | true vis { part gt { pop pop false exit } if pop } forall 24 | dup part 2 eq and { 25 | 0 vis { exch pop 2 eq { 1 add } if } forall 2 lt and 26 | } if 27 | } { true } ifelse 28 | } def 29 | 30 | /paths { 31 | dup (end) eq { /N N 1 add def } { 32 | visit { map 1 index get { paths } forall } if leave 33 | } ifelse pop 34 | } def 35 | 36 | /part 1 def /N 0 def (start) paths N = 37 | /part 2 def /N 0 def (start) paths N = 38 | -------------------------------------------------------------------------------- /day_13/solution.awk: -------------------------------------------------------------------------------- 1 | #/usr/bin/awk -f 2 | 3 | sub(/,|=/,FS)NF~2{D[$0]}/f/{/x/?X=$4:Y=$4;for(k in D){split(k,a) 4 | x=a[1];y=a[2];if(/x/&&x>X){delete D[k];D[2*X-x" "y]}if(/y/&&y>Y) 5 | {delete D[k];D[x" "2*Y-y]}}}/ld/&&!A{for(k in D)A++;print A}END{ 6 | for(y=-1;++y> setpagedevice 91 | bounds [ /h /w ] { exch def } forall 92 | /inited true def 93 | } def 94 | /frame { 95 | inited not { init-page } if 96 | set-bounds 97 | bounds h exch 1 add div exch w exch 1 add div 2 copy gt { exch } if pop dup scale 98 | dots { 99 | { 255 div } forall setrgbcolor 100 | value exch min-x sub 1 add 101 | exch max-y exch sub 1 add 102 | 0.5 0 360 arc fill 103 | } forall 104 | showpage 105 | } def 106 | 107 | /limit 4000 def 108 | /small-enough { set-bounds bounds limit lt exch limit lt and } def 109 | 110 | draw-frames { small-enough { frame } if } if 111 | 112 | next-fold dots length = 113 | { draw-frames { small-enough { frame } if } if next-fold } loop 114 | 115 | draw-frames not { frame } if 116 | 117 | min-y 1 max-y { 118 | min-x 1 max-x { 119 | 2 copy exch key dots exch known { 1 } { 0 } ifelse 120 | output ( #) 3 2 roll get write pop 121 | } for 122 | output (\n) writestring pop 123 | } for 124 | -------------------------------------------------------------------------------- /day_14/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | !/HO -> OH/{X[$1]=$3}END{S(10,N,A)S(29,A)}gsub(i,FS){for(o=O=$++i;$++i; 4 | O=$i)N[O$i]++}function S(Y,N,T,H){H[o]++++H[O];for(p in N){split(p,a,z) 5 | P=N[p];x=y=H[a[1]]+=P;H[a[2]]+=P;T[a[1]X[p]]+=P;T[X[p]a[2]]+=P}delete N 6 | if(!Y){for(k in H)x>(k=H[k])?x=k:y> def 6 | /+= { 2 index 2 index known { 2 index 2 index get add } if put } def 7 | 8 | input 256 string readline pop 9 | /first 1 index 0 get def 10 | /last 1 index dup length 1 sub get def 11 | 0 1 2 index length 2 sub { 1 index exch 2 getinterval pairs exch 1 += } for pop 12 | 13 | /subs << { 14 | input token not { exit } if 15 | input (-> X) readstring pop 3 get 16 | } loop >> def 17 | 18 | /split { [ % key -- [ k1 k2 ] 19 | exch subs 1 index get exch ( ) cvs { } forall 20 | ( ) dup 1 4 3 roll put dup 0 4 index put 21 | 3 1 roll 22 | ( ) dup 0 4 3 roll put dup 1 4 3 roll put 23 | ] } def 24 | 25 | /extend { 26 | /pairs <<>> pairs { 27 | exch split { 2 index exch 2 index += } forall pop 28 | } forall def 29 | } def 30 | 31 | /answer { 32 | [ << first 1 last 1 >> pairs { 33 | exch ( ) cvs { 2 index exch 2 index += } forall pop 34 | } forall { exch pop } forall ] 35 | dup { gt lt } { 36 | /cmp exch def 37 | dup 0 get exch { 2 copy cmp { exch } if pop } forall 38 | exch 39 | } forall sub 2 idiv 40 | } def 41 | 42 | [ 10 30 ] { { extend } repeat answer = } forall 43 | -------------------------------------------------------------------------------- /day_15/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | function R(i,s,k){!i||(i=s FS k)in S||(q=v+int(substr(M[k%H], 4 | s%H+1,1)+k/H+int(s/H)-1)%9+1)*Q[i]>Q[i]||Q[i]=q}{g=M[H++]=$0} 5 | END{for(;X++<5;X*=4)for(v=k=0;S[$0=k]k;delete Q[k]){k=R(y=$2, 6 | x=$1,y-1)R(x,x-1,y)R(x> def 55 | /Q << /0,0 0 >> def 56 | X 1 sub dup key 57 | { 58 | mark extract-min visited 2 index 1 put 59 | 1 index 4 index eq { = cleartomark pop exit } if 60 | 1 index value [ { -1 0 } { +1 0 } { 0 -1 } { 0 +1 } ] { exec 61 | [ 2 3 ] { index add exch } forall add-node 62 | } forall cleartomark 63 | } loop 64 | } forall 65 | -------------------------------------------------------------------------------- /day_16/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | function b(i,t){for(;i--;sub(/./,z))t=t*2+(/^1/);return t}function D(e,c,o,d,E) 4 | {A+=b(3);if(4~e=b(3))do;while(b(1)*(d=b(4,d)));else{c=b(1)?b(11):o=b(15)-length 5 | for(d=e~2?"e":e;c--&&length+o;e||d+=B){D(E=B)e~1&&d*=B;e~2&&Bd&& 6 | d=B}e~5&&d=E>B;e~6&&d=E=Y=j++;x=y=0)for(X=i;!(y<$7|| 4 | x>$5||x>=$4&&y<=$8&&(j>A&&A=j)++B||!X&&x<$4);X&&x+=X--)y+=Y--}$0=(A^2-A)/2RS B 5 | -------------------------------------------------------------------------------- /day_17/solution.ps: -------------------------------------------------------------------------------- 1 | %!PS 2 | 3 | /input (%stdin) (r) file def 4 | /next-line { 5 | input 256 string readline pop 6 | (=) search not { pop exit } if pop pop 7 | (..) search pop /min-x exch cvi def pop 8 | (, y=) search pop /max-x exch cvi def pop 9 | (..) search pop /min-y exch cvi def pop 10 | /max-y exch cvi def 11 | } def 12 | 13 | /hit { 14 | dup min-y ge exch max-y le and exch 15 | dup min-x ge exch max-x le and and 16 | } def 17 | /miss { 18 | min-y lt 1 index max-x gt or 19 | exch min-x lt dx 0 le and or 20 | } def 21 | 22 | { next-line 23 | << /PageSize [ max-x 2 add min-y dup 1 add mul 2 idiv max-y sub 2 add ] >> setpagedevice 24 | 1 min-y neg 1 add translate 25 | 0 0 26 | max-x -1 1 { /dx0 exch def min-y neg -1 min-y { /dy0 exch def 27 | /dy dy0 def 28 | /dx dx0 def 29 | newpath 0 0 moveto 30 | { 31 | currentpoint hit { 32 | 1 add dy0 2 index gt { exch pop dy0 exch } if 33 | dy0 dy sub 1 sub 10 mod 10 div 1 1 sethsbcolor eofill 34 | exit 35 | } if 36 | currentpoint miss { exit } if 37 | dx dy 38 | dy0 0 gt { rlineto } { rmoveto } ifelse 39 | currentpoint 2 copy .5 0 360 arc moveto 40 | /dy dy 1 sub def 41 | dx 0 gt { /dx dx 1 sub def } if 42 | } loop 43 | } for } for 44 | 45 | 0.3 setlinewidth [1 1 2 1] 0 setdash 0 setgray 46 | newpath 0 0 moveto max-x 0 lineto stroke 47 | showpage 48 | 49 | exch dup 1 add mul 2 idiv = = 50 | } loop 51 | -------------------------------------------------------------------------------- /day_18/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | ############################################################################# 4 | # I don't even know how anymore, but this still works on my input... 5 | # Questionable hacks: 6 | # - reducing first record 7 | # - adding the same record to itself 8 | # - the max pair must be larger than the overall total 9 | # 10 | # NOTE: this exploits a bug in awk (version 20200816) 11 | # the expression --$u++ should not be valid, 12 | # but when u *happens to be a function parameter* it is allowed by awk. 13 | # This is parsed as (the fully parenthesised expression isn't even valid): 14 | # --($(u++)) 15 | # even though it should be parsed as: 16 | # --(($u)++) 17 | # which would pre-decrement an rvalue. 18 | ############################################################################# 19 | 20 | END{print M()g;for(u in N)for(m in N)S(u m)M();print B}gsub(/,|()/,FS)N[$0]&& 21 | S(O$0)function M(){+((g=$1)sub(/ *./,z))||g=M()+g*3+M()+g*2;B> def 7 | 8 | /input (%stdin) (r) file def 9 | /lines [ { 10 | input 256 string readline not { pop exit } if 11 | [ exch { 12 | zero sub dup 0 lt { pop } { 13 | dup 9 gt { delim exch get } if 14 | } ifelse 15 | } forall ] 16 | } loop ] def 17 | 18 | /explode { 19 | /unchanged true def 20 | /carry 0 def 21 | /depth 0 def 22 | [ exch { unchanged { 23 | dup close eq { 24 | depth 4 gt { 25 | /unchanged false def 26 | pop 27 | /carry exch def 28 | 2 1 counttomark 3 sub { /i exch def 29 | i index type /integertype eq { 30 | i 1 add i roll add i 1 roll 31 | 0 exit 32 | } if 33 | } for 34 | pop pop 0 35 | } if 36 | /depth depth 1 sub def 37 | } { dup open eq { /depth depth 1 add def } if } ifelse 38 | } { 39 | carry 0 ne { dup type /integertype eq { 40 | carry add /carry 0 def 41 | } if } if 42 | } ifelse } forall ] 43 | unchanged 44 | } bind def 45 | 46 | /split { 47 | /unchanged true def 48 | [ exch { unchanged { 49 | dup type /integertype eq { dup 9 gt { 50 | /unchanged false def 51 | open exch 52 | 2 div dup floor cvi exch ceiling cvi 53 | close 54 | } if } if 55 | } if } forall ] 56 | unchanged 57 | } bind def 58 | 59 | /magnitude { 60 | dup type /arraytype eq { 61 | aload pop magnitude 2 mul 62 | exch magnitude 3 mul add 63 | } if 64 | } bind def 65 | /sum { 66 | 1 sub array astore { 67 | [ open [ 5 3 roll ] { aload pop } forall close ] 68 | { explode { split { exit } if } if } loop 69 | } forall { cvx exec } forall magnitude 70 | } bind def 71 | 72 | lines aload length sum = 73 | /max 0 def 74 | lines { lines { 2 copy ne { 75 | 1 index 2 sum dup max gt { /max exch def 0 } if 76 | } if pop } forall pop } forall 77 | max = 78 | -------------------------------------------------------------------------------- /day_19/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | function F(y,x){x++<3&&$x-=y*e[x]F(y,x)}function How(_){print _;Big? Idk ~11:km} 4 | function O(z){z?d+=O(z-1)(($z-a[z])^2)^.5:d=0}function s(x,y,t){split(S[x,y],t)} 5 | function R(x,y){return++y<4?R(x,y)+$y*(!((x=c[x]-e[x])-(y=a[y]-b[y]))-!(x+y)):0} 6 | /-+-/{T[o]=o=$3}gsub(/,/,SUBSEP=FS){for(S[o,p=r=C[o]++]=$0;p--;f[o,p]=f[o,p]d r) 7 | f[o,r]=f[o,r](d=s(o,p,a)O(3)RS d"\40")p}END{for(L[0];D1&&++n>9;){T[j]=s(j,J,a)s(j,$2,b)s(i,I,c)s(i,+e[2],e) 10 | for(k=C[j];k--;S[j,k]=R(1)FS R(2)FS R(3))$0=S[j,k];$0=S[i,I]s(j,J,e);L[j]=F(1)$0 11 | for(k=C[j];k--;$0=L[j])S[j,k]=s(j,k,e)F(-1)$0;K=!++D}for(k in S)Many+=!q[S[k]]++ 12 | for(k in L){$0=L[k];for(j in L)O(split(L[j],a))+d>Big&&Big=d}How(Many);How(Big)} 13 | -------------------------------------------------------------------------------- /day_20/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | function I(m,a,g,e){++NR;for(y=l--+2;y<=NR;y++)for(x=l;++x2{for(i=split($0,a,z);i;i--)P[NR,i]=a[i]~/#/} 7 | -------------------------------------------------------------------------------- /day_20/solution.ps: -------------------------------------------------------------------------------- 1 | %!PS 2 | 3 | /assert { exch not { 4 | $error /newerror true put 5 | (%stderr) (w) file [ (\033[31mASSERT FAIL:\033[0m ) 4 3 roll (\n) ] { 6 | 2 copy writestring pop 7 | } forall flushfile 8 | stop 9 | } if pop } def 10 | 11 | /input (%stdin) (r) file def 12 | 13 | /char-to-bit { 10 idiv 4 exch sub } def 14 | /read-bits { [ 3 1 roll string readline pop { char-to-bit } forall ] aload length } def 15 | 16 | /algorithm [ { input 512 read-bits 0 eq { exit } if } loop ] def 17 | algorithm length 512 eq (invalid algorithm) assert 18 | /fill-value 19 | algorithm 0 get 1 eq { 20 | algorithm 511 get 0 eq (last must be 0, when first is 1) assert 21 | { round 2 mod } 22 | } { 0 } ifelse 23 | def 24 | 25 | /image [ { [ input 256 read-bits 0 eq { pop exit } if ] } loop ] def 26 | 27 | /get-or-fill { 28 | % y x img 29 | mark 4 1 roll { 30 | 3 2 roll get exch get exch pop 31 | } stopped { cleartomark fill-value } if 32 | } bind def 33 | 34 | /pixel { 35 | 0 -1 1 1 { -1 1 1 { 36 | 5 index 2 index add 37 | exch 5 index add 38 | 4 index get-or-fill 39 | 3 2 roll 2 mul add exch 40 | } for pop } for 41 | algorithm exch get 42 | } bind def 43 | 44 | /enhance { 45 | /height 1 index length def 46 | /width 1 index 0 get length def 47 | [ exch -1 1 height { 48 | [ exch 49 | -1 1 width { 50 | counttomark 1 add index pixel 51 | 4 1 roll pop pop 52 | } for pop 53 | ] exch 54 | } for pop ] 55 | /round round 1 add def 56 | draw 57 | } def 58 | 59 | /lit { 0 exch { { add } forall } forall } def 60 | 61 | 62 | /round 0 def 63 | /max-rounds 50 def 64 | 65 | /scale-factor 10 def 66 | /draw currentpagedevice /OutputDevice get /bbox ne { 67 | /height image length def 68 | /width image 0 get length def 69 | << /PageSize [ [ width height ] { max-rounds 1 sub 2 mul add scale-factor mul } forall ] >> setpagedevice 70 | { 71 | scale-factor dup scale 72 | max-rounds round sub dup translate 73 | 0 1 height 1 sub { 74 | 2 copy get 0 1 width 1 sub { 75 | 2 copy get fill-value ne { 2 index 1 1 rectfill } { pop } ifelse 76 | } for pop pop 77 | } for 78 | 79 | showpage 80 | } 81 | } { {} } ifelse def 82 | 83 | image draw enhance enhance dup lit = flush 84 | max-rounds round sub { enhance } repeat lit = 85 | -------------------------------------------------------------------------------- /day_21/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | function D(i,r,a,c){for(p in Q)for(c in i){$0=c;g(a,Q[p]*i[$0],r+1)}c&&D(a,!r)} 4 | function g(a,m,e) {($(e+2)+=$e=($e+p+1)%10+1)<21?a[$0]+=m:e~1?t+=m:u+=m}d(a,$5) 5 | function o(f) {x=(2+r+++r+++r+++f)%10+1}a{U[a FS $5]=1;D(U)}{a=$5}$0=r*s[!q] 6 | function d(i,e) {i&&(1e3>s[q=!q]+=o(i)x)&&d(e,x)}split(1367631,Q,z)&&$0=u>t?u:t 7 | -------------------------------------------------------------------------------- /day_21/solution.ps: -------------------------------------------------------------------------------- 1 | %!PS 2 | 3 | /input (%stdin) (r) file def 4 | [ /A /B ] { 4 { input token pop pop } repeat input token pop def } forall 5 | 6 | /deterministic { 7 | /rolls 0 def 8 | 0 exch 0 4 3 roll { 9 | rolls 1 add 3 mul add 2 add 10 mod 1 add 10 | /rolls rolls 3 add def 11 | exch 1 index add 12 | dup 1000 ge { exit } if 13 | exch 4 2 roll 14 | } loop pop pop pop 15 | rolls mul 16 | } bind def 17 | 18 | /concat { % (str1) (str2) -- (str1\0str2) 19 | 2 copy length exch length add 1 add string dup dup 20 | 4 3 roll 4 index length 1 add exch putinterval 3 1 roll exch 21 | 0 exch putinterval 22 | } bind def 23 | 24 | /key { () exch { 10 string cvs concat } forall } bind def 25 | /value { [ exch 256 string cvs { token not { exit } if exch } loop ] } bind def 26 | 27 | /+= { 28 | % val dict key 29 | 2 copy known { 2 copy get } { 0 } ifelse 30 | 4 3 roll add put 31 | } bind def 32 | 33 | /dice << 3 1 4 3 5 6 6 7 7 6 8 3 9 1 >> def 34 | 35 | /quantum { 36 | /qa 0 def 37 | /qb 0 def 38 | [ 3 2 roll 1 sub 0 4 3 roll 1 sub 0 ] key 39 | << exch 1 >> { 40 | dup length 0 eq { pop exit } if 41 | << >> exch { 42 | exch /state exch value def 43 | dice { 44 | 2 index mul 45 | exch state 0 get add 10 mod 46 | dup state 1 get add 1 add 47 | dup 21 ge { pop pop /qa exch qa add def } { 48 | 4 index [ 4 2 roll state 2 get state 3 get ] key += 49 | } ifelse 50 | } forall 51 | pop 52 | } forall 53 | << >> exch { 54 | exch /state exch value def 55 | dice { 56 | 2 index mul 57 | exch state 2 get add 10 mod 58 | dup state 3 get add 1 add 59 | dup 21 ge { pop pop /qb exch qb add def } { 60 | 4 index [ state 0 get state 1 get 6 4 roll ] key += 61 | } ifelse 62 | } forall 63 | pop 64 | } forall 65 | } loop 66 | qa qb 2 copy lt { exch } if pop 67 | } bind def 68 | 69 | A B deterministic = 70 | A B quantum = 71 | -------------------------------------------------------------------------------- /day_22/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | function V(C,n){for(k in C){$0=k;n+=($2-$1+1)*($4-$3+1)*($6-$5+1)*C[k]} 4 | print n}function F(C,c){for(k in C)c[k];for(k in c)g(split(k,a))$2{F(A)}F(B)END{V(A)V(B) 7 | }function g(i){return$i> exch { 57 | aload pop 58 | [ 3 index { 0 eq { pop } if } forall ] { 59 | dup value 2 index overlap dup valid { 60 | 4 index dup 3 index get neg 61 | exch 2 index key += 62 | } if pop pop 63 | } forall 64 | exch { 2 copy key 1 3 1 roll += } if 65 | pop 66 | } forall volume 67 | } bind def 68 | 69 | [ small-steps all-steps ] { reboot = } forall 70 | -------------------------------------------------------------------------------- /day_23/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | ############################################################################## 4 | # 5 | # This solution makes three significant assumptions about the input data: 6 | # 7 | # 1) Each amphipod must move to the hallway 8 | # 2) Each row has exactly one amphipod of each type 9 | # 3) The input is not one of the 26 inputs (18 %) that fail part 2 :) 10 | # 11 | # With the first two assumptions only the horizontal movement needs to be 12 | # calculated. The additional cost to move to and from the hallway is constant 13 | # derived from the number of rows. The additional lines in part 2 will not 14 | # invalidate the assumptions. 15 | # 16 | # The vertical cost is: 17 | # 18 | # E(rows) = (1 + 10 + 100 + 1000) * (∑ 1..rows) * 2 19 | # 20 | # The first term is the cost of a single step of a row (assumption 2). 21 | # This is multiplied by the sum of steps to the hall from each depth. 22 | # This gives the one way cost, which is then multiplied by 2 to get the full 23 | # cost of a return journey. 24 | # 25 | # This gives us: 26 | # 27 | # E(2) = 6666 28 | # E(4) = 22220 29 | # 30 | # And we can nicely derive E(4) from E(2): 31 | # 32 | # E(4) = E(2) * (∑ 1..4)/(∑ 1..2) 33 | # = E(2) * 10/3 34 | # = E(2) * (7/3 + 1) 35 | # 36 | # The map is represented as a single string: 7 characters representing the 37 | # hallway, followed by the rows from top to bottom 4 characters each row. 38 | # The characters are mapped: "A" => A, "B" => 1, "C" => 2, "D" => 3, "." => 6. 39 | # 40 | # hallway|row1|row2 -- "|"-separators added for visual aid. 41 | # 6666666|A123|A123 -- Configuration with each amphipod in it's room. 42 | # 43 | # When moving an amphipod from the hallway to a room, only the last row is 44 | # checked, and the amphipod is moved there. Thus the solved state consists of 45 | # all sixes (empty), ending with a single complete row in correct order. 46 | # 47 | # 6666666|6666|A123 -- Solved state for part 1 48 | # 49 | ############################################################################## 50 | 51 | function S(a,y,s){for(;y<7&&6~$(y+=a);$0=k)j(y,r,s+=2-(1.7~y))}function j(u,l, 52 | e,m){t=$l;$l=$u;$u=t;e=m+e*10^t;for(l=u=0;8>t=++u;)if(6-(a=$u)&&6a~$(o=4+a+Y)) 53 | {for($o=6;++t2;for(--t;t-->a+3&&$t~6;l++)l+=t<6;if(21~t-a) 54 | return j(o,u,l,e)}(V[$0]<=e+=J)*V[$0]||Q[V[$0]=e]=Q[e]7$0}sub(/B/,1){OFS=FS=z} 55 | sub(/C/,2)sub(/D/,3)~1{A=B;B=$4$6$8$10}A{Y=2^NR/2;for(Q[J=0]=666(m=6666)A X B; 56 | split(Q[J],q,7)Q[J]!~7m"{"Y"}A123";J++)for(k in q)for(i=z<$0=k=q[k];i++<5;$r&& 57 | S(1,i)S(-1,i+1))for(r=6+i;$r~6;)r+=4;print++N*m+J;delete Q;X="321A31A2";N=7/3} 58 | -------------------------------------------------------------------------------- /day_24/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | function f(d){for(i=1;i++<=14;)printf(d[i]<1?1:d[i]>9?9:d[i]) 4 | print z}9>o=$16{$0=S[--s];o+=$1;m[NR]=1+o;M[NR]=9+o;m[$2]=1-o 5 | M[$2]=9-o}$16>9{S[s++]=$46" "NR}BEGIN{RS="inp?"}END{f(M)f(m)} 6 | -------------------------------------------------------------------------------- /day_24/solution.ps: -------------------------------------------------------------------------------- 1 | %!PS 2 | 3 | /input (%stdin) (r) file def 4 | /next { input token pop } def 5 | 6 | /set-digit { 7 | % index val str 8 | 3 1 roll 9 | dup 1 lt { pop 1 } if 10 | dup 9 gt { pop 9 } if 11 | 48 add put 12 | } def 13 | 14 | /min 14 string def 15 | /max 14 string def 16 | 0 1 13 { 17 | { next /inp eq { exit } if } loop 18 | 15 { next pop } repeat 19 | 20 | next dup 9 gt { pop 29 { next pop } repeat next } { 21 | 3 2 roll add 22 | 2 copy 2 copy 23 | 1 add min set-digit 24 | 9 add max set-digit 25 | exch pop 2 copy 26 | 1 exch sub min set-digit 27 | 9 exch sub max set-digit 28 | } ifelse 29 | } for 30 | max = 31 | min = 32 | -------------------------------------------------------------------------------- /day_25/solution.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | END{while(S(">",++N)+S("v"));print N}function S(t,e,p){for(k in A) 4 | B[k]=A[k];for(k in B)p+=B[$0=k]~t&&0~B[i=(k+!e)%NR" "($2+!!e)%W]&& 5 | A[i]=(A[k]=0)t;return p}{for(W=i=gsub(z,FS)-1;i;)A[NR-1" "--i]=$i} 6 | -------------------------------------------------------------------------------- /day_25/solution.ps: -------------------------------------------------------------------------------- 1 | %!PS 2 | 3 | /input (%stdin) (r) file def 4 | 5 | /left /down /empty (.v>) { def } forall 6 | /map [{ input 256 string readline not { pop exit } if } loop] def 7 | /H map length def 8 | /W map 0 get length def 9 | 10 | /map-copy { [ map { W string copy } forall ] } bind def 11 | 12 | /step { 13 | false map-copy 14 | 0 1 H 1 sub { /y exch def 0 1 W 1 sub { /x exch def 15 | dup y get x get left eq { dup y get x 1 add W mod get empty eq { 16 | map y get dup x empty put x 1 add W mod left put 17 | exch pop true exch 18 | } if } if 19 | } for } for 20 | pop map-copy 21 | 0 1 H 1 sub { /y exch def 0 1 W 1 sub { /x exch def 22 | dup y get x get down eq { dup y 1 add H mod get x get empty eq { 23 | map y get x empty put map y 1 add H mod get x down put 24 | exch pop true exch 25 | } if } if 26 | } for } for 27 | pop 28 | } bind def 29 | 30 | /draw currentpagedevice /OutputDevice get /bbox eq { {} } { 31 | /size 10 def 32 | << /PageSize [ [ W H ] { 1 add size mul } forall ] >> setpagedevice 33 | { 34 | size dup scale 35 | 1 1 translate 36 | 0 1 H 1 sub { /y exch def 0 1 W 1 sub { /x exch def 37 | map y get x get dup empty eq { pop } { 38 | 1 index exch down eq { 180 add 360 mod } if 39 | 360 div 1 1 sethsbcolor 40 | x y .5 0 360 arc fill 41 | } ifelse 42 | } for } for 43 | showpage 44 | } 45 | } ifelse bind def 46 | 47 | 0 { draw 1 add step not { exit } if } loop = 48 | --------------------------------------------------------------------------------