aoc2022/day2.m

101 lines
2.7 KiB
Mathematica

% this could be probably like ¼ the length
% but i wanted to write grammars and bidirectional predicates ok
% leave me alone
:- module day2.
:- interface.
:- import_module basics.
:- import_module list.
:- pred run(part::in, list(string)::in, answer::out) is cc_multi.
:- implementation.
:- import_module int.
:- import_module char.
:- import_module string.
:- import_module pair.
:- type move ---> rock; paper; scissors.
:- type moves == pair(move).
:- type result ---> me; you; draw.
:- type move_res == pair(move, result).
:- type parser(T) == (pred(T, chars, chars)).
:- mode parser(I) == (pred(out(I), in, out) is semidet).
:- mode parser == parser(ground).
:- pred hand(move::out, chars::in, chars::out) is semidet.
hand(rock) --> ['A']; ['X'].
hand(paper) --> ['B']; ['Y'].
hand(scissors) --> ['C']; ['Z'].
:- pred result(result::out, chars::in, chars::out) is semidet.
result(you) --> ['X'].
result(draw) --> ['Y'].
result(me) --> ['Z'].
:- pred two(parser(T)::parser, parser(U)::parser,
T::out, U::out, chars::in, chars::out) is semidet.
two(P, Q, A, B) --> P(A), [' '], Q(B).
:- pred line1(moves::out, chars::in, chars::out) is semidet.
line1(A - B) --> two(hand, hand, A, B).
:- pred line2(move_res::out, chars::in, chars::out) is semidet.
line2(A - B) --> two(hand, result, A, B).
:- pred parse_line(parser(T)::parser, string::in, T::out) is semidet.
parse_line(P, Str, X) :- P(X, to_char_list(Str), []).
:- pred to_int(move, int).
:- mode to_int(in, out) is det.
:- mode to_int(out, in) is semidet.
to_int(rock, 1).
to_int(paper, 2).
to_int(scissors, 3).
:- func to_int(move) = int.
to_int(A) = B :- to_int(A, B).
:- pred win(move, move, result).
:- mode win(in, in, out) is det.
:- mode win(in, out, in) is det.
% you me
win(rock, rock, draw).
win(rock, paper, me).
win(rock, scissors, you).
win(paper, rock, you).
win(paper, paper, draw).
win(paper, scissors, me).
win(scissors, rock, me).
win(scissors, paper, you).
win(scissors, scissors, draw).
:- func win_score(result) = int.
win_score(me) = 6.
win_score(you) = 0.
win_score(draw) = 3.
:- func score1(move, move) = int.
score1(You, Me) = to_int(Me) + win_score(Res) :- win(You, Me, Res).
:- func score2(move, result) = int.
score2(You, Res) = to_int(Me) + win_score(Res) :- win(You, Me, Res).
:- pred run(list(string)::in, parser(pair(T, U))::parser,
(func(T, U) = int)::in, int::out) is det.
run(Lines, P, F, Out) :-
if map(parse_line(P), Lines, Res) then
Out = sum(map(func(X - Y) = F(X, Y), Res))
else
die("invalid input"). % lol
:- pragma no_determinism_warning(run/3).
run(one, Lines, int(Out)) :- run(Lines, line1, score1, Out).
run(two, Lines, int(Out)) :- run(Lines, line2, score2, Out).