You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
2.5 KiB
72 lines
2.5 KiB
-module(day21).
|
|
|
|
-export([solve/1]).
|
|
|
|
solve(InputData) ->
|
|
Monkeys = parse_input(InputData),
|
|
{eval(<<"root">>, Monkeys), undo(human_path(<<"root">>, p2fix(Monkeys), []))}.
|
|
|
|
% turn the root into a big equal sign
|
|
|
|
p2fix(#{<<"root">> := {_Op, Left, Right}} = Monkeys) ->
|
|
Monkeys#{<<"root">> := {$-, Left, Right}}.
|
|
|
|
parse_input(Input) -> parse_input(Input, #{}).
|
|
|
|
parse_input(<<>>, Acc) -> Acc;
|
|
parse_input(<<$\n, Rest/binary>>, Acc) -> parse_input(Rest, Acc);
|
|
parse_input(<<Name:4/bytes, $:, $\s, Left:4/bytes, $\s, Op, $\s, Right:4/bytes, Rest/binary>>, Monkeys) ->
|
|
parse_input(Rest, Monkeys#{Name => {Op, Left, Right}});
|
|
parse_input(<<Name:4/bytes, $:, $\s, RestIn/binary>>, Monkeys) ->
|
|
{Value, RestOut} = parse_int(RestIn),
|
|
parse_input(RestOut, Monkeys#{Name => Value}).
|
|
|
|
eval(Name, Monkeys) ->
|
|
#{Name := Node} = Monkeys,
|
|
case Node of
|
|
Value when is_integer(Value) -> Value;
|
|
{Op, Left, Right} ->
|
|
LeftValue = eval(Left, Monkeys),
|
|
RightValue = eval(Right, Monkeys),
|
|
case Op of
|
|
$+ -> LeftValue + RightValue;
|
|
$- -> LeftValue - RightValue;
|
|
$/ -> LeftValue div RightValue;
|
|
$* -> LeftValue * RightValue
|
|
end
|
|
end.
|
|
|
|
undo(HumanPath) -> lists:foldl(fun do_undo/2, 0, HumanPath).
|
|
|
|
do_undo({_Side, $+, Value}, Target) -> Target - Value;
|
|
do_undo({_Side, $*, Value}, Target) -> Target div Value;
|
|
do_undo({left, $/, Value}, Target) -> Target * Value;
|
|
do_undo({right, $/, Value}, Target) -> Value div Target;
|
|
do_undo({left, $-, Value}, Target) -> Target + Value;
|
|
do_undo({right, $-, Value}, Target) -> Value - Target.
|
|
|
|
|
|
human_path(<<"humn">>, _State, Path) -> lists:reverse(Path);
|
|
human_path(Name, Monkeys, Path) ->
|
|
#{Name := Node} = Monkeys,
|
|
case Node of
|
|
Value when is_integer(Value) ->
|
|
not_found;
|
|
{Op, Left, Right} ->
|
|
case human_path(Left, Monkeys, [{left, Op, eval(Right, Monkeys)} | Path]) of
|
|
not_found -> human_path(Right, Monkeys, [{right, Op, eval(Left, Monkeys)} | Path]);
|
|
Found -> Found
|
|
end
|
|
end.
|
|
|
|
|
|
%% Parse Integer standard code
|
|
parse_int(<<$-, Rest/binary>>) ->
|
|
{AbsoluteValue, Binary} = parse_int0(Rest, 0),
|
|
{-1 * AbsoluteValue, Binary};
|
|
parse_int(Binary) ->
|
|
parse_int0(Binary, 0).
|
|
|
|
parse_int0(<<Digit, Rest/binary>>, Acc) when Digit >= $0 andalso Digit =< $9 ->
|
|
parse_int0(Rest, Acc*10 + Digit - $0);
|
|
parse_int0(Binary, Acc) when is_binary(Binary) -> {Acc, Binary}.
|