Skip to content

Instantly share code, notes, and snippets.

@tomtheisen
Last active December 18, 2021 06:01
Show Gist options
  • Save tomtheisen/24051041da60cb67075fb9d33b3c5afe to your computer and use it in GitHub Desktop.
Save tomtheisen/24051041da60cb67075fb9d33b3c5afe to your computer and use it in GitHub Desktop.
Advent of Munging 2021

Advent Of Code 2021 solutions in Text Munge. https://munge.netlify.app/

Why? I don't know.

Day 1

Part 1
#(
	/(\d+)\s+(?=(\d+))/ => { 
		$2 $1 >> if { inc(deepercount) } 
	}
	{ get(deepercount) }
)
Part 2
#(
	/(\d+)\s+(?=\d+\s+\d+\s+(\d+))/ => { 
		$2 $1 >> if { inc(deepercount) } 
	}
	{ get(deepercount) }
)

Day 2

Part 1
#(
	fx { 0 set(x) set(y) }
	(
		/forward (\d+)/ => { get(x) $1 + set(x) }
		/up (\d+)/      => { get(y) $1 - set(y) }
		/down (\d+)/    => { get(y) $1 + set(y) }
	)
	{ get(x) get(y) * }
)
Part 2
#(
	fx { 0 set(x) set(y) set(aim) }
	(
		/forward (\d+)/ => { 
			get(x) $1 + set(x) 
			get(aim) $1 * get(y) + set(y)
		}
		/up (\d+)/   => { get(aim) $1 - set(aim) }
		/down (\d+)/ => { get(aim) $1 + set(aim) }
	)
	{ get(x) get(y) * }
)

Day 3

Part 1
def(bitmode) #(
	@ /01|10/ => "" ! adjacent opposites vanish
	/0+/ => "0"
	/1+/ => "1"
)
#(
	/.+/ => { _ push(lines) _ len set(width) }
	{
		0 set(col) drop
		"" get(width) times {
			for(lines) {
				_ get(col) skip 1 take
				cat
			}
			push(cols)
			inc(col)
		}
		0 for(cols) {
			2 *
			_ do(bitmode) + ! gamma bit
		}
		set(gamma)
		1 get(width) times { 2 * } 1 -
		get(gamma) - ! epsilon
		*
	}
)
Part 2
def(bitmode) #(
	@ /01|10/ => "" ! adjacent opposites vanish
	/0+/ => "0"
	/1+|^$/ => "1" ! default 1

)
def(findO2) {
	! get mode of col'th char
	"" for(O2lines) { _ get(col) skip 1 take cat }
	do(bitmode) set(criteria) drop
	
	! filter
	count(O2lines) times {
		pop(O2lines)
		copy get(col) skip 1 take get(criteria) = 
		if { cons(O2lines) } { drop }
	}
	
	! recurse
	count(O2lines) 1 >> if {
		inc(col) do(findO2)
	}
}
def(findCO2) {
	! get mode of col'th char
	"" for(CO2lines) { _ get(col) skip 1 take cat }
	do(bitmode) set(criteria) drop
	
	! filter
	count(CO2lines) times {
		pop(CO2lines)
		copy get(col) skip 1 take get(criteria) = not
		if { cons(CO2lines) } { drop }
	}
	
	! recurse
	count(CO2lines) 1 >> if {
		inc(col) do(findCO2)
	}
}
def(unbin) #(
	fx { 0 set(unbin) }
	/./ => { get(unbin) 2 * _ + set(unbin) }
	{ get(unbin) }
)
#(
	/.+/ => { ! populate arrays and set dimension
		_ push(O2lines) 
		_ push(CO2lines) 
		_ len set(width) 
	}
	{
		! compute oxygen generator rating
		0 set(col) do(findO2) 
		pop(O2lines) do(unbin) set(O2rating) 
		
		! compute CO2 scrubber rating 
		0 set(col) do(findCO2) 
		pop(CO2lines) do(unbin) set(CO2rating) 

		clear get(O2rating) get(CO2rating) *
	}
)

Day 4

