96 lines
2.4 KiB
Mathematica
96 lines
2.4 KiB
Mathematica
|
:- module day17.
|
||
|
:- interface.
|
||
|
:- import_module basics.
|
||
|
|
||
|
:- pred run(part::in, lines::in, answer::out) is cc_multi.
|
||
|
|
||
|
:- implementation.
|
||
|
:- import_module char.
|
||
|
:- import_module int.
|
||
|
:- import_module string.
|
||
|
:- import_module list.
|
||
|
:- import_module array.
|
||
|
|
||
|
:- type wind ---> l; r.
|
||
|
:- type cell ---> empty; full.
|
||
|
|
||
|
:- type row == list(cell).
|
||
|
:- type board == list(row).
|
||
|
|
||
|
:- pred empty(row::in) is semidet.
|
||
|
empty(Row) :- all [X] member(X, Row) => X = empty.
|
||
|
|
||
|
:- func empty = row.
|
||
|
empty = replicate(7, empty).
|
||
|
|
||
|
:- func trim_top0(board) = board.
|
||
|
trim_top0([]) = [].
|
||
|
trim_top0([R | Rs]) = Out :-
|
||
|
if empty(R) then Out = trim_top0(Rs)
|
||
|
else Out = [R | Rs].
|
||
|
|
||
|
:- func trim_top(board) = board.
|
||
|
trim_top(B) = [empty, empty, empty | trim_top0(B)].
|
||
|
|
||
|
|
||
|
:- type piece == list(row).
|
||
|
|
||
|
:- func make_piece(list(string)) = piece.
|
||
|
make_piece(Strs) = Piece :-
|
||
|
if map(row, Strs, Rows) then Piece = Rows
|
||
|
else die("piece: invalid input").
|
||
|
|
||
|
:- func pieces = array(piece).
|
||
|
pieces = array(['🬋🬋', '🬫🬃', '🬭▌', '▌', '🬹']).
|
||
|
|
||
|
'🬋🬋' = make_piece(["..####."]).
|
||
|
'🬫🬃' = make_piece(["...#...", "..###..", "...#..."]).
|
||
|
'🬭▌' = make_piece(["....#..", "....#..", "..###.."]).
|
||
|
'▌' = make_piece(["..#....", "..#....", "..#....", "..#...."]).
|
||
|
'🬹' = make_piece(["..##...", "..##..."]).
|
||
|
|
||
|
:- func piece(int) = piece.
|
||
|
piece(I) = pieces^elem(I `mod` 5).
|
||
|
|
||
|
|
||
|
:- pred left_row(row::in, row::out) is semidet.
|
||
|
left_row([], []).
|
||
|
left_row([empty | Rest], Rest ++ [empty]).
|
||
|
|
||
|
:- pred left_piece(piece::in, piece::out) is semidet.
|
||
|
left_piece(P, Q) :- map(left_row, P, Q).
|
||
|
|
||
|
:- pred right_row(row::in, row::out) is semidet.
|
||
|
right_row(P, Q) :-
|
||
|
if P = [] then Q = []
|
||
|
else remove_suffix(P, [empty], P0), Q = [empty | P0].
|
||
|
|
||
|
:- pred right_piece(piece::in, piece::out) is semidet.
|
||
|
right_piece(P, Q) :- map(right_row, P, Q).
|
||
|
|
||
|
:- func row_to_string(row) = string.
|
||
|
row_to_string(Row) =
|
||
|
from_char_list(map(func(X) = ite(unify(X, empty), '·', '█'), Row)).
|
||
|
|
||
|
:- func piece_to_lines(piece) = lines.
|
||
|
piece_to_lines(P) = map(row_to_string, P).
|
||
|
|
||
|
|
||
|
:- pred cell(char::in, cell::out) is semidet.
|
||
|
cell('.', empty).
|
||
|
cell('#', full).
|
||
|
|
||
|
:- pred row(string::in, row::out) is semidet.
|
||
|
row(Str, Out) :-
|
||
|
length(Str) = 7,
|
||
|
map(cell, to_char_list(Str), Out).
|
||
|
|
||
|
:- pred parse(lines::in, array(wind)::out) is det.
|
||
|
parse(Lines, array(List)) :-
|
||
|
List = map(func(C) = ite(unify(C, '<'), l, r),
|
||
|
condense(map(to_char_list, Lines))).
|
||
|
|
||
|
|
||
|
run(_, _, Out) :-
|
||
|
Out = lines(condense(map(piece_to_lines, map(piece, [1,3,1,2])))).
|