-
Notifications
You must be signed in to change notification settings - Fork 0
/
18.pl
108 lines (95 loc) · 2.83 KB
/
18.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
:- use_module(library(dcgs)).
:- use_module(library(ordsets)).
:- use_module(library(pio)).
:- use_module(library(clpz)).
:- use_module(library(format)).
:- use_module(library(assoc)).
:- use_module(library(debug)).
:- use_module(library(lists)).
:- use_module(library(between)).
:- use_module(library(lambda)).
:- use_module(dcgs/dcgs_utils).
:- use_module(heaps).
pad(X, ['\n'|X]).
input(N, N, A, A) --> ... .
input(_, _, A, A) --> call(eos).
input(MaxN, N, A0, A) -->
"\n",
number(X), ",", number(Y),
{ ord_add_element(A0, X-Y, A1), N1 #= N + 1 },
input(MaxN, N1, A1, A).
visit_and_queue(Max, Map, Parent, Prio, Dir, Visited0-Queue0, Visited-Queue) :-
move(Dir, Parent, Current),
Current = X-Y,
% if it is a rock, or it was visited, or it is out of bounds, do nothing
( ( ord_memberchk(Current, Map)
; get_assoc(Current, Visited0, _)
; (\+ between(0, Max, X))
; (\+ between(0, Max, Y))
)
-> Visited = Visited0, Queue = Queue0
; % otherwise queue it
put_assoc(Current, Visited0, Prio-Parent, Visited),
% And queue it on the heap
add_to_heap(Queue0, Prio, Current, Queue)
).
move(east, X-Y, X1-Y) :-
X1 #= X + 1.
move(west, X-Y, X1-Y) :-
X1 #= X - 1.
move(north, X-Y, X-Y1) :-
Y1 #= Y - 1.
move(south, X-Y, X-Y1) :-
Y1 #= Y + 1.
process(Max, _, Visited, Queue, Visited-Prio) :-
get_from_heap(Queue, Prio, X-Y, _),
X #= Max,
Y #= Max.
process(Max, A, Visited0, Queue0, Sol) :-
get_from_heap(Queue0, Prio, X-Y, Queue1),
Prio1 #= Prio + 1,
foldl( visit_and_queue(Max, A, X-Y, Prio1)
, [north, east, south, west]
, Visited0-Queue1
, Visited-Queue
),
!,
process(Max, A, Visited, Queue, Sol).
part1(F, Sol) :-
phrase_from_file((call(pad), input(1024, 0, [], Map)), F),
empty_heap(Empty),
add_to_heap(Empty, 0, 0-0, Queue),
put_assoc(0-0, t, 0-nil, Visited),
process(70, Map, Visited, Queue, _-Sol).
consume(0, X-Y) -->
"\n",
number(X), ",", number(Y), ... .
consume(N, Sol) -->
{ N #> 0 },
"\n",
number(_), ",", number(_),
{ N1 #= N - 1 },
consume(N1, Sol).
part2_helper(F, Sol, Sol, Sol2) :-
phrase_from_file((call(pad), consume(Sol, Sol2)), F).
part2_helper(F, Min, Max, Sol) :-
Mid #= (Min + Max) // 2,
(phrase_from_file((call(pad), input(Mid, 0, [], Map)), F),
empty_heap(Empty),
add_to_heap(Empty, 0, 0-0, Queue),
put_assoc(0-0, t, 0-nil, Visited),
\+ process(70, Map, Visited, Queue, _),
part2_helper(F, Min, Mid, Sol)
;
Mid1 #= Mid + 1,
part2_helper(F, Mid1, Max, Sol)
).
part2(F, Sol) :-
part2_helper(F, 1024, 3451, Sol).
run :-
part1("18.txt", Sol1),
format("Task 1: ~w~n", [Sol1]),
part2("18.txt", X-Y),
format("Task 2: ~w,~w~n", [X,Y]),
halt.
:- initialization(run).