Part 1
#(
	/ ?\b(\d)\b/ => { 0 $1 } ! zero-fill to two digits
	@(
		/.*X.*/s => () ! if board is won
		/.*/s => #( 
			/^(\d+),?/ => { $1 set(callnum) clear }
			get(callnum) => "__" ! replace called number with __
			
			! in a win, replace _ with X
			! row win
			/^(?:__ ){4}__$/m => '_' => "X"
			! column win
			/(?:__(?:\s\w\w){4}\s){4}__/m 
				=> /__((?:\s\w\w){4})?/ 
				=> /^__/ => "XX"
		)
	)
	( ! keep only the winning board
		/(\n.|.)*?X(\n.|.)*/ => ()
		/./s => ""
	)
	/\d+/ => { get(boardtotal) _ + set(boardtotal) }
	{ get(boardtotal) get(callnum) * }
)
Part 2
#(
	/ ?\b(\d)\b/ => { 0 $1 } ! zero-fill to two digits
	@1#(
		/(?:\n.|.)*?X(?:\n.|.)*/ => { 
			! remove winning board but remember it
			_ set(board) 
			get(callnum) set(clearnum)
			clear
		}
		/.*/s => #(
			/^(\d+),?/ => { $1 set(callnum) clear }
			get(callnum) => "__" ! replace called number with __
			
			! in a win, replace _ with X
			! row win
			/^(?:__ ){4}__$/m => '_' => "X"
			! column win
			/(?:__(?:\s\w\w){4}\s){4}__/m 
				=> /__((?:\s\w\w){4})?/ 
				=> /^__/ => "XX"
		)
	)
	{ get(board) }
	/\d+/ => { get(boardtotal) _ + set(boardtotal) }
	{ get(boardtotal) get(clearnum) * }
)

Day 5

Part 1
def(addcloud) {
	"clouds" swap cat copy  ! build variable name
	get 1 + ! get dynamically
	swap set ! and store the result
	2 = if { inc(multiclouds) }
	inc(pos)
}
#(
	(
		/(\d+),(\d+) -> \1,(\d+)/ => {
			$2 $3 min set(pos) drop
			$2 $3 max 1 + get(pos) - times 
			{ ! iterate over line
				$1 "," get(pos) cat cat 
				do(addcloud)
			}
		}
		/(\d+),(\d+) -> (\d+),\2/ => {
			$1 $3 min set(pos) drop
			$1 $3 max 1 + get(pos) - times 
			{ ! iterate over line
				get(pos) "," $2 cat cat
				do(addcloud)
			}
		}
	)
	{ get(multiclouds) }
)
Part 2
def(abs) '-' => ""
def(sign) /[1-9]\d*/ => "1"
#(
	! match input line
	/(\d+),(\d+) -> (\d+),(\d+)/ => {
		! calculate directions
		$3 $1 - do(sign) set(dx)
		$4 $2 - do(sign) set(dy)
	
		! caclulate target iteration count
		$3 $1 set(x) - do(abs)
		$4 $2 set(y) - do(abs)
		max 1 +
		times { ! iterate over line
			get(x) "," get(y) cat cat 

			"clouds" swap cat copy ! build variable name
			get 1 + ! get dynamically
			swap set ! and store the result
			2 = if { inc(multiclouds) }
			
			get(x) get(dx) + set(x) drop
			get(y) get(dy) + set(y) drop
		}
	}
	{ get(multiclouds) }
)

Day 6

Part 1
def(day) (
	'0' => "68"
	/\d/ => { _ 1 - }	
)
#(
	',' => ""
	{ 
		_ 80 times { do(day) } 
		len
	}
)
Part 2
def(day) /^(\d+),((?:\d+,){6})(\d+),(\d+)$/ => {
	$2          ! days 0-5
	$3 $1 + "," ! day 6
	$4 ","      ! day 7
	$1          ! day 8
}
#(
	/\d/ => { _ push(fish) }
	{ ! index by cohort
		9 times { 0 push(cohort) }
		for(fish) {
			_ 1 + times { uncons(cohort) }
			1 +
			_ 1 + times { cons(cohort) }
		}
		"," join(cohort)
		256 times { do(day) }
	}
	@/(\d+),(\d+)/ => { $1 $2 + }
)

Day 7

