# Specifying a simple puzzle in CLP

**URL:** <https://swi-prolog.discourse.group/t/specifying-a-simple-puzzle-in-clp/3892>\
**Category:** Help!\
**Tags:** discussion, how-to, clp, clpfd\
**Created:** [April 30, 2021, 7:32pm UTC](https://swi-prolog.discourse.group/t/specifying-a-simple-puzzle-in-clp/3892 "2021-04-30T19:32:53Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![bladyjoker](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/bladyjoker/32/2634_2.png) [@bladyjoker](https://swi-prolog.discourse.group/u/bladyjoker)\
**Post date:** [April 30, 2021, 7:32pm UTC](https://swi-prolog.discourse.group/t/specifying-a-simple-puzzle-in-clp/3892/1 "2021-04-30T19:32:53Z")

</div>

Hello marvelous Prolog community,  
I watched Vsauces’ recent Future of Reasoning video on YouTube ([https://youtu.be/\_ArVh3Cj9rw?t=590](https://youtu.be/_ArVh3Cj9rw?t=590)) where he presented his audience with a simple logical puzzle:

```prolog
Paul is looking at Mary.
Mary is looking at Peter.
Paul is married.
Peter is unmarried.

Is a married person looking at an unmarried person?

```

I wanted to specify this puzzle in Prolog, naturally I turned to _clp_ libraries for this. I ended up using the following formulation:

```prolog
:- use_module(library(clpfd)).

?- [Paul, Peter, Mary] ins 0..1,
   LookingAts = [Paul-Mary, Mary-Peter],
   Paul #= 1, Peter #= 0,
   member(1-0, LookingAts).
Paul = 1,
Peter = Mary, Mary = 0,
LookingAts = [1-0, 0-0] ;
Paul = Mary, Mary = 1,
Peter = 0,
LookingAts = [1-1, 1-0].

```

I encoded _married_ as 1 and _unmarried_ as _0_, and placed _looking at_ facts in a list which I eventually query to find solutions for `a married person looking at an unmarried person` with `member(1-0, LookingAts)`

I’m fairly inexperienced in _clp_ and Prolog generally, but still I don’t find this solution overly satisfactory. Is there perhaps a more elegant, perhaps more readable or idiomatic way of expressing this puzzle?

Regards,  
Drazen

---

<div class="post-metadata">

**Author:** ![JCR](https://avatars.discourse-cdn.com/v4/letter/j/258eb7/32.png) [@JCR](https://swi-prolog.discourse.group/u/JCR)\
**Post date:** [April 30, 2021, 8:25pm UTC](https://swi-prolog.discourse.group/t/specifying-a-simple-puzzle-in-clp/3892/2 "2021-04-30T20:25:46Z")

</div>

Hi and welcome!

Can’t you do it as follows?

```
p(paul, looksAt, mary).
p(mary, looksAt, peter).
married(paul).
unmarried(peter).

```

With the query `?-married(X), p(X, looksAt, Y), unmarried(Y).`

Or you explicitly wanted to use CLP?

Cheers/JCR

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [May 1, 2021, 1:53am UTC](https://swi-prolog.discourse.group/t/specifying-a-simple-puzzle-in-clp/3892/3 "2021-05-01T01:53:18Z")

</div>

If you try that simple program, you’ll find that the query fails.

However, if you know that a person is either married or unmarried, then you can try adding the fact `married(mary)`, in which case you’ll get success (mary looks at peter); and if you try instead adding the fact `unmarried(mary)`', you’ll also get success (paul looks at mary).

So, the trick is encoding the married state as either `married` or `unmarried`, and setting up Mary accordingly. You can’t just have both `married` and `unmarried` facts for Mary; but you can have the married state as a list of _Person-MarriedOrUnmarried_.

```prolog
looking_at(paul, mary).
looking_at(mary, peter).

married_state([paul-married,
               peter-unmarried,
               mary-M]) :-
    M = married ; M = unmarried.

query(P1, P2) :-
    married_state(MarriedState),
    looking_at(P1, P2),
    member(P1-married, MarriedState),
    member(P2-unmarried, MarriedState),
    P1 \= P2.

?- query(P1,P2).
P1 = mary, P2 = peter ;
P1 = paul, P2 = mary ;
false.

```

This isn’t a complete solution … you need to try all possible values of MarriedState and verify that the rest of the query succeeds. I’ll leave that extra piece as an exercise. 😉

---

<div class="post-metadata">

**Author:** ![bladyjoker](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/bladyjoker/32/2634_2.png) [@bladyjoker](https://swi-prolog.discourse.group/u/bladyjoker)\
**Post date:** [May 1, 2021, 5:46pm UTC](https://swi-prolog.discourse.group/t/specifying-a-simple-puzzle-in-clp/3892/4 "2021-05-01T17:46:08Z")

</div>

Thanks a lot Jean-Christophe and Peter!

Re JCR: As Peter suggested, there’s this silent fact that Mary can indeed be either married or unmarried, which, when considered explicitly, gives us solutions.

Re Peter: I like your solution as it’s pure Prolog and straight to the point. `married_state` represents _world choices_ we’re searching through, very cool.

> [@peter.ludemann](#):
>
> This isn’t a complete solution … you need to try all possible values of MarriedState and verify that the rest of the query succeeds. I’ll leave that extra piece as an exercise

Hmmm, I honestly don’t see what’s lacking from your solution. `married_state` succeeds twice as that’s how many possible states there are:

```prolog
married_state([paul-married,
               peter-unmarried,
               mary-M]) :-
    M = married ; M = unmarried.
?- married_state(X).
X = [paul-married, peter-unmarried, mary-married] ;
X = [paul-married, peter-unmarried, mary-unmarried].

```

I wonder what I’m missing 🙂

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [May 1, 2021, 7:02pm UTC](https://swi-prolog.discourse.group/t/specifying-a-simple-puzzle-in-clp/3892/5 "2021-05-01T19:02:58Z")

</div>

> [@bladyjoker](#):
>
> I wonder what I’m missing 🙂

You’re running the test manually. A true programmer runs the tests with automation. 😉  
The `all_query/0` predicate below will succeed if all states can have a married person looking at an unmarried person (if it fails, it might print out some intermediate results … again, I leave cleaning that up as an exercise).

This is essentially the same code as before, except I’ve added a `MarriedState` argument to `query/2` (making it `query/3`) and added a `query_all/0` predicate to verify that for all possible values from `married_state/1` the query succeeds.

```prolog
looking_at(paul, mary).
looking_at(mary, peter).

married_state([paul-married,
               peter-unmarried,
               mary-M]) :-
    M = married ; M = unmarried.

query(P1, P2, MarriedState) :-
    looking_at(P1, P2),
    member(P1-married, MarriedState),
    member(P2-unmarried, MarriedState),
    P1 \= P2.

all_query :-
    forall(married_state(MS),
           ( query(P1, P2, MS),
             format('~w looking at ~w with state=~w~n', [P1, P2, MS])
           )).

```

```prolog
?- all_query.
mary looking at peter with state=[paul-married,peter-unmarried,mary-married]
paul looking at mary with state=[paul-married,peter-unmarried,mary-unmarried]

```
