% 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).