You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
input=Kino.Input.textarea("Please, paste your input here:")
defmoduleDay20Shareddodefparse(input)domodules=input|>Kino.Input.read()|>String.split("\n")|>Enum.map(fnmodule_raw->[type_raw,name,outs_raw]=Regex.run(~r/([%&]*)(\w+) -> ([\w, ]+)$/,module_raw,capture: :all_but_first)outs=String.split(outs_raw,~r/[,\s+]/,trim: true)config=casetype_rawdo""->%{type: :cast,outs: outs}"%"->%{type: :flip,outs: outs,state: :off}"&"->%{type: :conj,outs: outs,state: %{}}end{name,config}end){machinezy(modules),graphy(modules)}end# Sets inputs and initial state for the conjuction modules, but leaves the rest of# configuration the same as parseddefpmachinezy(modules)domodules|>Enum.map(fn{name,%{type: :conj}=config}->inputs=modules|>Enum.filter(fn{_,%{outs: outs}}->Enum.member?(outs,name)end)|>Enum.map(fn{out_name,_}->out_nameend)state=inputs|>Enum.map(fninp->{inp,:low}end)|>Map.new(){name,%{config|state: state}}otherwise->otherwiseend)|>Map.new()end# Generates a graph with the vertices and edges for the given machine (not sure if needed)defpgraphy(modules)domodule_names=Enum.map(modules,&elem(&1,0))graph=Graph.new()|>Graph.add_vertices(module_names)Enum.reduce(modules,graph,fn{name,%{outs: outs}},graph->Enum.reduce(outs,graph,fnout,graph->Graph.add_edge(graph,name,out)end)end)endendDay20Shared.parse(input)
Part 1
defmoduleDay20Part1do@init_pulses[{"button",:low,"broadcaster"}]@init_counts{0,0}@steps1000defsolve({machine,_graph})do1..@steps|>Enum.reduce({machine,@init_counts},fn_step,{machine,counts}->process(@init_pulses,machine,counts)end)# |> IO.inspect()|>then(fn{_machine,{low_n,high_n}}->low_n*high_nend)enddefpprocess([],machine,counts),do: {machine,counts}defpprocess([pulse|queue],machine,{low_n,high_n})do{new_machine,new_pulses}=update_machine(pulse,machine)# IO.inspect(pulse, label: "pulse")new_counts=ifelem(pulse,1)==:lowdo{low_n+1,high_n}else{low_n,high_n+1}endprocess(queue++new_pulses,new_machine,new_counts)enddefpupdate_machine({from_module,pulse_type,to_module},machine)docaseMap.get(machine,to_module)do%{type: :cast}=module->next_pulses=Enum.map(module[:outs],fnout->{to_module,pulse_type,out}end){machine,next_pulses}%{type: :flip}=module-># Flip-flop modules (prefix %) are either on or off; they are initially off.# If a flip-flop module receives a high pulse, it is ignored and nothing happens.# However, if a flip-flop module receives a low pulse, it flips between on and off.# If it was off, it turns on and sends a high pulse.# If it was on, it turns off and sends a low pulse.ifpulse_type==:highdo{machine,[]}elsemodule=flip(module)next_pulses=Enum.map(module[:outs],fnout->ifmodule[:state]==:ondo{to_module,:high,out}else{to_module,:low,out}endend){%{machine|to_module=>module},next_pulses}end%{type: :conj,state: state}=module-># Conjunction modules (prefix &) remember the type of the most recent pulse received# from each of their connected input modules; they initially default to remembering# a low pulse for each input.# When a pulse is received, the conjunction module first updates its memory for# that input. Then, if it remembers high pulses for all inputs, it sends a low pulse;# otherwise, it sends a high pulse.state=%{state|from_module=>pulse_type}module=%{module|state: state}signal=invertor_will_send(state)next_pulses=Enum.map(module[:outs],fnout->{to_module,signal,out}end){%{machine|to_module=>module},next_pulses}nil->{machine,[]}endenddefpflip(%{state: :off}=module),do: %{module|state: :on}defpflip(%{state: :on}=module),do: %{module|state: :off}defpinvertor_will_send(state)doifEnum.all?(state,fn{_,type}->type==:highend)do:lowelse:highendendendinput|>Day20Shared.parse()|>Day20Part1.solve()# 743871576 is the right answer
Part 2
defmoduleDay20Part2do# See https://elixirforum.com/t/advent-of-code-2023-day-20/60474 for solution ideas# Maybe use https://csacademy.com/app/graph_editor/ to find cycles in the input# Kostya's result: 243_221_023_462_303end# input# |> Day20Shared.parse()# |> Day20Part2.solve()