% % A program to solve the logic puzzle from % https://www.ahapuzzles.com/logic/logic-puzzles/expensive-coffee % (Aha!Puzzles by james@ahapuzzles.com) % % Author: Joachim Schimpf, 2024 % Creative Commons Attribution 4.0 International License. % % ?- go. % Blue Mountain costs \$40 and must be steeped at 200F for 60 seconds % La Esmeralda costs \$60 and must be steeped at 210F for 210 seconds % St. Helena costs \$80 and must be steeped at 215F for 45 seconds % Kopi Luwak costs \$100 and must be steeped at 205F for 180 seconds % Aroeiras costs \$120 and must be steeped at 195F for 120 seconds % Yes (0.00s cpu, solution 1, maybe more) % No (0.01s cpu) % :- lib(ic_symbolic). :- lib(ic). :- local domain(names('Aroeiras','Blue Mountain','Kopi Luwak','La Esmeralda','St. Helena')). go :- N = 5, length(Name, N), Name &:: names, length(Price, N), Price #:: [40,60,80,100,120], length(Temp, N), Temp #:: [195,200,205,210,215], length(Seconds, N), Seconds #:: [45,60,120,180,210], ic_symbolic:alldifferent(Name), ic:alldifferent(Price), ic:alldifferent(Temp), ic:alldifferent(Seconds), % Avoid symmetric solutions by ordering some property, e.g. price ic_global:ordered(<, Price), % 1. The \$40 coffee needs 200°F water. ic:element(P40Coffee, Price, 40), ic:element(P40Coffee, Temp, 200), % 2. St. Helena costs \$20 more than the coffee that requires 210°F water. ic_symbolic:element(HelenaCoffee, Name, 'St. Helena'), ic:element(HelenaCoffee, Price, HelenaPrice), ic:element(T210Coffee, Temp, 210), ic:element(T210Coffee, Price, T210Price), HelenaPrice #= T210Price + 20, % 3. The coffee that needs 215°F water is either Aroeiras or St. Helena. ic:element(T215Coffee, Temp, 215), ic_symbolic:element(T215Coffee, Name, T215Name), T215Name &:: ['Aroeiras','St. Helena'], % 4. The coffee that requires 205°F water costs \$40 more than % the La Esmeralda. ic:element(T205Coffee, Temp, 205), ic:element(T205Coffee, Price, T205Price), ic_symbolic:element(EsmCoffee, Name, 'La Esmeralda'), ic:element(EsmCoffee, Price, EsmPrice), T205Price #= EsmPrice + 40, % 5. The coffee that steeps for 2 minutes isn't St. Helena coffee % or Kopi Luwak. ic:element(S120Coffee, Seconds, 120), ic_symbolic:element(S120Coffee, Name, S120Name), S120Name &\= 'St. Helena', S120Name &\= 'Kopi Luwak', % 6. The coffee that steeps for 1 minute costs \$40 less than the % coffee that steeps for 45 seconds. ic:element(S60Coffee, Seconds, 60), ic:element(S60Coffee, Price, S60Price), ic:element(S45Coffee, Seconds, 45), ic:element(S45Coffee, Price, S45Price), S60Price #= S45Price - 40, % 7. Of the coffee that costs \$40 and the coffee that needs 195°F % water, one steeps for 2 minutes and the other is Blue Mountain. ic:element(P40Coffee, Price, 40), ic:element(P40Coffee, Seconds, P40Seconds), ic_symbolic:element(P40Coffee, Name, P40Name), ic:element(T195Coffee, Temp, 195), ic:element(T195Coffee, Seconds, T195Seconds), ic_symbolic:element(T195Coffee, Name, T195Name), ( P40Seconds #= 120 and T195Name &= 'Blue Mountain' or T195Seconds #= 120 and P40Name &= 'Blue Mountain' ), % 8. Of the coffee that steeps for 3.5 minutes and the coffee that % requires 200°F water, one costs \$60 and the other is Blue Mountain. ic:element(S210Coffee, Seconds, 210), ic:element(S210Coffee, Price, S210Price), ic_symbolic:element(S210Coffee, Name, S210Name), ic:element(T200Coffee, Temp, 200), ic:element(T200Coffee, Price, T200Price), ic_symbolic:element(T200Coffee, Name, T200Name), ( S210Price #= 60 and T200Name &= 'Blue Mountain' or T200Price #= 60 and S210Name &= 'Blue Mountain' ), % Labeling ( foreach(Xs, [Price,Temp,Seconds]) >> foreach(X, Xs) do ic:indomain(X) ), % Result ( foreach(N,Name), foreach(P,Price), foreach(T,Temp), foreach(S,Seconds) do printf("%w costs \$%w and must be steeped at %wF for %w seconds\n", [N,P,T,S]) ).