:- 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])))).