I spent way too much time at the beginning trying to be clever about parsing the input. The Regex named captures work great, but I also tried to dynamically create the functions using metaprogramming. Eventually I gave up on that and hard-coded the function combinations.
After constructing three neat layers of reduces for the rounds, monkeys, and items, I realized that the state needed to be modified within the round so that monkeys could throw to other monkeys coming later in the round. This is a prime example where a functional paradigm is actually less intuitive. I saw that one person on the Elixir forum used GenServers, which is a perfect way of thinking about state a little more procedurally. I opted for smushing the round and monkey reduces into a single reduce so that they could share the same accumulator.
Admittedly, I did not figure out the trick to the second part on my own. My brain was headed in the correct direction, but I didn't really want to spend my time figuring out a math problem. (Usually, I love doing math, but my primary goal has been to keep up with these Advent of Code problems.)
defmoduleDay11douseAOCdefnew("old","+","old"),do:fnold->old+oldenddefnew(left,"+","old"),do:fnold->String.to_integer(left)+oldenddefnew("old","+",right),do:fnold->old+String.to_integer(right)enddefnew("old","*","old"),do:fnold->old*oldenddefnew(left,"*","old"),do:fnold->String.to_integer(left)*oldenddefnew("old","*",right),do:fnold->old*String.to_integer(right)enddefparse_note(note)doinfo=Regex.named_captures(~r/Monkey (?<monkey>\d):
Starting items: (?<items>.*)
Operation: new = (?<left>.*) (?<op>.*) (?<right>.*)
Test: divisible by (?<test>.*)
If true: throw to monkey (?<throw_true>.*)
If false: throw to monkey (?<throw_false>.*)/,note){String.to_integer(info["monkey"]),%{count:0,items:info["items"]|>String.split(", ")|>Enum.map(&String.to_integer/1),operation:new(info["left"],info["op"],info["right"]),test:fntest->ifrem(test,info["test"]|>String.to_integer)==0doinfo["throw_true"]|>String.to_integer()elseinfo["throw_false"]|>String.to_integer()endend}}enddefnotes()doinput(11)|>String.split("\n\n",trim:true)|>Map.new(&parse_note/1)enddefpart1donotes=notes()Enum.reduce(1..(20*map_size(notes)),notes,fni,monkeys->current_monkey=rem(i-1,map_size(notes))%{items:items,operation:operation,test:test}=monkeys[current_monkey]Enum.reduce(items,monkeys,fnitem,state->new_worry_level=operation.(item)|>div(3)state|>update_in([test.(new_worry_level),:items],fnitems->items++[new_worry_level]end)|>update_in([current_monkey,:items],fn[_|items]->itemsend)|>update_in([current_monkey,:count],fncount->count+1end)end)end)|>Enum.sort_by(fn{_,%{count:count}}->countend,:desc)|>Enum.take(2)|>Enum.reduce(fn{_,%{count:first_count}},{_,%{count:second_count}}->first_count*second_countend)enddefpart2donotes=notes()Enum.reduce(1..(10_000*map_size(notes)),notes,fni,monkeys->current_monkey=rem(i-1,map_size(notes))%{items:items,operation:operation,test:test}=monkeys[current_monkey]Enum.reduce(items,monkeys,fnitem,state->new_worry_level=operation.(item)|>rem(9699690)state|>update_in([test.(new_worry_level),:items],fnitems->items++[new_worry_level]end)|>update_in([current_monkey,:items],fn[_|items]->itemsend)|>update_in([current_monkey,:count],fncount->count+1end)end)end)|>Enum.sort_by(fn{_,%{count:count}}->countend,:desc)|>Enum.take(2)|>Enum.reduce(fn{_,%{count:first_count}},{_,%{count:second_count}}->first_count*second_countend)endend
Top comments (0)
Subscribe
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)