Compare commits
No commits in common. "bf96f6d15fa7f243221d59f43879945407a66ee8" and "442b930c417e60c7c32665ee2db7861072c35726" have entirely different histories.
bf96f6d15f
...
442b930c41
2
Makefile
2
Makefile
|
@ -1,6 +1,6 @@
|
|||
MMCFLAGS := --infer-all --warn-unused-imports \
|
||||
--output-compile-error-lines 1000 \
|
||||
-s asm_fast.gc.stseg
|
||||
-s asm_fast.gc.debug.stseg
|
||||
|
||||
all: aoc
|
||||
|
||||
|
|
|
@ -1,275 +0,0 @@
|
|||
:- module day12.
|
||||
:- interface.
|
||||
:- import_module basics.
|
||||
|
||||
:- pred run(part::in, lines::in, answer::out) is cc_multi.
|
||||
|
||||
:- implementation.
|
||||
:- import_module int.
|
||||
:- import_module char.
|
||||
:- import_module string.
|
||||
:- import_module list.
|
||||
:- import_module array2d.
|
||||
:- import_module map.
|
||||
:- import_module psqueue.
|
||||
:- import_module solutions.
|
||||
|
||||
:- type point == {int, int}.
|
||||
|
||||
:- type grid ---> g(array :: array2d(char), start :: point, end :: point).
|
||||
|
||||
:- pred grid(lines::in, grid::out) is nondet.
|
||||
grid(Lines, g(Arr, {SX, SY}, {EX, EY})) :-
|
||||
Arr = from_lists(map(to_char_list, Lines)),
|
||||
find(Arr, 'S', SX, SY),
|
||||
find(Arr, 'E', EX, EY).
|
||||
|
||||
:- pred find(array2d(T)::in, T::in, int::out, int::out) is nondet.
|
||||
find(Arr, X, I, J) :- index_arr(Arr, I, J), Arr^elem(I, J) = X.
|
||||
|
||||
:- func grid^elem(point) = char.
|
||||
G^elem({X, Y}) = G^array^elem(X, Y).
|
||||
|
||||
:- func height(char) = int.
|
||||
height(C) = I :-
|
||||
if C = 'S' then I = 0
|
||||
else if C = 'E' then I = 25
|
||||
else I = to_int(C) - to_int('a').
|
||||
|
||||
:- func height(grid, point) = int.
|
||||
height(G, P) = height(G^elem(P)).
|
||||
|
||||
:- pred adj_point(point::in, point::out) is multi.
|
||||
adj_point({X, Y}, {X+1, Y}).
|
||||
adj_point({X, Y}, {X-1, Y}).
|
||||
adj_point({X, Y}, {X, Y+1}).
|
||||
adj_point({X, Y}, {X, Y-1}).
|
||||
|
||||
:- pred adj(grid::in, point::in, point::out) is nondet.
|
||||
adj(G, P, Q) :-
|
||||
adj_point(P, Q), in_bounds(G, Q),
|
||||
height(G, Q) =< height(G, P) + 1.
|
||||
|
||||
:- pred in_bounds(grid::in, point::in) is semidet.
|
||||
in_bounds(G, {X, Y}) :- in_bounds(G^array, X, Y).
|
||||
|
||||
|
||||
:- pred bounds(grid::in, int::out, int::out) is det.
|
||||
bounds(G, W, H) :- bounds(G^array, W, H).
|
||||
|
||||
:- pred index(grid::in, point::out) is nondet.
|
||||
index(Grid, {I, J}) :- index_arr(Grid^array, I, J).
|
||||
|
||||
:- pred index_arr(array2d(T)::in, int::out, int::out) is nondet.
|
||||
index_arr(Arr, I, J) :-
|
||||
bounds(Arr, W, H),
|
||||
nondet_int_in_range(0, W-1, I),
|
||||
nondet_int_in_range(0, H-1, J).
|
||||
|
||||
|
||||
:- type path == list(point).
|
||||
:- type distance ---> i(int); inf.
|
||||
:- type pm == map(point, point).
|
||||
:- type nq == psqueue(distance, point).
|
||||
|
||||
:- pred (distance::in) < (distance::in) is semidet.
|
||||
i(_) < inf.
|
||||
i(M) < i(N) :- M < N.
|
||||
|
||||
:- pred min(distance::in, distance::in, distance::out) is det.
|
||||
min(A, B, ite(A < B, A, B)).
|
||||
|
||||
:- func init_dist(point, point) = distance.
|
||||
init_dist(Start, P) = ite(unify(P, Start), i(0), inf).
|
||||
|
||||
:- pred init_queue(grid::in, point::in, nq::out) is det.
|
||||
init_queue(G, Start, Q) :-
|
||||
Points = solutions(index(G)),
|
||||
foldl(pred(P::in, !.Q::in, !:Q::out) is det :-
|
||||
det_insert(init_dist(Start, P), P, !Q),
|
||||
Points, psqueue.init, Q).
|
||||
|
||||
:- pred init_queue(grid::in, nq::out) is det.
|
||||
init_queue(G, Q) :- init_queue(G, G^start, Q).
|
||||
|
||||
:- pred incr(distance::in, distance::out) is det.
|
||||
incr(inf, inf).
|
||||
incr(i(N), i(N+1)).
|
||||
|
||||
:- pred neighbour(grid::in, nq::in, point::in, {point,distance}::out) is nondet.
|
||||
neighbour(G, Q, P, {N, D}) :- adj(G, P, N), search(Q, N, D).
|
||||
|
||||
:- pred update_distance(point::in, distance::in, {point,distance}::in,
|
||||
pm::in, pm::out, nq::in, nq::out) is det.
|
||||
update_distance(Prev, DNew, {P, DOld}, !M, !Q) :-
|
||||
if DNew < DOld then
|
||||
(if adjust(func(_) = DNew, P, !Q) then true else die("point disappeared")),
|
||||
set(P, Prev, !M)
|
||||
else true.
|
||||
|
||||
:- pred path0(grid::in, point::in, pm::in, pm::out, nq::in, nq::out) is det.
|
||||
path0(G, End, !M, !Q) :-
|
||||
det_remove_least(Distance, Point, !Q),
|
||||
(if Point = End then true else
|
||||
solutions(neighbour(G, !.Q, Point), Neighbours),
|
||||
incr(Distance, NeighDistance), % 🐴↔🐴
|
||||
foldl2(update_distance(Point, NeighDistance), Neighbours, !M, !Q),
|
||||
path0(G, End, !M, !Q)).
|
||||
|
||||
:- func get_path_len(grid, pm, point, point) = distance.
|
||||
get_path_len(G, M, Start, Point) = Out :-
|
||||
if Point = Start then
|
||||
Out = i(0)
|
||||
else if search(M, Point, Prev) then
|
||||
incr(get_path_len(G, M, Start, Prev), Out)
|
||||
else
|
||||
Out = inf.
|
||||
|
||||
|
||||
:- pred path_len(grid::in, point::in, point::in, distance::out) is det.
|
||||
path_len(Grid, Start, End, Len) :-
|
||||
init_queue(Grid, Start, Queue),
|
||||
path0(Grid, End, init, Prevs, Queue, _),
|
||||
Len = get_path_len(Grid, Prevs, Start, End).
|
||||
|
||||
:- pred path_len(grid::in, distance::out) is det.
|
||||
path_len(Grid, Len) :- path_len(Grid, Grid^start, Grid^end, Len).
|
||||
|
||||
|
||||
:- pred start(grid::in, point::out) is nondet.
|
||||
start(Grid, P) :- index(Grid, P), height(Grid, P) = 0.
|
||||
|
||||
:- pred shortest(grid::in, list(point)::in, point::in, distance::out) is det.
|
||||
shortest(Grid, Starts, End, Distance) :-
|
||||
floyd_warshall(Grid, AllDistances),
|
||||
map(pred(P::in, D::out) is det :- fw_distance(Grid, AllDistances, P, End) = D,
|
||||
Starts, Distances),
|
||||
foldl(min, Distances, inf, Distance).
|
||||
|
||||
:- func distance(distance) = answer.
|
||||
distance(inf) = string("∞").
|
||||
distance(i(N)) = int(N).
|
||||
|
||||
|
||||
:- type dm == map({point, point}, int).
|
||||
|
||||
:- func fw_distance(grid, fw, point, point) = distance.
|
||||
fw_distance(Grid, Array, From, To) = Out :-
|
||||
Val = Array^elem(point_to_int(Grid, From), point_to_int(Grid, To)),
|
||||
(if Val < 0 then Out = inf else Out = i(Val)).
|
||||
|
||||
:- pred edge(grid::in, {point,point}::out) is nondet.
|
||||
edge(Grid, {From, To}) :- index(Grid, From), adj(Grid, From, To).
|
||||
|
||||
|
||||
:- func point_to_int(grid, point) = int.
|
||||
point_to_int(Grid, {X, Y}) = Y*W + X :-
|
||||
bounds(Grid, W, _).
|
||||
|
||||
:- func int_to_point(grid, int) = point.
|
||||
int_to_point(Grid, I) = {I `mod` W, I `div` W} :-
|
||||
bounds(Grid, W, _).
|
||||
|
||||
:- func max_int_bound(grid) = int.
|
||||
max_int_bound(Grid) = W * H :-
|
||||
bounds(Grid, W, H).
|
||||
|
||||
:- func edge_to_ints(grid, {point, point}) = {int, int}.
|
||||
edge_to_ints(Grid, {From, To}) =
|
||||
{point_to_int(Grid, From), point_to_int(Grid, To)}.
|
||||
|
||||
|
||||
:- pred loop(pred(int, T, T), int, T, T).
|
||||
:- mode loop(pred(in, in, out) is det, in, in, out) is det.
|
||||
:- mode loop(pred(in, di, uo) is det, in, di, uo) is det.
|
||||
:- mode loop(pred(in, array2d_di, array2d_uo) is det,
|
||||
in, array2d_di, array2d_uo) is det.
|
||||
loop(P, I, !Acc) :- loop(P, 0, I, !Acc).
|
||||
|
||||
:- pred loop(pred(int, T, T), int, int, T, T).
|
||||
:- mode loop(pred(in, in, out) is det, in, in, in, out) is det.
|
||||
:- mode loop(pred(in, di, uo) is det, in, in, di, uo) is det.
|
||||
:- mode loop(pred(in, array2d_di, array2d_uo) is det,
|
||||
in, in, array2d_di, array2d_uo) is det.
|
||||
loop(P, Lo, Hi, !Acc) :-
|
||||
if Lo >= Hi then true else
|
||||
P(Lo, !Acc),
|
||||
loop(P, Lo + 1, Hi, !Acc).
|
||||
|
||||
:- type fw == array2d(int).
|
||||
|
||||
:- pred add_edges(list({int,int})::in, fw::array2d_di, fw::array2d_uo) is det.
|
||||
add_edges([], !Fw).
|
||||
add_edges([{From, To} | Es], !Fw) :-
|
||||
!Fw^elem(From, To) := 1,
|
||||
add_edges(Es, !Fw).
|
||||
|
||||
:- pred floyd_warshall(grid::in, fw::array2d_uo) is det.
|
||||
floyd_warshall(Grid, !:Fw) :-
|
||||
VCount = max_int_bound(Grid),
|
||||
Edges = map(edge_to_ints(Grid), solutions(edge(Grid))),
|
||||
|
||||
!:Fw = array2d.init(VCount, VCount, -1),
|
||||
|
||||
add_edges(Edges, !Fw),
|
||||
|
||||
loop(pred(V::in, !.Fw::array2d_di, !:Fw::array2d_uo) is det :-
|
||||
!Fw^elem(V, V) := 0,
|
||||
VCount, !Fw),
|
||||
|
||||
loop(pred(K::in, !.Fw::array2d_di, !:Fw::array2d_uo) is det :-
|
||||
loop(pred(I::in, !.Fw::array2d_di, !:Fw::array2d_uo) is det :-
|
||||
loop(pred(J::in, !.Fw::array2d_di, !:Fw::array2d_uo) is det :-
|
||||
(if
|
||||
IK = unsafe_lookup(!.Fw, I, K), IK > 0,
|
||||
KJ = unsafe_lookup(!.Fw, K, J), KJ > 0,
|
||||
IJ = unsafe_lookup(!.Fw, I, J), not (IJ > 0, IJ =< IK + KJ)
|
||||
then
|
||||
unsafe_set(I, J, IK + KJ, !Fw)
|
||||
else true),
|
||||
VCount, !Fw),
|
||||
VCount, !Fw),
|
||||
VCount, !Fw).
|
||||
|
||||
run(one, Lines, Out) :-
|
||||
if
|
||||
grid(Lines, Grid),
|
||||
path_len(Grid, Len)
|
||||
then
|
||||
Out = distance(Len)
|
||||
else
|
||||
die("bad input").
|
||||
run(two, Lines, Out) :-
|
||||
% IOU one floyd warshall
|
||||
if grid(Lines, Grid) then
|
||||
solutions(start(Grid), Starts),
|
||||
shortest(Grid, Starts, Grid^end, Distance),
|
||||
Out = distance(Distance)
|
||||
else
|
||||
die("bad input").
|
||||
|
||||
|
||||
|
||||
/* omg could u imagine if this had worked tho
|
||||
|
||||
:- pragma memo(path/5, [fast_loose]).
|
||||
:- pred path(grid::in, point::in, point::in, path::in, int::out)
|
||||
is nondet.
|
||||
path(G, P, P, _, 0).
|
||||
path(G, P, Q, Seen, Len + 1) :-
|
||||
adj(G, P, P1),
|
||||
not member(P1, Seen),
|
||||
path(G, P1, Q, [P|Seen], Len).
|
||||
|
||||
:- pred path(grid::in, point::in, point::in, int::out) is nondet.
|
||||
path(G, P, Q, Len) :- path(G, P, Q, [], Len).
|
||||
|
||||
:- import_module solutions.
|
||||
|
||||
run(one, Lines, Out) :-
|
||||
if grid(Lines, G) then
|
||||
solutions(path(G, G^start, G^end), Paths),
|
||||
Out = int(det_head(Paths))
|
||||
else
|
||||
die("bad input").
|
||||
*/
|
|
@ -0,0 +1,230 @@
|
|||
:- module day12.
|
||||
:- interface.
|
||||
:- import_module basics.
|
||||
|
||||
:- pred run(part::in, lines::in, answer::out) is cc_multi.
|
||||
|
||||
:- implementation.
|
||||
:- import_module int.
|
||||
:- import_module char.
|
||||
:- import_module string.
|
||||
:- import_module list.
|
||||
:- import_module array2d.
|
||||
|
||||
:- type point == {int, int}.
|
||||
|
||||
:- type grid ---> g(array :: array2d(char), start :: point, end :: point).
|
||||
|
||||
:- pred grid(lines::in, grid::out) is semidet.
|
||||
grid(Lines, g(Arr, {SX, SY}, {EX, EY})) :-
|
||||
Arr = from_lists(map(to_char_list, Lines)),
|
||||
find(Arr, 'S', SX, SY),
|
||||
find(Arr, 'E', EX, EY).
|
||||
|
||||
:- pred find_from(array2d(T)::in, T::in, int::in, int::in, int::out, int::out)
|
||||
is semidet.
|
||||
find_from(Arr, A, X1, Y1, X2, Y2) :-
|
||||
bounds(Arr, W, H),
|
||||
Y1 < H,
|
||||
(if X1 < W then
|
||||
B = Arr^elem(X1, Y1),
|
||||
(if A = B then X2 = X1, Y2 = Y1
|
||||
else find_from(Arr, A, X1+1, Y1, X2, Y2))
|
||||
else
|
||||
find_from(Arr, A, 0, Y1+1, X2, Y2)).
|
||||
|
||||
:- pred find(array2d(T)::in, T::in, int::out, int::out) is semidet.
|
||||
find(Arr, A, X, Y) :- find_from(Arr, A, 0, 0, X, Y).
|
||||
|
||||
:- func get(grid, point) = char.
|
||||
get(G, {X, Y}) = G^array^elem(X, Y).
|
||||
|
||||
:- func height(char) = int.
|
||||
height(C) = I :-
|
||||
if C = 'S' then I = 0
|
||||
else if C = 'E' then I = 25
|
||||
else I = to_int(C) - to_int('a').
|
||||
|
||||
:- func height(grid, point) = int.
|
||||
height(G, P) = height(get(G, P)).
|
||||
|
||||
:- pred adj_point(point::in, point::out) is multi.
|
||||
adj_point({X, Y}, {X+1, Y}).
|
||||
adj_point({X, Y}, {X-1, Y}).
|
||||
adj_point({X, Y}, {X, Y+1}).
|
||||
adj_point({X, Y}, {X, Y-1}).
|
||||
|
||||
:- pred adj(grid::in, point::in, point::out) is nondet.
|
||||
adj(G, P, Q) :-
|
||||
adj_point(P, Q), in_bounds(G, Q),
|
||||
abs(height(G, P) - height(G, Q)) =< 1.
|
||||
|
||||
:- pred in_bounds(grid::in, point::in) is semidet.
|
||||
in_bounds(G, {X, Y}) :-
|
||||
bounds(G^array, W, H),
|
||||
0 =< X, X < W,
|
||||
0 =< Y, Y < H.
|
||||
|
||||
:- pred index(grid::in, point::out) is nondet.
|
||||
index(G, {I, J}) :-
|
||||
bounds(G^array, W, H),
|
||||
nondet_int_in_range(0, W-1, I),
|
||||
nondet_int_in_range(0, H-1, J).
|
||||
|
||||
|
||||
:- type path == list(point).
|
||||
|
||||
:- type distance ---> i(int); inf.
|
||||
|
||||
:- import_module solutions.
|
||||
|
||||
:- import_module map.
|
||||
:- type pm == map(point, point).
|
||||
|
||||
:- type nq ---> nq(pq, dm).
|
||||
:- type dm == map(point, distance).
|
||||
:- type pq == list({point, distance}).
|
||||
|
||||
:- pred remove_min(point::out, distance::out, pq::in, pq::out) is semidet.
|
||||
remove_min(X, D, [{X0, D0} | PQ0], PQ) :-
|
||||
if
|
||||
remove_min(X1, D1, PQ0, PQ1),
|
||||
D1 @< D0
|
||||
then
|
||||
X = X1, D = D1,
|
||||
PQ = [{X0, D0} | PQ1]
|
||||
else
|
||||
X = X0, D = D0,
|
||||
PQ = PQ0.
|
||||
|
||||
:- pred seen(nq::in, point::in) is semidet.
|
||||
seen(nq(_, S), X) :- contains(S, X).
|
||||
|
||||
:- pred next(point::out, distance::out, nq::in, nq::out) is semidet.
|
||||
next(X, D, nq(!.Q, !.S), nq(!:Q, !:S)) :-
|
||||
remove_min(X, D, !Q), set(X, D, !S).
|
||||
|
||||
:- pred set_distance_pq(point::in, distance::in, pq::in, pq::out) is det.
|
||||
set_distance_pq(_, _, [], []).
|
||||
set_distance_pq(X, D, [{Y, E} | Xs], Zs) :-
|
||||
if X = Y then
|
||||
Zs = [{X, D} | Xs]
|
||||
else
|
||||
set_distance_pq(X, D, Xs, Xs2),
|
||||
Zs = [{Y, E} | Xs2].
|
||||
|
||||
:- pred set_distance(point::in, distance::in, nq::in, nq::out) is det.
|
||||
set_distance(X, D, nq(!.Q, !.S), nq(!:Q, !:S)) :-
|
||||
set_distance_pq(X, D, !Q),
|
||||
(if contains(!.S, X) then det_update(X, D, !S) else true).
|
||||
|
||||
:- func get_distance(point, pq, dm) = distance.
|
||||
:- mode get_distance(in, in, in) = out is semidet.
|
||||
get_distance(X, [], S) = search(S, X).
|
||||
get_distance(X, [{Y, D} | Xs], S) = D1 :-
|
||||
if X = Y then D1 = D else D1 = get_distance(X, Xs, S).
|
||||
|
||||
:- func get_distance(point, nq) = distance.
|
||||
:- mode get_distance(in, in) = out is semidet.
|
||||
get_distance(X, nq(Q, S)) = get_distance(X, Q, S).
|
||||
|
||||
|
||||
:- pred insert_init(point::in, point::in, pq::in, pq::out) is det.
|
||||
insert_init(From, X, !Queue) :-
|
||||
(if X = From then D = i(0) else D = inf),
|
||||
cons({X, D}, !Queue).
|
||||
|
||||
:- pred init_queue(grid::in, point::in, nq::out) is det.
|
||||
init_queue(G, From, nq(Q, init)) :-
|
||||
aggregate(index(G), insert_init(From), [], Q).
|
||||
|
||||
|
||||
:- pred get_path_rev(pm::in, point::in, point::in, path::out) is det.
|
||||
get_path_rev(Map, From, To, Path) :-
|
||||
if From = To then
|
||||
Path = []
|
||||
else if search(Map, To, Prev) then
|
||||
get_path_rev(Map, From, Prev, Tail),
|
||||
Path = [To | Tail]
|
||||
else
|
||||
To = {X, Y},
|
||||
die("no predecessor for {%d, %d}", [i(X), i(Y)]).
|
||||
|
||||
:- pred get_path(pm::in, point::in, point::in, path::out) is det.
|
||||
get_path(Map, From, To, reverse(Path)) :- get_path_rev(Map, From, To, Path).
|
||||
|
||||
:- func incr(distance) = distance.
|
||||
incr(inf) = inf.
|
||||
incr(i(N)) = i(N + 1).
|
||||
|
||||
:- pred neighbours(grid::in, point::in, nq::in, point::out) is nondet.
|
||||
neighbours(G, Point, Queue, N) :-
|
||||
adj(G, Point, N),
|
||||
not seen(Queue, N).
|
||||
|
||||
:- pred path(grid::in, point::in, point::in, path::out,
|
||||
nq::in, nq::out, pm::in, pm::out) is semidet.
|
||||
path(G, From, To, Path, !Queue, !Prev) :-
|
||||
next(Point, Distance, !Queue),
|
||||
Distance = inf => die("ow"),
|
||||
Neighs = solutions(neighbours(G, Point, !.Queue)),
|
||||
foldl2(pred(Neigh::in, % 🐴
|
||||
!.Queue::in, !:Queue::out,
|
||||
!.Prev::in, !:Prev::out) is det :- (
|
||||
Alt = incr(Distance),
|
||||
(if Alt @< get_distance(Neigh, !.Queue) then
|
||||
set_distance(Neigh, Alt, !Queue),
|
||||
set(Neigh, Point, !Prev)
|
||||
else true)),
|
||||
Neighs, !Queue, !Prev),
|
||||
(if Point = To then
|
||||
get_path(!.Prev, From, To, Path)
|
||||
else
|
||||
path(G, From, To, Path, !Queue, !Prev)).
|
||||
|
||||
:- pred path(grid::in, point::in, point::in, path::out) is semidet.
|
||||
path(G, From, To, Path) :-
|
||||
init_queue(G, From, Queue),
|
||||
path(G, From, To, Path, Queue, _, init, _).
|
||||
|
||||
:- pred path(grid::in, path::out) is semidet.
|
||||
path(G, Path) :- path(G, G^start, G^end, Path).
|
||||
|
||||
|
||||
run(_, Lines, Out) :-
|
||||
if
|
||||
grid(Lines, G),
|
||||
init_queue(G, G^start, Q),
|
||||
path(G, G^start, G^end, Path, Q, nq(Q1, S1), init, Prev)
|
||||
then
|
||||
Out = 'new other'({"RESULT", length(Path):int,
|
||||
"G", G, "Path", Path,
|
||||
"Q1", Q1,
|
||||
"S1", to_assoc_list(S1):list(_),
|
||||
"Prev", to_assoc_list(Prev):list(_)})
|
||||
else
|
||||
die("bad input").
|
||||
|
||||
/* omg could u imagine if this had worked tho
|
||||
|
||||
:- pragma memo(path/5, [fast_loose]).
|
||||
:- pred path(grid::in, point::in, point::in, path::in, int::out)
|
||||
is nondet.
|
||||
path(G, P, P, _, 0).
|
||||
path(G, P, Q, Seen, Len + 1) :-
|
||||
adj(G, P, P1),
|
||||
not member(P1, Seen),
|
||||
path(G, P1, Q, [P|Seen], Len).
|
||||
|
||||
:- pred path(grid::in, point::in, point::in, int::out) is nondet.
|
||||
path(G, P, Q, Len) :- path(G, P, Q, [], Len).
|
||||
|
||||
:- import_module solutions.
|
||||
|
||||
run(_, Lines, Out) :-
|
||||
if grid(Lines, G) then
|
||||
solutions(path(G, G^start, G^end), Paths),
|
||||
Out = int(det_head(Paths))
|
||||
else
|
||||
die("bad input").
|
||||
*/
|
|
@ -1,178 +0,0 @@
|
|||
--- todo make it parse the input unmodified
|
||||
|
||||
fmod OBJECT is
|
||||
sort Object .
|
||||
ops ore clay obsidian geode : -> Object [ctor] .
|
||||
endfm
|
||||
|
||||
view Object from TRIV to OBJECT is sort Elt to Object . endv
|
||||
|
||||
|
||||
fmod INV is
|
||||
pr NAT + OBJECT .
|
||||
|
||||
sorts Item Inv .
|
||||
subsort Item < Inv .
|
||||
op nil : -> Inv [ctor] .
|
||||
op __ : Nat Object -> Item [ctor prec 10] .
|
||||
op _and_ : Inv Inv -> Inv
|
||||
[ctor comm assoc id: nil prec 11] .
|
||||
|
||||
vars A B : Object .
|
||||
vars I J : Nat .
|
||||
|
||||
eq 0 A = nil .
|
||||
eq (I A) and (J A) = (I + J) A .
|
||||
|
||||
vars X Y : Inv .
|
||||
|
||||
op _-_ : Inv Inv -> [Inv] [prec 20] .
|
||||
eq Y - nil = Y .
|
||||
ceq I A and X - J A and Y = sd(I, J) A and (X - Y) if J <= I .
|
||||
|
||||
op count : Object Inv -> Nat .
|
||||
eq count(A, I A and X) = I .
|
||||
eq count(A, X) = 0 [owise] .
|
||||
endfm
|
||||
|
||||
|
||||
fmod BP-ITEM is
|
||||
pr OBJECT + INV .
|
||||
|
||||
sort BpItem .
|
||||
op item : Object Inv -> BpItem [ctor] .
|
||||
|
||||
var A : Object . var Xs : Inv .
|
||||
|
||||
op (Each _ robot costs _ .) : Object Inv -> BpItem [prec 20] .
|
||||
eq (Each A robot costs Xs .) = item(A, Xs) .
|
||||
endfm
|
||||
|
||||
view BpItem from TRIV to BP-ITEM is sort Elt to BpItem . endv
|
||||
|
||||
|
||||
fmod BP is
|
||||
pr SET{BpItem} * (sort Set{BpItem} to Items, op _,_ to __ [prec 21]) .
|
||||
|
||||
sort Bp .
|
||||
op bp : Nat Items -> Bp [ctor] .
|
||||
|
||||
var I : Nat .
|
||||
var Rs : Items .
|
||||
|
||||
op (Blueprint _ : _) : Nat Items -> Bp [prec 30] .
|
||||
eq (Blueprint I : Rs) = bp(I, Rs) .
|
||||
|
||||
op index : Bp -> Nat .
|
||||
eq index(bp(I, Rs)) = I .
|
||||
|
||||
op items : Bp -> Items .
|
||||
eq items(bp(I, Rs)) = Rs .
|
||||
endfm
|
||||
|
||||
view Bp from TRIV to BP is sort Elt to Bp . endv
|
||||
|
||||
|
||||
fmod MAYBE{T :: TRIV} is
|
||||
sort Maybe{T} .
|
||||
subsort T$Elt < Maybe{T} .
|
||||
op nothing : -> Maybe{T} [ctor] .
|
||||
endfm
|
||||
|
||||
fmod BAG{T :: TRIV} is
|
||||
sort Bag{T} .
|
||||
subsort T$Elt < Bag{T} .
|
||||
|
||||
op nil : -> Bag{T} [ctor] .
|
||||
op __ : Bag{T} Bag{T} -> Bag{T} [ctor assoc comm id: nil] .
|
||||
endfm
|
||||
|
||||
fmod STATE is
|
||||
pr NAT .
|
||||
pr LIST{Bp} * (sort List{Bp} to Bps,
|
||||
op __ : Bps Bps -> Bps to __ [prec 31]) .
|
||||
pr MAYBE{Object} * (sort Maybe{Object} to Making) .
|
||||
pr BAG{Object} * (sort Bag{Object} to Robots) .
|
||||
|
||||
sort State .
|
||||
op running : Bp Making Robots Inv -> State [ctor] .
|
||||
subsort Nat < State .
|
||||
|
||||
var Bp : Bp .
|
||||
var Rs : Robots .
|
||||
var X : Object .
|
||||
var Y : Making .
|
||||
var Xs : Inv .
|
||||
|
||||
op new : Bp -> State .
|
||||
eq new(Bp) = running(Bp, nothing, ore, nil).
|
||||
|
||||
op count : Object State -> Nat .
|
||||
eq count(X, running(Bp, Y, Rs, Xs)) = count(X, Xs) .
|
||||
endfm
|
||||
|
||||
view State from TRIV to STATE is sort Elt to State . endv
|
||||
|
||||
|
||||
mod RULES is
|
||||
pr STATE .
|
||||
|
||||
var Bp : Bp .
|
||||
var Is : Items .
|
||||
var Rs : Robots .
|
||||
var X : Object .
|
||||
var Y : Making .
|
||||
vars Xs Ys : Inv .
|
||||
|
||||
op collect : Robots -> Inv .
|
||||
eq collect(nil) = nil .
|
||||
eq collect(X Rs) = 1 X and collect(Rs) .
|
||||
|
||||
op qual : Bps Inv -> Nat .
|
||||
eq qual(Bp, Xs) = index(Bp) * count(geode, Xs) .
|
||||
|
||||
rl [collect] : running(Bp, Y, Rs, Xs) =>
|
||||
running(Bp, Y, Rs, Xs and collect(Rs)) .
|
||||
|
||||
crl [startBuild] : running(Bp, nothing, Rs, Xs) =>
|
||||
running(Bp, X, Rs, Xs - Ys)
|
||||
if item(X, Ys) Is := items(Bp)
|
||||
/\ Xs - Ys :: Inv .
|
||||
|
||||
rl [finishBuild] : running(Bp, X, Rs, Ys) =>
|
||||
running(Bp, nothing, X Rs, Ys) .
|
||||
|
||||
rl [done] : running(Bp, Y, Rs, Xs) => qual(Bp, Xs) .
|
||||
endm
|
||||
|
||||
|
||||
smod RUN is
|
||||
pr LIST{State} .
|
||||
pr RULES .
|
||||
|
||||
var N : Nat .
|
||||
var X : Object .
|
||||
var S : State .
|
||||
var Ss : List{State} .
|
||||
|
||||
--- this won't work because e.g. in example 1 it will just keep making a
|
||||
--- million clay guys forever and never get enough ore for an obsidian guy
|
||||
strat buildBest : @ State .
|
||||
sd buildBest := startBuild[X <- geode]
|
||||
or-else startBuild[X <- obsidian]
|
||||
or-else startBuild[X <- clay]
|
||||
or-else startBuild[X <- ore] .
|
||||
|
||||
strat step1 : @ State .
|
||||
sd step1 := try(buildBest) ; collect ; try(finishBuild) .
|
||||
|
||||
strat stepAll : @ List{State} .
|
||||
sd stepAll := try(matchrew S Ss by S using step1, Ss using stepAll) .
|
||||
|
||||
strat stepsOnly : Nat @ List{State} .
|
||||
sd stepsOnly(0) := idle .
|
||||
sd stepsOnly(s(N)) := stepAll ; stepsOnly(N) .
|
||||
|
||||
strat steps : Nat @ List{State} .
|
||||
sd steps(N) := stepsOnly(N) ; done ! .
|
||||
endsm
|
2
aoc.m
2
aoc.m
|
@ -47,7 +47,6 @@ run_day(Day, Part, Lines, Out) :-
|
|||
:- import_module day9.
|
||||
:- import_module day10.
|
||||
:- import_module day11.
|
||||
:- import_module day12.
|
||||
:- import_module day13.
|
||||
:- import_module day14.
|
||||
:- import_module day16.
|
||||
|
@ -65,7 +64,6 @@ solution(8, day8.run).
|
|||
solution(9, day9.run).
|
||||
solution(10, day10.run).
|
||||
solution(11, day11.run).
|
||||
solution(12, day12.run).
|
||||
solution(13, day13.run).
|
||||
solution(14, day14.run).
|
||||
solution(16, day16.run).
|
||||
|
|
195
day12.m
195
day12.m
|
@ -1,195 +0,0 @@
|
|||
:- module day12.
|
||||
:- interface.
|
||||
:- import_module basics.
|
||||
|
||||
:- pred run(part::in, lines::in, answer::out) is cc_multi.
|
||||
|
||||
:- implementation.
|
||||
:- import_module int.
|
||||
:- import_module char.
|
||||
:- import_module string.
|
||||
:- import_module list.
|
||||
:- import_module array2d.
|
||||
:- import_module map.
|
||||
:- import_module psqueue.
|
||||
:- import_module solutions.
|
||||
|
||||
:- type point == {int, int}.
|
||||
|
||||
:- type grid ---> g(array :: array2d(char), start :: point, end :: point).
|
||||
|
||||
:- pred grid(lines::in, grid::out) is nondet.
|
||||
grid(Lines, g(Arr, {SX, SY}, {EX, EY})) :-
|
||||
Arr = from_lists(map(to_char_list, Lines)),
|
||||
find(Arr, 'S', SX, SY),
|
||||
find(Arr, 'E', EX, EY).
|
||||
|
||||
:- pred find(array2d(T)::in, T::in, int::out, int::out) is nondet.
|
||||
find(Arr, X, I, J) :- index_arr(Arr, I, J), Arr^elem(I, J) = X.
|
||||
|
||||
:- func grid^elem(point) = char.
|
||||
G^elem({X, Y}) = G^array^elem(X, Y).
|
||||
|
||||
:- func height(char) = int.
|
||||
height(C) = I :-
|
||||
if C = 'S' then I = 0
|
||||
else if C = 'E' then I = 25
|
||||
else I = to_int(C) - to_int('a').
|
||||
|
||||
:- func height(grid, point) = int.
|
||||
height(G, P) = height(G^elem(P)).
|
||||
|
||||
:- pred adj_point(point::in, point::out) is multi.
|
||||
adj_point({X, Y}, {X+1, Y}).
|
||||
adj_point({X, Y}, {X-1, Y}).
|
||||
adj_point({X, Y}, {X, Y+1}).
|
||||
adj_point({X, Y}, {X, Y-1}).
|
||||
|
||||
:- pred adj(grid::in, point::in, point::out) is nondet.
|
||||
adj(G, P, Q) :-
|
||||
adj_point(P, Q), in_bounds(G, Q),
|
||||
height(G, Q) =< height(G, P) + 1.
|
||||
|
||||
:- pred in_bounds(grid::in, point::in) is semidet.
|
||||
in_bounds(G, {X, Y}) :- in_bounds(G^array, X, Y).
|
||||
|
||||
|
||||
:- pred bounds(grid::in, int::out, int::out) is det.
|
||||
bounds(G, W, H) :- bounds(G^array, W, H).
|
||||
|
||||
:- pred index(grid::in, point::out) is nondet.
|
||||
index(Grid, {I, J}) :- index_arr(Grid^array, I, J).
|
||||
|
||||
:- pred index_arr(array2d(T)::in, int::out, int::out) is nondet.
|
||||
index_arr(Arr, I, J) :-
|
||||
bounds(Arr, W, H),
|
||||
nondet_int_in_range(0, W-1, I),
|
||||
nondet_int_in_range(0, H-1, J).
|
||||
|
||||
|
||||
:- type path == list(point).
|
||||
:- type distance ---> i(int); inf.
|
||||
:- type pm == map(point, point).
|
||||
:- type nq == psqueue(distance, point).
|
||||
|
||||
:- pred (distance::in) < (distance::in) is semidet.
|
||||
i(_) < inf.
|
||||
i(M) < i(N) :- M < N.
|
||||
|
||||
:- pred min(distance::in, distance::in, distance::out) is det.
|
||||
min(A, B, ite(A < B, A, B)).
|
||||
|
||||
:- func init_dist(point, point) = distance.
|
||||
init_dist(Start, P) = ite(unify(P, Start), i(0), inf).
|
||||
|
||||
:- pred init_queue(grid::in, point::in, nq::out) is det.
|
||||
init_queue(G, Start, Q) :-
|
||||
Points = solutions(index(G)),
|
||||
foldl(pred(P::in, !.Q::in, !:Q::out) is det :-
|
||||
det_insert(init_dist(Start, P), P, !Q),
|
||||
Points, psqueue.init, Q).
|
||||
|
||||
:- pred init_queue(grid::in, nq::out) is det.
|
||||
init_queue(G, Q) :- init_queue(G, G^start, Q).
|
||||
|
||||
:- pred incr(distance::in, distance::out) is det.
|
||||
incr(inf, inf).
|
||||
incr(i(N), i(N+1)).
|
||||
|
||||
:- pred neighbour(grid::in, nq::in, point::in, {point,distance}::out) is nondet.
|
||||
neighbour(G, Q, P, {N, D}) :- adj(G, P, N), search(Q, N, D).
|
||||
|
||||
:- pred update_distance(point::in, distance::in, {point,distance}::in,
|
||||
pm::in, pm::out, nq::in, nq::out) is det.
|
||||
update_distance(Prev, DNew, {P, DOld}, !M, !Q) :-
|
||||
if DNew < DOld then
|
||||
(if adjust(func(_) = DNew, P, !Q) then true else die("point disappeared")),
|
||||
set(P, Prev, !M)
|
||||
else true.
|
||||
|
||||
:- pred path0(grid::in, point::in, pm::in, pm::out, nq::in, nq::out) is det.
|
||||
path0(G, End, !M, !Q) :-
|
||||
det_remove_least(Distance, Point, !Q),
|
||||
(if Point = End then true else
|
||||
solutions(neighbour(G, !.Q, Point), Neighbours),
|
||||
incr(Distance, NeighDistance), % 🐴↔🐴
|
||||
foldl2(update_distance(Point, NeighDistance), Neighbours, !M, !Q),
|
||||
path0(G, End, !M, !Q)).
|
||||
|
||||
:- func get_path_len(grid, pm, point, point) = distance.
|
||||
get_path_len(G, M, Start, Point) = Out :-
|
||||
if Point = Start then
|
||||
Out = i(0)
|
||||
else if search(M, Point, Prev) then
|
||||
incr(get_path_len(G, M, Start, Prev), Out)
|
||||
else
|
||||
Out = inf.
|
||||
|
||||
|
||||
:- pred path_len(grid::in, point::in, point::in, distance::out) is det.
|
||||
path_len(Grid, Start, End, Len) :-
|
||||
init_queue(Grid, Start, Queue),
|
||||
path0(Grid, End, init, Prevs, Queue, _),
|
||||
Len = get_path_len(Grid, Prevs, Start, End).
|
||||
|
||||
:- pred path_len(grid::in, distance::out) is det.
|
||||
path_len(Grid, Len) :- path_len(Grid, Grid^start, Grid^end, Len).
|
||||
|
||||
|
||||
:- pred start(grid::in, point::out) is nondet.
|
||||
start(Grid, P) :- index(Grid, P), height(Grid, P) = 0.
|
||||
|
||||
:- pred shortest(grid::in, list(point)::in, point::in, distance::out) is det.
|
||||
shortest(Grid, Starts, End, Distance) :-
|
||||
map(pred(P::in, D::out) is det :- path_len(Grid, P, End, D),
|
||||
Starts, Distances),
|
||||
foldl(min, Distances, inf, Distance).
|
||||
|
||||
:- func distance(distance) = answer.
|
||||
distance(inf) = string("∞").
|
||||
distance(i(N)) = int(N).
|
||||
|
||||
|
||||
run(one, Lines, Out) :-
|
||||
if
|
||||
grid(Lines, Grid),
|
||||
path_len(Grid, Len)
|
||||
then
|
||||
Out = distance(Len)
|
||||
else
|
||||
die("bad input").
|
||||
run(two, Lines, Out) :-
|
||||
% i did floyd warshall and it was WAY too slow
|
||||
% like several seconds per row :////
|
||||
if grid(Lines, Grid) then
|
||||
solutions(start(Grid), Starts),
|
||||
shortest(Grid, Starts, Grid^end, Distance),
|
||||
Out = distance(Distance)
|
||||
else
|
||||
die("bad input").
|
||||
|
||||
|
||||
|
||||
/* omg could u imagine if this had worked tho
|
||||
|
||||
:- pragma memo(path/5, [fast_loose]).
|
||||
:- pred path(grid::in, point::in, point::in, path::in, int::out)
|
||||
is nondet.
|
||||
path(G, P, P, _, 0).
|
||||
path(G, P, Q, Seen, Len + 1) :-
|
||||
adj(G, P, P1),
|
||||
not member(P1, Seen),
|
||||
path(G, P1, Q, [P|Seen], Len).
|
||||
|
||||
:- pred path(grid::in, point::in, point::in, int::out) is nondet.
|
||||
path(G, P, Q, Len) :- path(G, P, Q, [], Len).
|
||||
|
||||
:- import_module solutions.
|
||||
|
||||
run(one, Lines, Out) :-
|
||||
if grid(Lines, G) then
|
||||
solutions(path(G, G^start, G^end), Paths),
|
||||
Out = int(det_head(Paths))
|
||||
else
|
||||
die("bad input").
|
||||
*/
|
Loading…
Reference in New Issue