1

Before I state this, I logically understand the solution to this question, am just having a hard time coding it. A family of 4 is trying to cross a bridge at night. One needs a flashlight to cross the bridge,and only two persons can cross the bridge at the same time, moving at the speed of the slower of the two. Father crosses the bridge in 1 minute, Mother in 2 minutes, Child in 5 minutes and Granny in 10. I am trying to write a Prolog program that can handle this kind of question, but for families of any size moving at any speed. The total crossing time must be less than a maximum specified time. We are given the families in a fact form family(Name,[X1/T1,X2/T2...etc]). We are asked to define a predicate MoveFamily(FamilyName, MAxTime, Moves, Time) where familyName and Max time are bound variables and moves binds to the moves taken to cross everyone from one side to another, time binds to the total time it takes. Here is what I have so far:

moveSouth(North,South,Moves,Time):-
   member(X/T1,North), % x is a member of the north list
   member(Y/T2,North), %y is a member of the north list
   X \= Y, 
   Big is max(T1,T2),
   select(X/T1, North, List2), %List2 is North with x removed
   select(Y/T2, List2, NewNorth), %newNorth is north with x and y removed
   New is Time+Big, %new time is old time plus maximum time
   moveNorth(NewNorth, [X/T1,Y/T2|South], [X+Y|Moves], New).

moveNorth([],_,[],_,_). %this will be the last move
moveNorth(North,South,Moves,Time):-
   member(X/T1,South),
   select(X/T1, South, NewSouth),
   New is Time + T1,
   moveSouth([X/T1|North], NewSouth, [X|Moves], New).

getList(Name,List):-
   family(Name,List).

moveFamily(Name, Max, Moves, Time):-
   getList(Name,People),
   Time =< Max,
   moveSouth(People, [], Moves, Time).

family(two, [fred/1, george/2]).

When I run this on the fact family(two, [fred/1, george/2]). I get :

[debug]  ?- moveFamily(two,20,Moves,Time).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR:    [9] _10170=<20
ERROR:    [8] moveFamily(two,20,_10200,_10202) 
ERROR:    [7] <user>
Exception: (9) _9500=<20 ? creep
Exception: (8) moveFamily(two, 20, _9498, _9500) ? creep

Does anyone know why this will not work?

edit: When crossing two at a time they move at the speed of the slower member

edit2: family "Two" is family(two, [fred/1, george/2]).

edit3: The desired output from the query moveFamily(two,20,Moves,Time) should be

  Moves = [fred+george],
  Time = 2 

edit4: I put the family fact in the code block, I'm a dummy and should have realized that's what you meant lol

coder
  • 12,832
  • 5
  • 39
  • 53
  • I tried running again with the time=< max commented out, and instead i just get False –  Apr 05 '18 at 22:32
  • also, family/2 is Family(two, [fred/1, george/2]), I will make that clearer in an edit –  Apr 05 '18 at 22:33
  • How else would I be able to ensure moves takes on the right values? would I use an append predicate and create a new list? I had tried using append before so I could not pass in moves recursively but could not figure out how to implement it –  Apr 05 '18 at 22:43
  • im confused as to what you mean :/ –  Apr 06 '18 at 00:10
  • 1
    I was trying to understand your code but gave up(this is terrible). Please use sourcecode debugger(like gtrace in SWI) and modify the bug one by one.at least you have to use select/3 at member(X/T1,North),member(Y/T2,North) and both side of '=<' must be number. – Taku Koyahata Apr 06 '18 at 06:41
  • Essentially, you are trying to use arithmetic functions from a separate C++ library built into most versions of Prolog, without specifying what you want to calculate. UNKNOWN + 1 isn't going to produce anything. You **must** use numerical atoms to calculate anything in Prolog, you cannot have uninstantiated variables in anything that uses [evaluation](http://www.swi-prolog.org/pldoc/man?section=arith). – G_V Apr 06 '18 at 09:09

1 Answers1

1

Some strange comments appeared overnight.

This seems to work:

moveFamily(Name,Max,Moves,Time) :-
  getList(Name,People),
  moveSouth(People,[],Moves,Time),
  Time =< Max.

getList(Name,List) :-
  family(Name,List).

moveSouth(North,South,[X+Y|Moves],New) :-
  member(X/T1,North), member(Y/T2,North), X \= Y,
  Big is max(T1,T2),
  select(X/T1,North,List2), select(Y/T2,List2,NewNorth),
  moveNorth(NewNorth,[X/T1,Y/T2|South],Moves,Time), New is Time + Big.
moveSouth([],_,[],0).

moveNorth(North,South,[X|Moves],New) :-
  member(X/T1,South), select(X/T1,South,NewSouth),
  moveSouth([X/T1|North],NewSouth,Moves,Time), New is Time + T1.
moveNorth([],_,[],0).

Addition: when you say [X|Moves] in parameter #3 in the recursive call, that means you are taking apart the return value from the call, but what you want to do is add X to it, which is what happens when you put that in the head of the clause instead.

Tomas By
  • 1,396
  • 1
  • 11
  • 23
  • Thank you so much! with this i was able to add the final modfications and complete the problem! I now see what you mean by i was taking the list apart instead of adding to it! –  Apr 06 '18 at 16:46
  • Your code certainly makes me think why I hadn't tried that already haha! –  Apr 06 '18 at 16:47