prolog

# How do I express and solve this trivial logic puzzle?

I tried to express a more complex logic puzzle and boiled down where I'm failing at to this trivial problem:

• a `Car` can be `red` or `green` or `blue`
• `bmw` is not `red` and not `blue`
• solution: `bmw` is `green`

But how do I express this in Prolog? I'd assume there is an almost verbatim formulation, which is also my goal. Just stating the facts and rules and then query. I tried several different options. This would be one attempt:

``````is_(Car,Color) :-
Color = red;
Color = green;
Color = blue.

is_(bmw,red) :- false.
is_(bmw,blue) :- false.
``````

But querying for `is_(bmw, C)` will yield all three colors instead of only `green`:

``````?- is_(bmw,C).
C = red ;
C = green ;
C = blue ;
false.
``````

I sort of understand why this isn't working. But also sort of not.

Above pseudo solution itself is equivalent to:

``````f(X,a).
f(X,b).
f(X,c).
f(r,a) :- false.
f(r,b) :- false.
``````

then:

``````?- f(r,X).
X = a ;
X = b ;
X = c ;
false.
``````

I mean of course ... the facts are disjunctionally related (OR) hence f(r,a) can be true. Also above code without the irrelevant context of car colors makes it obvious that the "knowledge base" as-is is nonsense. But this just brings me back to - how to express it then correctly?

Could someone tell me how this would have to be done? And maybe infer from above pseudo-solution where my thinking is going wrong?

Solution

• As in a relational database:

``````car_manu(bmw).

car_color_general(red).
car_color_general(green).
car_color_general(blue).

car_manu_not_color(bmw, red).
car_manu_not_color(bmw, blue).

car_manu_color(Manu, Color) :-
car_manu(Manu),
car_color_general(Color),
% Ensuring that Manu and Color are instantiated, before using \+
\+ car_manu_not_color(Manu, Color).
``````

Result in swi-prolog:

``````?- car_manu_color(Manu, Color).
Manu = bmw,
Color = green ;
false.
``````