1

I have 3 jugs of water problem to solve but with a little trick.I dont have to use an algorithm but to have a 'function' that allows to user to move litres from on jug to another with an initial and final state that its written also by him.

For example he writes initial(10,0,0,0,r) and the first state is 10 litres in first and zero in the other two, also he writes final(0,3,3,3,l) and the final state has 3 litres in the two smaller jugs and zero in the first one.

The 'moves' between the jugs happen when he writes go(7,3,r) where he moves 3 litres to the right (from right to left we have the jugs form bigger to smaller) from bigger to the second jug, -7 is the litres that are left and 3 are the litres to be moved and r is the direction-.

And i have written this prolog code but every go-state is false..Has anyone any idea why??

:- dynamic go/3.
:- dynamic cur_state/1,init/5.
:- dynamic end_state/1, final/5.

cur_state(State):-State = state(10,0,0,7,l).
end_state(State):-State = state(0,3,3,0,r).

pour(state(D1,D2,D3,N,l),move(D,C,r),state(D,C,D3,N,r)) :-
        D is D1-N,
        C is D2+N.
pour(state(D1,D2,D3,N,r),move(D,C,l),state(D,C,D3,N,l)) :-
        D is D1-N,
        C is D2.
pour(state(D1,D2,D3,N,l),move(D,C,r),state(D,D2,C,N,r)) :-
        D is D1-N,
        C is D3+N.
pour(state(D1,D2,D3,N,l),move(D,C,r),state(D1,D,C,N,r)) :-
        D is D2-N,
        C is D3+N.
pour(state(D1,D2,D3,N,r),move(D,C,l),state(D1,D,C,N,l)) :-
        D is D2-N,
        C is D1+N.
pour(state(D1,D2,D3,N,r),move(D,C,l),state(D1,D,c,N,l)) :-
        D is D2-N,
        C is D3.
pour(state(D1,D2,D3,N,l),move(D,C,r),state(C,D2,D,N,r)) :-
        D is D3-N,
        C is D1.
pour(state(D1,D2,D3,N,r),move(D,C,l),state(D1,C,D,N,l)) :-
        D is D3-N,
        C is D2+N.
pour(state(D1,D2,D3,N,r),move(D,C,l),state(C,D2,D,N,l)) :-
        D is D3-N,
        C is D1+N.

carry(7,0).
carry(3,0).
carry(10,0).
carry(4,0).
carry(7,3).

legal(10,X,Y):-X+Y=<10.
legal(X,Y,Z):-X+Y+Z=<10.
legal(X,7,Y):-X+Y=<3.
legal(X,Y,3):-X+Y=<7.

newstate(state(D1,D2,D3,N,l),state(D11,D22,D33,N1,r)):-
        carry(M,C),
        M=<7,C=<3,
        D22 is D2+N,
        D11 is D1-N,
    D3 is D33,
    N1 is N,
        D2=<7,D1=<10,
    legal(D1,D2,D3).

newstate(state(D1,D2,D3,N,r),state(D11,D22,D33,N1,l)):-
        carry(M,C),
        M=<10,C=<100,
        D11 is D1-N,
    D22 is D2,
    D33 is D3,
        D1=<10,
    legal(D1,D2,D3).

newstate(state(D1,D2,D3,N,l),state(D11,D22,D33,N1,r)):-
        carry(M,C),
        M=<10,C<3,
        D11 is D1-N,
        D33 is D3+N,
    D22 is D2,
        D1=<10,D3=<3,
    legal(D1,D2,D3).

newstate(state(D1,D2,D3,N,r),state(D11,D22,D33,N1,l)):-
        carry(M,C),
        M=<7,C=<3,
        D22 is D2-N,
        D33 is D1+N,
        D11 is D1,
        D2=<7,D1=<10,
    legal(D1,D2,D3).

newstate(state(D1,D2,D3,N,l),state(D11,D22,D33,N1,r)):-
        carry(M,C),
        M=<7,C=0,
        D22 is D2-N,
        D33 is D3+N,
        D11 is D1,
    D2=<7,D3=<3,
    legal(D1,D2,D3).