Part 1
def(abs) '-' => ""
#(
	/\d+/ => { _ 5 lpad push(pos) }
	{
		sort(pos)
		
		! find halfway point
		count(pos) 2 / floor set(half) 
		times { pop(pos) }
		! retrieve median
		set(median) 
		! put everything back
		get(half) times { push(pos) } 
		
		! sum total variance
		0 for(pos) { _ get(median) - do(abs) + }
	}
)
Part 2
def(abs) '-' => ""
#(
	fx { "1e99" set(besttarget) set(bestcost) }
	/\d+/ => { 
		_ push(pos)
		_ get(min) min set(min)
		_ get(max) max set(max)
	}
	{
		get(max) get(min) set(target) -
		times {
			0 for(pos) {
				_ get(target) - do(abs)
				copy 1 + * 2 / +
			}
			set(cost) 
			get(bestcost) << if {
				get(cost) set(bestcost) drop
				get(target) set(besttarget) drop
			}
			inc(target)
		}
	}
	{ get(bestcost) }
)

Day 8

Part 1
#(
	/.*\| / => ""
	(
		/\b\w{2,4}\b/ => { inc(sum) }
		/\b\w{7}\b/ => { inc(sum) }
	)
	{ get(sum) }
)
Part 2
#(
	/.+/ => #(
		! one-by-one replace each lowercase character to the
		! *correct* uppercase character from the 7-segment

		/([a-g])(?=([^|]*?\1){8})/ => fx { $1 set(F) }
		get(F) => "F"
		
		{ "abcdefg " _ }
		/^\w*([a-g])\w* (?=[^|]*\b(?:\1\w|\w\1)\b)(?=([^|]*?\1){8})/ 
			=> { $1 set(C) drop }
		get(C) => "C"
		
		/([a-g])(?=([^|]*?\1){7})/ => fx { $1 set(A) }
		get(A) => "A"
		
		{ "abcdefg " _ }
		/^\w*([a-g])\w* (?=[^|]*\b(?=\w*\1)\w{4}\b)(?=([^|]*?\1){7})/ 
			=> { $1 set(D) drop }
		get(D) => "D"

		/([a-g])(?=([^|]*?\1){6})/ => fx { $1 set(G) }
		get(G) => "G"
		
		/([a-g])(?=([^|]*?\1){5})/ => fx { $1 set(B) }
		get(B) => "B"

		/[a-g]/ => "E"
		
		! with all letters now corrected, remove prefix part
		/.+\|/ => ""
		! sort words
		/\w+/ => #(
			fx { empty(chars) }
			/./ => fx { _ push(chars) }
			{ sort(chars) "" join(chars) }
		)
		(
			/ ABCEFG\b/ => "0"
			/ CF\b/ => "1"
			/ ACDEG\b/ => "2"
			/ ACDFG\b/ => "3"
			/ BCDF\b/ => "4"
			/ ABDFG\b/ => "5"
			/ ABDEFG\b/ => "6"
			/ ACF\b/ => "7"
			/ ABCDEFG\b/ => "8"
			/ ABCDFG\b/ => "9"
		)
		fx { get(sum) _ + set(sum) }
	)
	{ get(sum) }
)

Day 9

Part 1

Takes about 30 seconds. transpose is slow.

def(transpose) #(
	fx { empty(lines) }
	/.+/ => { _ push(lines) _ len set(width) }
	{
		0 set(i) drop
		get(width) times {
			for(lines) { _ get(i) skip 1 take }
			"\n" inc(i)
		}
	}
	/\n+$/ => ""
)
#(
	/\s+$/ => "" ! normalize ending
	( ! put current height in lower right corner
		/.+$/ => { _ " \n " 9 _ len lpad }
		/.+/m => { _ " " }
	)
	@#(
		/(?=(\d))(?:\B\1|\1\B)(?=.*\1$)/s => " "
		{ _ do(transpose) }
		/(?=(\d))(?:\B\1|\1\B)(?=.*\1$)/s => " "
		{ _ do(transpose) }
		
		! decrement working digit
		/[1-9]$/ => { _ 1 - }
		/0$/ => ""
	)
	/\d/ => { _ 1 + get(risk) + set(risk) }
	{ get(risk) }
)
Part 2

This is very slow for the full solution, taking more than 15 minutes on my machine.

def(transpose) #(
	fx { empty(lines) }
	/.+/ => { _ push(lines) _ len set(width) }
	{
		0 set(i) drop
		get(width) times {
			for(lines) {
				_ get(i) skip 1 take
			}
			"\n" inc(i)
		}
	}
)
#(
	/\s+$/ => "" ! normalize ending
	@ #(
		1(/[0-8]/ => "X") ! find start of next basin
		@ #( ! flood fill
			/[0-8]*X[0-8]*/ => /./ => "X"
			{ _ do(transpose) }
			/[0-8]*X[0-8]*/ => /./ => "X"
			{ _ do(transpose) }
		)
		fx { 0 set(size) }
		/X/ => { inc(size) " " }
		fx { get(size) 5 lpad dump push(sizes) }
	)
	{ 
		"Solution: " sort(sizes) 1 3 times { pop(sizes) * }
		"\nBasin removal:\n" _
	}
)

Day 10

Part 1
#(
	@(
		'()' => ""
		'[]' => ""
		'{}' => ""
		'<>' => ""
	)
	/[\(\[{<]/ => ""
	/(.)?.*\n?/ => { $1 }
	(
		')' => "3 "
		']' => "57 "
		'}' => "1197 "
		'>' => "25137 "
	)
	@/(\d+) (\d+)/ => { $1 $2 + }
)
Part 2
#(
	@( ! reduce
		'()' => ""
		'[]' => ""
		'{}' => ""
		'<>' => ""
	)
	! remove the invalid
	/.*[\)\]}>].*\n?/ => ""
	( ! token scores
		'(' => " 1"
		'[' => " 2"
		'{' => " 3"
		'<' => " 4"
	)
	! line scores
	@/(\d+) (\d+)$/m => { $2 5 * $1 + }
	
	! accumulate push all scores
	/\d+/ => { _ 20 lpad push(scores) }

	{ ! median
		sort(scores) 
		count(scores) 2 / floor times { pop(scores) drop }
		pop(scores)
		0 + ! trim
	}
)

Day 11

Part 1
! Legend: 
! 	F - to flash 
! 	f - flash on cooldown this turn

def(countF) #(
	/[^F]/s => ""
	{ _ len }
)
def(step) #(
	(
		'9' => { "F" inc(flashes) }
		/\d/ => { _ 1 + }
	)
	@(
		/(?<=(.{1,12})?)(\d)(?=(.{1,12})?)/s => { 
			$1 12 lpad 3 take "\n" cat
			$1 12 lpad 11 skip $2 $3 12 rpad 1 take "\n" cat cat cat cat
			$3 12 rpad 9 skip "\n\n" cat
			cat cat
			do(countF) _ +
			copy 9 >> if { drop "F" inc(flashes) }
		}
		'F' => "f"
	)
	'f' => "0"
)
{ 
	_ 100 times {do(step)} 
	clear 
	get(flashes)
}
Part 2
def(countF) #(
	/[^F]/s => ""
	{ _ len }
)
def(step) #(
	fx { inc(steps) }
	(
		'9' => { "F" inc(flashes) }
		/\d/ => { _ 1 + }
	)
	@(
		/(?<=(.{1,12})?)(\d)(?=(.{1,12})?)/s => { 
			$1 12 lpad 3 take "\n" cat
			$1 12 lpad 11 skip $2 $3 12 rpad 1 take "\n" cat cat cat cat
			$3 12 rpad 9 skip "\n\n" cat
			cat cat
			do(countF) _ +
			copy 9 >> if { drop "F" inc(flashes) }
		}
		'F' => "f"
	)
	/^(?:f{10}\n?){10}/ => ""
	'f' => "0"
)
#(
	@ { _ do(step) }
	{ get(steps) 1 - }
)

Day 12

Part 1
#(
	/(.+)-(.+)/ => { $1 $2 push $2 $1 push }
	"start"
	@#(
		(
			/^.*?\bend$/m => ()
			/^(.*?\b(\w+))$\n?/m => {
				$1 set(sofar) drop
				$2 for { get(sofar) " " _ "\n" }
			}
		)
		/^.*?\b([a-z]+)\b.*?\b\1\b.*$\n?/m => ""
	)
	/.+/ => { inc(paths) }
	{ get(paths) }
)
Part 2
#(
	/(.+)-(.+)/ => { $1 $2 push $2 $1 push }
	"start"
	@#(
		(
			/^.*?\bend$/m => ()
			/^(.*?\b(\w+))$\n?/m => {
				$1 set(sofar) drop
				$2 for { get(sofar) " " _ "\n" }
			}
		)
		/^.+?\bstart\b.*$\n?/m => ""
		/^.*?\b([a-z]+)\b(?=.*?\b\1\b).*?\b([a-z]+)\b(?=.*?\b\2\b).*$\n?/m => ""
	)
	/.+/ => { inc(paths) }
	{ get(paths) }
)

Day 13

Part 1
def(foldX) /(\d+),(\d+)/ => {
	$1 get(pos) 2 * $1 - min "," $2
}
def(foldY) /(\d+),(\d+)/ => {
	$1 "," $2 get(pos) 2 * $2 - min
}

#(
	/^(.*?)fold along ([xy])=(\d+)\n?/s => {
		$3 set(pos) drop
		$2 "x" = if { $1 do(foldX) }
		$2 "y" = if { $1 do(foldY) }
	}
	/^(.+)$(?=.*?\b\1\b)/sm => ""
	/^\d+,\d+$/m => fx { inc(dots) }
	{ get(dots) }
)
Part 2
def(foldX) /(\d+),(\d+)/ => {
	$1 get(pos) 2 * $1 - min "," $2
}
def(foldY) /(\d+),(\d+)/ => {
	$1 "," $2 get(pos) 2 * $2 - min
}
#(
	@#( ! repeat folds
		/^(.*?)fold along ([xy])=(\d+)\n?/s => {
			$3 set(pos) drop
			$2 "x" = if { $1 do(foldX) }
			$2 "y" = if { $1 do(foldY) }
		}
		! eliminate dupes
		/^(.+)$(?=.*?\b\1\b)\n?/sm => ""
	)
	! get bounding box
	/(\d+),(\d+)/ => fx { 
		$1 1 + get(width) max set(width) drop
		$2 1 + get(height) max set(height) drop
	}
	/^/ => "\n" ! now each line is delimited on both ends
	{
		0 set(row) drop
		get(height) times {
			0 set(col) drop
			get(width) times {
				_
				"\n" get(col) "," get(row) "\n" cat cat cat cat
				index -1 >> if { "#" } { " " }
				inc(col)
			}
			"\n"
			inc(row)
		}
	}
)

Day 14

Part 1
def(PairInsertion) /(?<=(\w))(?=(\w))/ => { $1 $2 cat get }
#(
	/(\w\w) -> (\w)\n?/ => { $2 $1 set $2 push(symbol) clear }
	{ _ 10 times { do(PairInsertion) } }
	/\w/ => { _ inc }
	{ 
		for(symbol) {
			_ get 9 lpad " " _ cat cat push(count)
		} 
		sort(count)
		uncons(count) " " pop(count) ! least and most common
	}
	/\s*(\d+).*?(\d+).*/ => { $2 $1 - }
)
Part 2
def(PairInsertion) #(
	/([A-Z])([A-Z]) (\d+)/ => { 
		$1 $1 $2 cat get " " $3 "\n"
		$1 $2 cat get $2 " " $3
	}
	@ /(\w\w) (\d+)\n(.*)\1 (\d+)\n?/s 
		=> { $1 " " $2 $4 + "\n" $3 }
)
#(
	(
		/^|$/ => "_"
		/(\w\w) -> (\w)\n?/ => { $2 $1 set $2 push(symbol) clear }
		/\s/ => ""
	)
	(
		/(\w)(?=(\w))/ => { $1 $2 " 1\n" }
		/.$/ => ""
	)
	{ 
		_ 40 times { do(PairInsertion) }
	}
	/([A-Z])(?=.*?(\d+))/ => fx { 
		$1 get $2 + $1 set 
		$1 push(symbols)
	}
	{ 
		for(symbol) {
			_ get 2 / 15 lpad " " _ cat cat push(count)
		} 
		sort(count)
		uncons(count) " " pop(count) ! least and most common
	}
	/\s*(\d+).*?(\d+).*/ => { $2 $1 - }
)

Day 15

Part 1
! vars: 
! 	reg maxcost
!	reg seen:{x},{y} -> cost
!   reg cave:{y} -> input row
!	arr queue:{cost} -> {x},{y}

def(GetRisk) /(\d+),(\d+)/ => {
	"cave:" $2 cat get
	$1 skip 1 take
}
def(QueueVisit) /^(\d+) (\d+,\d+)$/ => {
	get(maxcost) $1 max set(maxcost) clear
	$2
	"queue:" $1 cat push
}
def(Search) /^(\d+) (\d+),(\d+)$/m => {
	"seen:" $2 "," $3 cat cat cat get "" = if 
	{
		! mark territory
		$1 "seen:" $2 "," $3 cat cat cat set
		clear
		
		! format `{cost} {x},{y}`
		! left
		$2 0 >> if {
			$2 1 - "," $3 cat cat copy 
			do(GetRisk) $1 + swap " " swap cat cat 
			do(QueueVisit)
		}
		! up
		$3 0 >> if {
			$2 "," $3 1 - cat cat copy 
			do(GetRisk) $1 + swap " " swap cat cat 
			do(QueueVisit)
		}
		! right
		$2 get(width) 1 - << if {
			$2 1 + "," $3 cat cat copy
			do(GetRisk) $1 + swap " " swap cat cat 
			do(QueueVisit)
		}
		! down
		$3 get(height) 1 - << if {
			$2 "," $3 1 + cat cat copy
			do(GetRisk) $1 + swap " " swap cat cat 
			do(QueueVisit)
		}
	}
}
#(
	fx { 0 set(height) }
	/.+/ => {
		_ "cave:" get(height) cat set 
		inc(height)
		_ len set(width) 
	}
	{ 
		"0,0" "queue:0" push
		"SearchCost:0"
	}
	@/^SearchCost:(\d+)$/ => {
		$1 set(currcost) drop
		get(currcost) get(maxcost) >> not if {
			"queue:" get(currcost) cat for {
				get(currcost) " " _ cat cat
				do(Search)
			}
			clear "SearchCost:" $1 1 +
		}
	}
	{ "seen:" get(width) 1 - "," get(height) 1 - cat cat cat get }
)
Part 2
! vars: 
! 	reg maxcost
!	reg {x},{y} -> cost
!   reg cave:{y} -> input row
!	arr queue:{cost} -> {x},{y}

def(GetRisk) /(\d+),(\d+)/ => {
	"cave:" $2 cat get
	$1 skip 1 take
}
def(QueueVisit) /^(\d+) (\d+,\d+)$/ => {
	get(maxcost) $1 max set(maxcost) clear
	$2
	"queue:" $1 cat push
}
def(Search) /^(\d+) (\d+),(\d+)$/m => {
	$2 "," $3 cat cat get "" = if 
	{
		! mark territory
		$1  $2 "," $3 cat cat set
		clear
		
		! format `{cost} {x},{y}`
		! left
		$2 0 >> if {
			$2 1 - "," $3 cat cat copy 
			do(GetRisk) $1 + swap " " swap cat cat 
			do(QueueVisit)
		}
		! up
		$3 0 >> if {
			$2 "," $3 1 - cat cat copy 
			do(GetRisk) $1 + swap " " swap cat cat 
			do(QueueVisit)
		}
		! right
		$2 get(width) 1 - << if {
			$2 1 + "," $3 cat cat copy
			do(GetRisk) $1 + swap " " swap cat cat 
			do(QueueVisit)
		}
		! down
		$3 get(height) 1 - << if {
			$2 "," $3 1 + cat cat copy
			do(GetRisk) $1 + swap " " swap cat cat 
			do(QueueVisit)
		}
	}
}
def(Tile) ( '9' => "1" /\d/ => { _ 1 + } )
#(
	/(.+)\n*/ => { $1 4 times { copy do(Tile) } "\n" }
	/.*/s => { _ 4 times { copy do(Tile) } "\n" }
	fx { 0 set(height) }
	/.+/ => {
		_ "cave:" get(height) cat set 
		inc(height)
		_ len set(width) 
	}
	{ 
		"0,0" "queue:0" push
		"SearchCost:0"
	}
	@/^SearchCost:(\d+)$/ => {
		$1 set(currcost) drop
		! dump
		get(currcost) get(maxcost) >> not if {
			"queue:" get(currcost) cat for {
				get(currcost) " " _ cat cat
				do(Search)
			}
			"queue:" get(currcost) cat empty
			clear 
			"SearchCost:" $1 1 +
		}
	}
	{ get(width) 1 - "," get(height) 1 - cat cat get }
)

Day 16

Part 1
def(unbin) #(
	fx { 0 set(n) }
	/./ => { get(n) 2 * _ + set(n) }
	{ get(n) }
)
def(DecodeLiteral) #(
	/.(.{4})/ => { $1 }
	do(unbin)
)
#(
	(
		'0' => "0000"
		'1' => "0001"
		'2' => "0010"
		'3' => "0011"
		'4' => "0100"
		'5' => "0101"
		'6' => "0110"
		'7' => "0111"
		'8' => "1000"
		'9' => "1001"
		/a/i=> "1010"
		/b/i=> "1011"
		/c/i=> "1100"
		/d/i=> "1101"
		/e/i=> "1110"
		/f/i=> "1111"
	)
	(
		/(...)100((?:1....)*0....)/ => { 
			"Literal ver:" $1 do(unbin) 
			" val:" $2 do(DecodeLiteral)
			"\n"
		}
		/(...)(...)0(.{15})/ => {
			"Operator ver:" $1 do(unbin) 
			" type:" $2 do(unbin)
			" sub-packet bits:" $3 do(unbin)
			"\n"
		}
		/(...)(...)1(.{11})/ => {
			"Operator ver:" $1 do(unbin) 
			" type:" $2 do(unbin)
			" sub-packets:" $3 do(unbin)
			"\n"
		}
		/0{1,7}$/m => ""
	)
	/ver:(\d+)/ => { get(vertotal) $1 + set(vertotal) clear }
	{ get(vertotal) }
)
Part 2
def(unbin) #(
	fx { 0 set(n) }
	/./ => { get(n) 2 * _ + set(n) }
	{ get(n) }
)
def(DecodeLiteral) #(
	/.(.{4})/ => { $1 }
	do(unbin)
)
def(Op) { 
	set(op) drop
	get(op) 0 = if { + }
	get(op) 1 = if { * }
	get(op) 2 = if { min }
	get(op) 3 = if { max }
	get(op) 5 = if { >> }
	get(op) 6 = if { << }
	get(op) 7 = if { = }
}
#(
	(
		'0' => "0000"
		'1' => "0001"
		'2' => "0010"
		'3' => "0011"
		'4' => "0100"
		'5' => "0101"
		'6' => "0110"
		'7' => "0111"
		'8' => "1000"
		'9' => "1001"
		/a/i=> "1010"
		/b/i=> "1011"
		/c/i=> "1100"
		/d/i=> "1101"
		/e/i=> "1110"
		/f/i=> "1111"
	)
	(
		/(...)100((?:1....)*0....)/ => { 
			"#" $2 do(DecodeLiteral)
			" len:" _ len
			"\n"
		}
		/(...)(...)0(.{15})/ => {
			"op:" $2 do(unbin)
			" sub-packet-bits:" $3 do(unbin)
			" len:" _ len
			"\n"
		}
		/(...)(...)1(.{11})/ => {
			"op:" $2 do(unbin)
			" sub-packets:" $3 do(unbin)
			" len:" _ len
			"\n"
		}
		/0{1,7}$/m => ""
	)
	@(
		! sub-packet-bit match min/max/add/prod (todo?)
		/^op:\d sub-packet-bits:(\d+) len:(\d+)\n#(\d+) len:\1\b/m => {
			"#" $3 " len:" $2 $1 +
		}

		! single sub-packet min/max/add/prod
		/^op:\d sub-packets:1 len:(\d+)\n#(\d+) len:(\d+)/m => {
			"#" $2 " len:" $1 $3 +
		}
		
		! sum with sub-packets
		/^op:(\d) sub-packets:(\d+) len:(\d+)\n#(\d+) len:(\d+)\n#(\d+) len:(\d+)/m => {
			"op:" $1 " sub-packets:" $2 1 - " len:" $3 "\n"
			"#" $4 $6 $1 do(Op) " len:" $5 $7 +
		}

		! sum with sub-packet-bits (todo?)
		/^op:(\d) sub-packet-bits:(\d+) len:(\d+)\n#(\d+) len:(\d+)\n#(\d+) len:(\d+)/m => {
			"op:" $1 " sub-packet-bits:" $2 " len:" $3 "\n"
			"#" $4 $6 $1 do(Op) " len:" $5 $7 +
		}
		
		! terminal literal
		/^#(\d+).*\n*$/ => { $1 }
	)
)

Day 17

Part 1
/x=(\d+)\.\.(\d+), y=(-\d+)\.\.(-\d+)/ => {
	$3 -1 * 1 -
	copy 1 + * 2 /
}
Part 2
! takes "{x},{y} {dx},{dy}"
! returns 0/1 testing for target hit
def(RunSim) #(
	@/(\d+),(-?\d+) (\d+),(-?\d+)/ => {
		$1 get(txmax) >>
		$2 get(tymin) <<
		+ if { 0 } ! passed the target
		{
			$1 get(txmin) 1 - >>
			$2 get(tymax) 1 + <<
			* if { 1 } ! direct hit
			{
				$1 $3 + "," $2 $4 +
				" "
				$3 $3 0 >> - "," $4 1 -
			}
		}
	}
)
#(
	/x=(\d+)\.\.(\d+), y=(-\d+)\.\.(-\d+)/ => fx {
		$1 set(txmin) $2 set(txmax) $3 set(tymin) $4 set(tymax)
	}
	{
		0 set(dx) drop
		get(txmax) times {
			inc(dx)
			get(tymin) set(dy) drop
			get(tymin) -2 * 1 + times {
				"0,0 " get(dx) "," get(dy) cat cat cat
				do(RunSim) if { 1 + }
				inc(dy)
			}
		}
	}
)

Day 17

Part 1
def(MarkDepth) 
( ! big idea `[]` is for outer use, `{}` is deeply nested
	/^/ => 	fx { 0 set(depth) }
	/\[|{/ => { inc(depth) get(depth) 4 >> if { "{" } { "[" } }
	/\]|}/ => { dec(depth) get(depth) 3 >> if { "}" } { "]" } }
)

def(Reduce) 
@#(
	/.+/ => do(MarkDepth)
	1(
		! explode
		/(\d+)?(\D*){(\d+),(\d+)}(\D*)(\d+)?/ => {
			$1 len if { $1 $3 + }
			$2 0 $5
			$6 len if { $6 $4 + }
		}
		! split
		/\d\d+/ => { 
			"[" _ 2 / floor "," _ 1 + 2 / floor "]"
		}
	)
)

#(
	@1( 
		/(.+)\n(.+)/ => { 
			"[" $1 "," $2 "]" 
			4 times { cat }
			do(Reduce)
		} 
	)

	! magnitude
	@/\[(\d+),(\d+)\]/ => { 3 $1 * 2 $2 * + }
)
Part 2
def(MarkDepth) 
( ! big idea `[]` is for outer use, `{}` is deeply nested
	/^/ => 	fx { 0 set(depth) }
	/\[|{/ => { inc(depth) get(depth) 4 >> if { "{" } { "[" } }
	/\]|}/ => { dec(depth) get(depth) 3 >> if { "}" } { "]" } }
)

def(Reduce) 
@#(
	/.+/ => do(MarkDepth)
	1(
		! explode
		/(\d+)?(\D*){(\d+),(\d+)}(\D*)(\d+)?/ => {
			$1 len if { $1 $3 + }
			$2 0 $5
			$6 len if { $6 $4 + }
		}
		! split
		/\d\d+/ => { 
			"[" _ 2 / floor "," _ 1 + 2 / floor "]"
		}
	)
)

def(Magnitude) @/\[(\d+),(\d+)\]/ => { 3 $1 * 2 $2 * + }

#(
	/.+/ => { _ push(input) }
	{
		for(input) {
			_ set(a) drop
			for(input) {
				_ set(b) drop
				get(a) get(b) = not if {
					"[" get(a) "," get(b) "]"
					4 times { cat }
					do(Reduce)
					do(Magnitude)
					get(maxsum) max set(maxsum)
				}
			}
		}
		clear get(maxsum)
	}
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment