0

So I've been working on something to help me understand Prolog better. I took the traditional water jug problem but added a bit of difficulty. Thus, my code is working pretty good. The only thing left to do would be to do some nice formatting for the output. Currently, it only shows the minimal path found with my code for the jug filling. (see example below)

So far, I thought a way I can do it, but I have no clue how to do it in Prolog.

The final list of my optimal path is formatted like this : [ [x(a,b),y(c,d),z(e,f)], [], [], ...]

I want to reach this format (see below for a more detailed output):

a -> b
c -> d
etc
  • First, I print the initial one that as liquid (in our case, 1. Otherwise, the first element on the list is the initial pattern). Then, I follow by taking the first sub-list, and comparing with the one before to see which of the jug did transfer to the other and print it. Then, continue until the list is empty.

Currently, it shows this:

?- problem.
[[jug(3,0),jug(5,0),jug(8,8)],[jug(3,0),jug(5,5),jug(8,3)],
 [jug(3,3),jug(5,2),jug(8,3)],[jug(3,0),jug(5,2),jug(8,6)],
 [jug(3,2),jug(5,0),jug(8,6)],[jug(3,2),jug(5,5),jug(8,1)],
 [jug(3,3),jug(5,4),jug(8,1)],[jug(3,0),jug(5,4),jug(8,4)]]
true .

Which is the right path for the current jugs configuration. (I'll add a way to do with n jugs later)

This is the way I would like it to show (in my code, you can see the index I want for each of them):

?- problem.
1 -> 2
2 -> 3
3 -> 1
2 -> 3
1 -> 2
2 -> 3
3 -> 1
true.

I'd love to get help with this one since everything I'm trying is a logical mess.

Thanks guys/girls <3

  • I feel like the main problem here is an inconvenient data format. You don't actually know which jug you're manipulating when you pour them, and your solutions don't have that information either. I think you should augment your data structure so you know which jug is which (perhaps `[3-jug(3,0), 2-jug(5,0), 1-jug(8,8)]`), and then during your pours, you can keep a side list of what happened, rather than trying to figure it all out post-facto. – Daniel Lyons Apr 25 '19 at 16:35
  • @DanielLyons: I would just use `jug(Column,MaxWater,CurrentWater)` as OP code is currently relying on `MaxWater` being defined strictly ascendent for the code to work properly (see for example the call to `sort/2` in `next_state/2`). Then for each transition he can use `Column` values to record each step. – gusbro Apr 25 '19 at 17:26
  • @gusbro that sound pretty good in fact. But I don't know how I would impletement it. I know where the jugs are, they are in the same order. Simply, I don't know how to compare them. My current plan is good on paper, crazy easy to implement in an imperative language. I have to get the index of each, and compare if they changed. If they did, then I take the position of it and use write(). That way I can produce a good looking output. The only thing is I don't know how to do it, how to get the index of the element in the list, etc, etc. – Guillaume Levesque Apr 25 '19 at 17:54
  • @GuillaumeLevesque: Have you tried your program with a different initial/end states (for example swapping first and second jugs) ? – gusbro Apr 25 '19 at 18:04
  • The algorithm you said you have in paper would also be easy to write in prolog. You have to also take into account that one jug "loses" water and another "gains" water to write the transition. But it would be easier if you just keep track of that info while you build your chain as you can already have all the information at that point. – gusbro Apr 25 '19 at 18:11
  • @gusbro The program works with every jugs I want them to have. When my output is done, I’ll rework the code so I can put the jugs I want, and how many I want. (Ex: problem([5,0,0], [4,3,4], [24,12,12],...).). I think it’s going to be easier than doing the output. I searched and read so much without any clues on how to do my output (explaining why I posted here) – Guillaume Levesque Apr 25 '19 at 18:16
  • @gusbro here is my algorithm, I don't know if you can help me write it in Prolog... Take list S, extract head and second element (`[X|Y|XS]`). Compare the two first, find out which jug lose and gain water. use `write(indexLoss), write(' -> '), write(indexGain).` Then repeat until `XS =:= [ ]`. – Guillaume Levesque Apr 25 '19 at 18:49

2 Answers2

0

Provided that you have an actual solution path (I believe your code will not yield correct results for some initial/end states), you can write the procedure as follows:

show([_]).
show([S1, S2|Tail]):-
  show1(S1, S2, 3, Gain, Loss),  # 3 here is the number of jugs
  write(Loss), write(' -> '), write(Gain),nl,
  show([S2|Tail]).

show1([], [], _, _, _).
show1([jug(Max1,Cur1)|S1], [jug(Max2,Cur2)|S2], Idx, Gain, Loss):-
  succ(NIdx, Idx),
  (Max1-Cur1=Max2-Cur2 -> true;
   (Cur2 > Cur1 -> Gain=Idx ;
    Loss=Idx
  )),
  show1(S1, S2, NIdx, Gain, Loss).

However, I'd advice you to improve the original code to compute these values when you build the solution path.

Sampe run:

show([[jug(3,0),jug(5,0),jug(8,8)],[jug(3,0),jug(5,5),jug(8,3)], 
     [jug(3,3),jug(5,2),jug(8,3)],[jug(3,0),jug(5,2),jug(8,6)], 
     [jug(3,2),jug(5,0),jug(8,6)],[jug(3,2),jug(5,5),jug(8,1)], 
     [jug(3,3),jug(5,4),jug(8,1)],[jug(3,0),jug(5,4),jug(8,4)]]).
1 -> 2
2 -> 3
3 -> 1
2 -> 3
1 -> 2
2 -> 3
3 -> 1
true.
gusbro
  • 22,357
  • 35
  • 46
0

see the pattern to inspect two adjacent elements

show(L) :-
    findall(T, (append(_,[A,B|_],L), transition(A,B,T)), Ts),
    maplist(writeln, Ts).

transition(
    [jug(3,A),jug(5,B),jug(8,C)],
    [jug(3,U),jug(5,V),jug(8,Z)],
    S->T
) :-
    P=[A^U,B^V,C^Z],
    nth0(L,P,X^M), X>M,
    nth0(R,P,Y^N), Y<N,
    S is 3-L, T is 3-R.
CapelliC
  • 59,646
  • 5
  • 47
  • 90