newstate(state(D1,D2,D3,N,r),state(D11,D22,D33,N1,l)):-
        carry(M,C),
        M=<7,C=<100,
        D22 is D2-N,
    D33 is D3,
    D11 is D1,    
    D2=<7,
    legal(D1,D2,D3).

newstate(state(D1,D2,D3,N,r),state(D11,D22,D33,N1,l)):-
        carry(M,C),
        M=<3,C=<7,
        D22 is D2+N,
        D33 is D3-N,
        D11 is D1,
    D3=<3,D2=<7,
    legal(D1,D2,D3).

newstate(state(D1,D2,D3,N,r),state(D11,D22,D33,N1,l)):-
        carry(M,C),
        M=<3,C=<100,
        D11 is D1+N,
        D33 is D3-N,
        D22 is D2,
    D3=<3,D1=<10,
    legal(D1,D2,D3).

newstate(state(D1,D2,D3,N,l),state(D11,D22,D33,N1,r)):-
        carry(M,C),
        M=<3,C=<100,
        D33 is D3-N,
        D22 is D2,
    D11 is D1,  
    D3=<3,
    legal(D1,D2,D3).


eisodos(_):- cur_state(State),write(State),nl.

init(S1,S2,S3,S4,S5):-assert(cur_state(State):-State =                 state(S1,S2,S3,S4,S5)),write('Arxikh:'),
write(state(S1,S2,S3,S4,S5)),retractall(init(S1,S2,S3,S4,S5)),nl.

final(S1,S2,S3,S4,S5):-assert(end_state(State):-State =  state(S1,S2,S3,S4,S5)),write('Telikh:'),
write(state(S1,S2,S3,S4,S5)),retractall(final(S1,S2,S3,S4,S5)),nl.

go(Move1,Move2,Move3):-cur_state(State),newstate(State,NextState),
    pour(State,move(Move1,Move2,Move3), NextState),
    retractall(cur_state(State):-State = state(_,_,_,_,_)),asserta(cur_state(NextState)),
    ((end_state(NextState),write('Bravo!!!!')) ;(write(' ---*Eiste sthn katastash --- :'),write(NextState))),nl.
false
  • 10,264
  • 13
  • 101
  • 209
tetartos
  • 171
  • 1
  • 1
  • 10

2 Answers2

1

I copied your code and compiled with SWI-Prolog, and I got these messages:

?- Warning: /home/carlo/prolog/jug1.pl:20:
    Singleton variables: [D3]
Warning: /home/carlo/prolog/jug1.pl:57:
    Singleton variables: [N1]
Warning: /home/carlo/prolog/jug1.pl:66:
    Singleton variables: [N1]
Warning: /home/carlo/prolog/jug1.pl:75:
    Singleton variables: [N1]
Warning: /home/carlo/prolog/jug1.pl:84:
    Singleton variables: [N1]
Warning: /home/carlo/prolog/jug1.pl:93:
    Singleton variables: [N1]
ERROR: /home/carlo/prolog/jug1.pl:102:
    evaluable `n' does not exist
ERROR: /home/carlo/prolog/jug1.pl:111:
    evaluable `n' does not exist
