Skip to content

Instantly share code, notes, and snippets.

@jp-diegidio
Last active October 14, 2023 18:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jp-diegidio/72e4df22b92e9427e265 to your computer and use it in GitHub Desktop.
Save jp-diegidio/72e4df22b92e9427e265 to your computer and use it in GitHub Desktop.
Einstein's riddle in Prolog
/*
Einstein's riddle: who owns the fish?
There are 5 houses in 5 different colors in a row. In each house lives a
person with a different nationality. The 5 owners drink a certain type of
beverage, smoke a certain brand of cigar, and keep a certain pet. No
owners have the same pet, smoke the same brand of cigar, or drink the same
beverage. Other facts:
1. The Brit lives in the red house.
2. The Swede keeps dogs as pets.
3. The Dane drinks tea.
4. The green house is on the immediate left of the white house.
5. The green house's owner drinks coffee.
6. The owner who smokes Pall Mall rears birds.
7. The owner of the yellow house smokes Dunhill.
8. The owner living in the center house drinks milk.
9. The Norwegian lives in the first house.
10. The owner who smokes Blends lives next to the one who keeps cats.
11. The owner who keeps the horse lives next to the one who smokes Dunhill.
12. The owner who smokes Bluemasters drinks beer.
13. The German smokes Prince.
14. The Norwegian lives next to the blue house.
15. The owner who smokes Blends lives next to the one who drinks water.
The question is: WHO OWNS THE FISH?
*/
:- use_module(library(clpfd)).
:- use_module(library(lists)).
:- use_module(library(aggregate)).
owns_fish :-
owners(Owners),
aggregate_all(
max(OL),
( member(O, Owners),
atom_length(O, OL)
),
OLM
),
OL is OLM + 1,
owns_fish(Owner, Count / Sum, Freq),
FF is round(100_000 * Freq) / 1_000,
RL is 3 + ceiling(log10(Sum + 1)) << 1,
Fmt = '~|~a:~*+ ~|~t~3f%~8+ ~|~t(~d/~d)~*+',
FAs = [Owner, OL, FF, Count, Sum, RL],
format(Fmt, FAs).
owns_fish(Owner, Rat, Freq) :-
owners(Owners),
aggregate(
a(sum(Count), bag(Owner-Count)),
aggregate(
count,
Ls^owns_fish(Ls, Owner),
Count
),
a(Sum, OCs0)
),
member(Owner, Owners),
( memberchk(Owner-Count, OCs0)
-> true
; Count = 0
),
Rat = Count / Sum,
Freq is Count rdiv Sum.
owns_fish([Ps, Hs, Bs, Cs, As], Owner) :-
owners(Owners),
owns_fish__sol([Ps, Hs, Bs, Cs, As], Fish),
nth1(I, Ps, Fish),
nth1(I, Owners, Owner).
owners(['British', 'Danish', 'German', 'Norwegian', 'Swedish']).
owns_fish__sol([Ps, Hs, Bs, Cs, As], Fish) :-
Ps = [British, Danish, German, Norwegian, Swedish],
Hs = [Blue, Green, Red, White, Yellow],
Bs = [Beer, Coffee, Milk, Tea, Water],
Cs = [Blends, Blumasters, Dunhill, Pallmall, Prince],
As = [Birds, Cats, Dogs, Fish, Horse],
Ps ins 1..5, all_different(Ps),
Hs ins 1..5, all_different(Hs),
Bs ins 1..5, all_different(Bs),
Cs ins 1..5, all_different(Cs),
As ins 1..5, all_different(As),
British #= Red, % 1
Swedish #= Dogs, % 2
Danish #= Tea, % 3
abs(Green - White) #= 1, % 4
Green #= Coffee, % 5
Pallmall #= Birds, % 6
Yellow #= Dunhill, % 7
Milk #= 3, % 8
abs(Blends - Cats) #= 1, % 10
abs(Horse - Dunhill) #= 1, % 11
Blumasters #= Beer, % 12
German #= Prince, % 13
abs(Norwegian - Blue) #= 1, % 14
abs(Blends - Water) #= 1, % 15
labeling([], Ps),
labeling([], Hs),
labeling([], Bs),
labeling([], Cs),
labeling([], As).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment