USING: accessors eval grouping io.encodings.utf8 io.files kernel math math.functions math.parser math.statistics multiline namespaces peg.ebnf prettyprint sequences sequences.extras splitting ; IN: aoc.11 : input ( -- lines ) "~/factor/aoc/11/11.in" utf8 file-lines ; SYMBOL: monkeys TUPLE: monkey items op test inspections ; : parse-op ( str -- quot ) split-words reverse join-words "old" "dup" replace "[ " " ]" surround "USING: math kernel ; " prepend ( -- x ) eval ; EBNF: parse-monkey [=[ line-rest = (!(" ") .)+ num = [0-9]+ => [[ dec> ]] items = " Starting items: "~ (num ", "*~)+ op = " Operation: new = old "~ line-rest => [[ parse-op ]] test = " Test: divisible by "~ num " If true: throw to monkey "~ num " If false: throw to monkey "~ num monkey = line-rest~ items op test => [[ first3 0 monkey boa ]] ]=] : I ( -- ) input { "" } split [ concat parse-monkey ] map monkeys set ; SYMBOL: manage : inspect ( item monkey -- item' ) dup inspections>> 1 + >>inspections op>> call( x -- x ) manage get call( x -- x ) ; : throw ( item monkey -- ) [ inspect dup ] keep test>> first3 [ divisor? ] 2dip ? monkeys get nth items>> push ; : turn ( monkey -- ) [ items>> ] [ V{ } clone >>items ] bi '[ _ throw ] each ; : round ( -- ) monkeys get [ turn ] each ; : (part) ( n quot -- n ) manage set [ round ] times monkeys get [ inspections>> ] map { 0 1 } kth-largests product ; : part1 ( -- n ) I 20 [ 3 / floor ] (part) ; : part2 ( -- n ) I 10000 monkeys get [ test>> first ] map-product '[ _ mod ] (part) ; : solve ( -- ) part1 . part2 . ;