ERROR: /home/carlo/prolog/jug1.pl:120:
    evaluable `n' does not exist
% /home/carlo/prolog/jug1.pl compiled 0,01 sec, 32 clauses

Superficial code inspection reveals other defects, like the lower case 'c' at line 23. You should apply all the hints that you got with your previous question.

Factorize your code, this will help you to understand what's going on: newstate/2 has 9 rules, nearly identical. The only changes, errors apart (again lower case identifiers that are mispelled variables), are differents constants. It seems that state/5 really holds values related to 'moves'. You should separe these (i.e. the last 2 arguments) and pass to newstate (that should become like newstate(OldState, NumLitres, Direction, NewState)).

Community
  • 1
  • 1
CapelliC
  • 59,646
  • 5
  • 47
  • 90
  • Thanks for your answer..i changed the c in line 23 but still i've got the same problems that you mentioned..I'm new in prolog so i'm not sure that i understand what you are suggesting..Can you give me an example? – tetartos Jan 27 '12 at 11:23
  • I've read again your question, and maybe I misunderstood your problem. If you want to read the user choices, you must us **read**. For instance: go(Move1,Move2,Move3) :- read(Initial), read(Final), read(Move1), apply_move(Initial, Move1, Intermed1), read(Move2), apply_move(Intermed1, Move2, Intermed2),... etc. Is this what you want? – CapelliC Jan 27 '12 at 21:11
  • for example a typical condition: the user initialize with init(10,0,0,0,r) and final(0,3,3,3,r) so we start with ten litres in only one jug and we want to have fiannly 3 litres in the last two jugs.But this can only happen by the moves the user gives.So he must give four 'moves' by writing go(7,3,r),go(0,3,l),go(4,3,r),go(0,4,l). So the problem is not solved by the 'code' but by the user..Did i help you understand? – tetartos Jan 28 '12 at 17:17
1

It's hard to make sense of what you've written. If initial state is ini(10,0,0,0,r), what are the last two arguments there? you only have three jugs don't you? Why final state is fin(0,3,3,3,r)? What do the last 3 and r mean??

You have three jugs, so your state just has three values in it: s(A,B,C). You seem to want to have it dynamically redefined on the go. Fine. Your go(...) predicate will call retract/assert and will have to take care of the logic. If you want your user to be able to say "pour to the right" why do you insist on him to write also how much water is left in the jug??? That seems wrong, your system must calculate that value, and update your current dynamic database with it. Plus, "pour to the right" from where ?? Seems to me, your go(7,3,r) says "pour from a '7'-jug the 3 liters of water into the jug to the right of it", but if so, why do you need to specify the amount at all?? Isn't it contrary to the usual specification of the jugs problem, where you do not have any ability to measure and are just instead given the jugs' capacities? Does it instead mean "pour all the water you can from a '7' jug into a '3' jug"? If so, r has no function.

So please clarify your problem. And lastly, what are your jugs' capacities?

EDIT: Well, after clarifications in the comments below about the rules, I would code this as follows:

%% to be called: initial(10-10,7-0,3-0).
%% to be called: final(10-0,7-3,3-3).

initial(C1-W1,C2-W2,C3-W3):- % capacity-water_content
  retractall( jug(_,_) ), 
  asserta( jug(C1,W1) ),
  asserta( jug(C2,W2) ),
  asserta( jug(C3,W3) ).

final(C1-W1,C2-W2,C3-W3):- 
  retractall( end_jug(_,_) ), 
  asserta( end_jug(C1,W1) ),
  asserta( end_jug(C2,W2) ),
  asserta( end_jug(C3,W3) ).

jugsState(L) :- findall(X-W, jug(X,W), L). % see the state

go(Cfrom,0):-  !, % pour out the water
  retract( jug(Cfrom,_) ), 
  asserta( jug(Cfrom,0) ),
  is_final_state.

go(Cfrom,Cto):-
  retract( jug(Cfrom,Wfrom) ),
  retract( jug(Cto,Wto) ),
  Space is Cto-Wto,
  (  Wfrom >= Space
  -> Wleft is Wfrom - Space,
     asserta( jug(Cfrom,Wleft) ),
     asserta( jug(Cto,Cto) )
  ;  Wnew is Wto+Wfrom,
     asserta( jug(Cfrom,0) ),
     asserta( jug(Cto,Wnew) ) ),
  is_final_state.

is_final_state :- true.

Now what's left is to define is_final_state which will check the jug facts, see if the end state is reached, print out the congratulatory message if it is, and return true always. Or something like that. The sample run can be e.g.

?- initial(10-10,7-0,3-0).
?- final(10-0,7-3,3-3).
?- go(10,7).
?- go(7,3).
?- go(7,0).
?- jugsState(X).
X = [7-0, 3-3, 10-3]
?- ....
Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • Ok you're right.Well the capacities are 10,7,3.The last two arguments are: the first is for the litres that are going to be moved(i use it in newstate),as i didn't know how to 'connect' the init and the newstate i had to put the same number of arguments.The other argument is for the direction of move r for right and l for left. – tetartos Jan 31 '12 at 14:09
  • I did the case that the jugs are from right to left 10 ,7 and 3.And go(7,3,r) means move 3 litres to the right and 7 will be left in the first jug.This can only happen with the first and third jug because we can't measure the litres and this is why we only need the direction and not the id of jug. – tetartos Jan 31 '12 at 14:09
  • I can't understand you. Are you saying you're only allowed to pour water in certain direction, <-10, 10<->7, 7<->3, 3-> ? Why don't you start by stating your specification clearly and fully? Is this a Prolog question or a question of deciphering what your problem really is? In any case, if you have 3 jugs, just have 3 facts describing them, each of form `jug(Capacity,Amount)`. Again, `go` can't let the user to say how much is left, it must calculate it itself. So it can be `go(From,To)` with `From,To` the capacities used as ID. `go` will maintain the three `jug` facts in consistent state. – Will Ness Jan 31 '12 at 20:02
  • No i'm not saying this..go can't tell how much is left but how else can i write 'go' only for eligible moves?? For example what i say is that this way if you write how much litres are left the user specifies the exact move from another.So if he writes go(7,3,r) it can't be any other move except from 3 litres from 10 to 3.There is also go(3,0,l) which 'moves'3 litres to left so to the jug with 7 litres capacity..And there are also other moves that are described by newstate.. – tetartos Feb 01 '12 at 06:47
  • I asked you to clearly and fully describe your problem statement. You still didn't. In usual formulations of 3 jugs, it *is* perfectly possible to say how much is left. The initial state says how much is there in each. Pouring usually involves pouring all the water that fits into the smaller jug. Then it is a matter of simple subtraction. So, *what is your setting?* Until you describe your problem clearly it is impossible to continue. – Will Ness Feb 01 '12 at 09:53
  • My programm actually is mostly a simulation than a programm that solves the 3-jugs problem.The user must write-go- to solve it by itself.The programm just need to check if user's go are possible moves.So i try to connect go with newstate.And i create the 9 possible moves by writing the 9 -pour- and 9 newstates that come after these 9 'pour'.i couldn't think another way to describe the 9 specific moves than mine.So i describe them by how many litres are moved and left (in go) to specify the move from the possible 9..I hope this post is more helpfull.. – tetartos Feb 02 '12 at 08:41
  • sorry, but you still don't describe your problem. Here, I'll start it for you: "there is a man who has three jugs, of 10,7, and 3 litres capacity. Initially there is some water in some jugs. Then the man is allowed to pour water from/to jugs according to the following rules: ... . The goal is to reach the state with a certain amount of water left in each jug." So, *what are the rules for pouring water into/from the jugs*??? – Will Ness Feb 02 '12 at 20:52
  • So, is it that we can {1. pour all water out from a jug onto the ground; and 2. pour all water we can from one jug into another one - either until the second jug is full, or the first is empty}? Are *these* your rules, or do you have something else? – Will Ness Feb 02 '12 at 22:06
  • Initial state: two options.Firts one -the user by init defines the initial state.Second the initial state is the jug of 10 litres is full and the other empty. Final state: two options.Firts one -the user by final defines the final state.Second the final state is the jug of 10 litres is empty and the other two jugs have 3 litres each. Rules: Pour water from each jug to another but with measure(so all the amount of water that the jug has) and pour empty the jug to the 'ground'(lose the water).We can't pour water if the jug is full or the amount of water that is gonna to be moved is more than the – tetartos Feb 04 '12 at 18:00
  • litres are needed to fill the other jug. – tetartos Feb 04 '12 at 18:01
  • And one last question...Is it possible every time i write the go function to show in the screen the jugsState without writing anything else? For example: go(10,7). and in the screen: Jugs[10-3,7-7,3-0]. ??? I tried with retractall but i didn't make it.. – tetartos Feb 05 '12 at 08:46
  • @tetartos of course, you can add it to the `is_final_state` predicate: `jugsState(X), writeln(X)`. You can also add more stuff, like summing up all water contents of all jugs, and if it's less than 6, print out a warning that the final state is unreachable. Or you can refuse to make such a move. There's all kinds of stuff you can add into this framework. BTW if you feel like it, here in stackoverflow you can "accept" an answer that you think answers your question. To do that, you click on a big empty check mark next to it, and the author of that answer gets their reputation bumped up. – Will Ness Feb 05 '12 at 09:59
  • @tetartos I think you should read more Prolog documentation, and/or introductory textbooks. The Art of Prolog is a fine book. [SWI-Prolog documentation](http://www.swi-prolog.org/pldoc/index.html) is very concise. – Will Ness Feb 05 '12 at 10:04
  • Will Ness one more question..Can i have a 'congratulation' message if jugstate is the same as final that i have been given at the start??? – tetartos Feb 23 '12 at 18:04
  • @tetartos that's the idea behind `is_final_state`. It returns `true` always, so why is it there at all? Because it is a skeleton code, so that you can add there the check for the finality of the state, and if it is indeed final, print the message. The name is a bit misleading; better rename it to `check_state_finality` or something. Also, if you detect that there is too little water, you can print a warning message, and `fail`. – Will Ness Feb 23 '12 at 18:19
  • yes but how can i check if it's equal the jugstate with final..? i'm not able to write it in prolog.. – tetartos Feb 23 '12 at 18:24
  • @tetartos so do you have enough rep to upvote yet? :) As for your check, after the call `jugsState(L), L=[C1-W1,C2-W2,C3-W3]` you can sum them up, `Total_water is W1+W2+W3, Total_water >= 6` etc. You can also use `sort`, as in `jugsState(_L), sort(_L,S), writeln(S), S=[3-3, 7-3, 10-0]` to check the finality. You can change the `jugsState` itself to incorporate sorting, as `jugsState(L) :- findall(X-W, jug(X,W), L0), sort(L0,L).` Etc., etc. :) – Will Ness Feb 23 '12 at 18:38
  • @tetartos or in general, `jugsState([C1-W1,C2-W2,C3-W3]), end_jug(C1,W1), ..., end_jug(C3,W3)` Remember, `end_jug(C,W)` facts are asserted by the `final(...)` call, which a user must make at the beginning of the session. (this way we don't need `sort`). – Will Ness Feb 23 '12 at 18:46
  • i have and i will give it right now :P Well now i have written this: jugsState(L) :- findall(X-W, jug(X,W), L0), sort(L0,L). how do i check this sorted L with final(C1-W1,C2-W2,C3-W3) ??? (i don't like prolog there is no if !!! :P) – tetartos Feb 23 '12 at 18:49
  • there is no way to check somehow end_jug with jug?? like this: if end_jug(C1,W1) == jug(C1,W1) && end_jug(C2,W2) == jug(C2,W2) && end_jug(C3,W3) == jug(C3,W3) write('Congrats'). – tetartos Feb 23 '12 at 19:17
  • @tetartos everything is an IF in Prolog. Look above, I already gave you the answer: `the_state_is_final :- jugsState([C1-W1,C2-W2,C3-W3]), end_jug(C1,W1), ..., end_jug(C3,W3)`. You just put `end_jug(C2,W2)` instead of `...` and it's done. Calling `the_state_is_final` will succeed if the state is final, and fail otherwise. You don't need any more checks, it is already checked for you by Prolog's unification, or else `end_jug(_,_)` wouldn't succeed. Remeber, all three `end_jug(_,_)` facts are asserted, when a user calls `final(...)` at the start of the session. *Let go of the Basic mindset*. :) – Will Ness Feb 23 '12 at 19:44
  • @tetartos you use it like this: `the_state_is_final, writeln('Congrats!')`. And the explicit IF in prolog is this: `the_state_is_final -> writeln('Congrats!')`. If you still have questions, ask a new question on SO, and include your new code there. :) Cheers, and you're welcome. :) – Will Ness Feb 23 '12 at 19:52
  • @tetartos take note, I've fixed an error in `initial` and `final` definitions, the calls to `retractall` were erroneous. – Will Ness Feb 24 '12 at 06:52