1

I'm trying to learn Prolog by solving Advent Of Code puzzles, and have ended up being stuck on a task that I think should be pretty simple. The puzzle in question is this one. The task requires me to find all program IDs (integers) that are connected to program ID 0. Connections are symmetric and transitive, so if there exists a connection between programs from different connected groups, all programs in the given groups are connected to each other.

My current situation is that I've sorted the integers in the puzzle into sublists that each represent the group that they belong to.

For example: [[0, 2], [1, 1], [2, 0, 3, 4], [3, 2, 4], [4, 2, 3, 6], [5, 6], [6, 4, 5]]

I need to get all the programs that are somehow connected to 0. In this example, that would be all programs except the program with ID 1.

So, the logic that I'm looking for is something that manages to check if a given integer exists in both the expanding group that contains 0 and the group that my recursive predicate connected is currently looking at. I realise that this method might end up ignoring new connections to groups that were looked at earlier in the recursion, but that is a separate problem.

Sorting the programs into the sublists like above is not a problem, so I'm omitting that part from what I have so far.

main(R) :-
  Groups = [[0, 2], [1, 1], [2, 0, 3, 4], [3, 2, 4], [4, 2, 3, 6], [5, 6], [6, 4, 5]],
  connected(Groups, [0], R). 

connected([H|T], X, R) :-
  member(Y, H), member(Y, X) -> flatten([H|X], X1), connected(T, X1, R) ; R = X. 

The result I'm getting here is simply: [0,2,0]
The result that I expect is: [0,2,0,2,0,3,4,3,2,4,4,2,3,6,5,6,6,4,5]

I've realised that the element [1,1] may stop the recursion too early, so I've tried changing the last line above to the following:
member(Y, H), member(Y, X) -> flatten([H|X], X1), connected(T, X1, R) ; connected(T, X, R).

However, that simply causes main(R). to evaluate to false for some reason. Likewise, it returns false if I simply remove [1,1] from the groups without changing the last line.

I assume that I'm overlooking something quite simple, and would appreciate any input.

SindreKjr
  • 249
  • 2
  • 17
  • 1
    It might be easier to work with adjacency lists as your "group variable". That is, the list would be formed like Groups = [[p0, []], [p1, [ – Simon Sirak Dec 22 '17 at 12:40
  • I agree that it feels like a graph problem, and my initial sorting was actually in the format that you're suggesting ([[p0, [1,2,3]], [p1, [...]]]). But I'm not sure where to go from there. Shouldn't it also be feasible to simply join together groups of nodes like I'm attempting? – SindreKjr Dec 22 '17 at 13:07
  • The reason you don't get everything is that `connected/2` stops as soon as it finds a set, such as `[1,1]` with an empty intersection with the current nodes. – Tomas By Dec 22 '17 at 13:35
  • @TomasBy When using `R = X`, yes. Did you read the last paragraphs of my post? Changing `R = X` to `connected(T, X, R)` or removing [1,1] results in false, and I don't understand why. – SindreKjr Dec 22 '17 at 13:41
  • 1
    Could add a 2nd clause `connected([], R, R).` – Tomas By Dec 22 '17 at 13:56
  • @TomasBy That seems to be all I needed to make my predicate do as I wanted. Thank you! :) – SindreKjr Dec 22 '17 at 15:09

1 Answers1

2

Assuming your Groups have the proper structure, you may keep a list of "unvisited" groups, and at each recursive step take an unvisited item and add its still-unvisited neighours.

i.e.:

main(R) :-
  Groups = [[0, 2], [1, 1], [2, 0, 3, 4], [3, 2, 4], [4, 2, 3, 6], [5, 6], [6, 4, 5]],
  connected([0], [], Groups, R).

connected([], _, _, []).
connected([P|Tail], Visited, Groups, [P|R]):-
  select([P|Ps], Groups, NGroups), % Get the item's neighours
  subtract(Ps, [P|Visited], NPs),  % subtract from it the visited ones
  union(Tail, NPs, NTail),         % and add these neighours to the unvisited list
  connected(NTail, [P|Visited], NGroups, R).

This will get the set of "connected" programs without duplicates:

?- main(R).
R = [0, 2, 3, 4, 6, 5]
gusbro
  • 22,357
  • 35
  • 46
  • It doesn't produce `[0,2,0,2,0,3,4,3,2,4,4,2,3,6,5,6,6,4,5]` – Tomas By Dec 22 '17 at 14:34
  • No, it gets the set of connected programs, as stated in the puzzle link provided by @OP. Will update answer to state that. – gusbro Dec 22 '17 at 14:40
  • Works perfectly, thanks! I see now that the predicate I had in mind might have gotten me stuck on the wrong mindset to solve the puzzle. – SindreKjr Dec 22 '17 at 15:10