1

I am trying to create a prolog predicate to solve this zebra problem however It keeps on running indefinitely and does not produce a result, how can I fix this.

Here is the Zebra Problem:

The five biggest DJs in the world are going to play in an electronic music festival, each one in a specific stage. They are side by side waiting to play. Find out their nationalities,vhobbies and which genre they play.

DJ Properties:

  • Shirt colors: black, blue, green, red, white

  • Nationalities: American, Canadian, Dutch, French, Scottish

  • Music genres: drum and bass, dubstep, EDM, house, trance

  • Performance stages: Arcadia, Asgard, Shangri-la, Valhalla, Xibalba

  • Ages: 25, 30, 35, 40, 45

  • Hobbies: camping, juggling, painting, singing, surfing

Clues

  • The Scott is somewhere to the left of the DJ wearing the White shirt.

  • At the fourth position is the DJ who is going to play on the Arcadia stage.

  • The 30-year-old DJ is at the first position.

  • The DJ that plays EDM is exactly to the right of the Canadian.

  • The one who likes Painting is next to the DJ who plays Dubstep.

  • The DJ wearing the Black shirt is somewhere between the Scott and the Dubstep player, in that order.

  • The French DJ is next to the one wearing the Blue shirt.

  • At one of the ends is the DJ that likes Camping.

  • The DJ who is going to play on the Asgard stage is wearing the Blue shirt.

  • The one that likes Painting is somewhere between the DJ wearing Green and the DJ wearing Blue, in that order.

  • At the fifth position is the DJ who plays Drum and bass.

  • In the middle is the DJ who is going to play on the Asgard stage.

  • The one who plays Trance is next to the one who plays Dubstep.

  • The Canadian is exactly to the left of the DJ who likes Juggling

  • The DJ whose hobby is Singing is exactly to the right of the DJ wearing the Black shirt.

  • The DJ in his Mid-thirties is next to the DJ who is into Juggling.

  • The 40-year-old DJ is at the fourth position.

  • The 40-year-old DJ is somewhere between the Dutch and the youngest DJ, in that order.

  • The DJ wearing Blue is somewhere to the left of the DJ who is going to play on the Xibalba stage.

  • The one who enjoys Surfing is going to play on the Valhalla stage.

  • The DJ wearing the Red shirt is somewhere to the right of the French

Here is my code so far:

member(X, [X|_]).
member(X, [_|T]) :- member(X, T).

left_of(A, B, L) :- append(_, [A|T], L), member(B, T).

next_to(A, B, L) :- left_of(A, B, L) ; left_of(B, A, L).

solve(DJs) :-
    DJs = [_, _, _, _, _],

    % Clue 1
    member([scott, _, _, _, _, _], DJs),
    member([_, white, _, _, _, _], DJs),
    left_of([scott, _, _, _, _, _], [_, white, _, _, _, _], DJs),

    % Clue 2
    DJs = [_, _, _, [_, _, _, arcadia, _, _], _],

    % Clue 3
    DJs = [[_, _, _, _, 30, _], _, _, _, _],

    % Clue 4
    member([canadian, _, _, _, _, _], DJs),
    member([_, _, edm, _, _, _], DJs),
    left_of([canadian, _, _, _, _, _], [_, _, edm, _, _, _], DJs),

    % Clue 5
    next_to([_, _, _, _, _, painting], [_, _, dubstep, _, _, _], DJs),

    % Clue 6
    left_of([scott, _, _, _, _, _], [_, black, _, _, _, _], DJs),
    left_of([_, black, _, _, _, _], [_, _, dubstep, _, _, _], DJs),

    % Clue 7
    next_to([french, _, _, _, _, _], [_, blue, _, _, _, _], DJs),

    % Clue 8
    (DJs = [[_, _, _, _, _, camping], _, _, _, _] ; DJs = [_, _, _, _, [_, _, _, _, _, camping]]),

    % Clue 9
    member([_, blue, _, asgard, _, _], DJs),

    % Clue 10
    left_of([_, green, _, _, _, _], [_, _, _, _, _, painting], DJs),
    left_of([_, _, _, _, _, painting], [_, blue, _, _, _, _], DJs),

    % Clue 11
    DJs = [_, _, _, [_, _, _, _, 40, _], _],

    % Clue 12
    next_to([_, _, trance, _, _, _], [_, _, dubstep, _, _, _], DJs),

    % Clue 13
    left_of([canadian, _, _, _, _, _], [_, _, _, _, _, juggling], DJs),

    % Clue 14
    left_of([_, black, _, _, _, _], [_, _, _, _, _, singing], DJs),

    % Clue 15
    next_to([_, _, _, _, 35, _], [_, _, _, _, _, juggling], DJs),

    % Clue 16
    left_of([dutch, _, _, _, _, _], [_, _, _, _, 25, _], DJs),
    left_of([_, _, _, _, 25, _], [_, _, _, _, 40, _], DJs),

    % Clue 17
    left_of([_, blue, _, _, _, _], [_, _, _, xibalba, _, _], DJs),

    % Clue 18
    member([_, _, _, valhalla, _, surfing],DJs),

    % Clue 19
    member([_, red, _, _, _, _], DJs),
    left_of([french, _, _, _, _, _], [_, red, _, _, _, _], DJs),

    % Check properties
    member([american, _, _, _, _, _], DJs),
    member([canadian, _, _, _, _, _], DJs),
    member([dutch, _, _, _, _, _], DJs),
    member([french, _, _, _, _, _], DJs),
    member([scottish, _, _, _, _, _], DJs),

    member([_, black, _, _, _, _], DJs),
    member([_, blue, _, _, _, _], DJs),
    member([_, green, _, _, _, _], DJs),
    member([_, red, _, _, _, _], DJs),
    member([_, white, _, _, _, _], DJs),

    member([_, _, drum_and_bass, _, _, _], DJs),
    member([_, _, dubstep, _, _, _], DJs),
    member([_, _, edm, _, _, _], DJs),
    member([_, _, house, _, _, _], DJs),
    member([_, _, trance, _, _, _], DJs),

    member([_, _, _, arcadia, _, _], DJs),
    member([_, _, _, asgard, _, _], DJs),
    member([_, _, _, shangri_la, _, _], DJs),
    member([_, _, _, valhalla, _, _], DJs),
    member([_, _, _, xibalba, _, _], DJs),

    member([_, _, _, _, 25, _], DJs),
    member([_, _, _, _, 30, _], DJs),
    member([_, _, _, _, 35, _], DJs),
    member([_, _, _, _, 40, _], DJs),
    member([_, _, _, _, 45, _], DJs),

    member([_, _, _, _, _, camping], DJs),
    member([_, _, _, _, _, juggling], DJs),
    member([_, _, _, _, _, painting], DJs),
    member([_, _, _, _, _, singing], DJs),
    member([_, _, _, _, _, surfing], DJs).
false
  • 10,264
  • 13
  • 101
  • 209
  • Usual reminder: You can step through your program, to see exactly what is happening and where it is going wrong, using e.g. `trace.` - https://www.swi-prolog.org/pldoc/man?section=debugger – brebs Apr 14 '23 at 08:59
  • Why are you defining member/2, when swi-prolog has a superior definition built-in? https://www.swi-prolog.org/pldoc/doc/_SWI_/library/lists.pl?show=src#member/2 – brebs Apr 14 '23 at 09:12
  • @TessellatingHeckler, what is wrong with `left_of/2`? – false Apr 14 '23 at 18:46
  • Here's a start: length(AllNationalities,5), length(AllColors,5), nth1(CanadianLoc,AllNationalities,canada), nth1(BlackLoc,AllColors,black),CanadianLoc < BlackLoc, %canadian is left of black ...so you start with unassigned lists of length 5; apply some rules; apply more rules. When done, be sure AllNationalities is a permutation of the list of available nationalities (use permutation/2). – Topological Sort Apr 14 '23 at 19:57
  • @false I was mixing up its interaction with member/2; if the Scottish person is supposed to be `left_of` the person in the white shirt, then `[scott, white, _, _, _, _]` should not be one of the things it suggests but it wasn't left_of doing that. – TessellatingHeckler Apr 14 '23 at 20:31
  • Looking at clue 1 - the 2 `member` lines are unnecessary, because a correct `left_of` predicate would itself be ensuring membership. – brebs Apr 16 '23 at 13:54

1 Answers1

1

Try to put your code into small manageable parts first. And then, use the to see if the answers you get are the answers you want. Just your first clue is:

clue1(DJs) :-
    DJs = [_, _, _, _, _],
    % Clue 1
    member([scott, _, _, _, _, _], DJs),
    member([_, white, _, _, _, _], DJs),
    left_of([scott, _, _, _, _, _], [_, white, _, _, _, _], DJs).

?- clue1(DJs).
   DJs = [[scott,white,_A,_B,_C,_D],[_E,white,_F,_G,_H,_I],_J,_K,_L], unexpected
;  DJs = [[scott,white,_A,_B,_C,_D],_E,[_F,white,_G,_H,_I,_J],_K,_L], unexpected
;  ... % many answers omitted
;  DJs = [[_A,white,_B,_C,_D,_E],[scott,_F,_G,_H,_I,_J],[_K,white,_L,_M,_N,_O],_P,_Q], unexpected
;  ... % many answers omitted
;  false.

In total, just for the first clue, there are 250 answers. Many of which can never lead to a solution: The first two answers have two white instead of just one. The last shown answer has scott to the right (and not left) of a white. It is quite similar with the subsequent clues. Let's remove the two member/2 goals since they are already implied by left_of/2. As a result we narrowed down the problem to 10 answers.

?- clue1(DJs).
   DJs = [[scott,_A,_B,_C,_D,_E],[_F,white,_G,_H,_I,_J],_K,_L,_M]
;  DJs = [[scott,_A,_B,_C,_D,_E],_F,[_G,white,_H,_I,_J,_K],_L,_M]
;  DJs = [[scott,_A,_B,_C,_D,_E],_F,_G,[_H,white,_I,_J,_K,_L],_M]
;  DJs = [[scott,_A,_B,_C,_D,_E],_F,_G,_H,[_I,white,_J,_K,_L,_M]]
;  DJs = [_A,[scott,_B,_C,_D,_E,_F],[_G,white,_H,_I,_J,_K],_L,_M]
;  DJs = [_A,[scott,_B,_C,_D,_E,_F],_G,[_H,white,_I,_J,_K,_L],_M]
;  DJs = [_A,[scott,_B,_C,_D,_E,_F],_G,_H,[_I,white,_J,_K,_L,_M]]
;  DJs = [_A,_B,[scott,_C,_D,_E,_F,_G],[_H,white,_I,_J,_K,_L],_M]
;  DJs = [_A,_B,[scott,_C,_D,_E,_F,_G],_H,[_I,white,_J,_K,_L,_M]]
;  DJs = [_A,_B,_C,[scott,_D,_E,_F,_G,_H],[_I,white,_J,_K,_L,_M]]
;  false.

Now, you can observe the failure with some patience. To improve speed you could move up clues, that consist of a single unification like, clue 2, 3, and 11. Also you could ensure with the help of dif/2 that all corresponding entries are different. This would improve speed, but still there would be failure.

Here is a generalization of your program that still fails. I have removed many of the goals in it, leaving only:

solve(DJs) :-
    DJs = [_, _, _, _, _],
    left_of([scott, _, _, _, _, _], [_, white, _, _, _, _], DJs),
    member([american, _, _, _, _, _], DJs),
    member([canadian, _, _, _, _, _], DJs),
    member([dutch, _, _, _, _, _], DJs),
    member([french, _, _, _, _, _], DJs),
    member([scottish, _, _, _, _, _], DJs).

?- solvex(DJs).
   false, unexpected.

Because this fragment fails, also your original program will fail. By fixing this problem, your program works. So you should be able to figure that out. Finally, your problem has, however, 48 solutions which is a bit unusual for a zebra puzzle which typically has only a single solution.

false
  • 10,264
  • 13
  • 101
  • 209