Решение головоломки Zebra (она же головоломка Эйнштейна) с использованием библиотеки Prolog clpfd

Мне дали задание решить головоломку с зеброй, используя решатель ограничений по моему выбору, и я попробовал его, используя библиотеку Prolog clpfd.

Я знаю, что есть и другие, более идиоматические способы решения этой проблемы в Прологе, но этот вопрос конкретно касается пакета clpfd!

Итак, конкретный вариант головоломки (учитывая, что их много), который я пытаюсь решить, таков:

Есть пять домов

  1. Англичанин живет в красном доме
  2. Шведы владеют собакой
  3. Датчане любят пить чай
  4. Зеленый дом оставлен белому дому
  5. Хозяин оранжереи пьет кофе
  6. Человек, который курит Pall Mall, владеет птицей
  7. В среднем доме пьют молоко
  8. Хозяин желтого дома курит Dunhill
  9. Норвежец живет в первом доме
  10. Курильщик мальборо живет рядом с владельцем кошки
  11. Хозяин лошади живет рядом с человек, который курит dunhill
  12. Курильщик Winfield любит пить пиво
  13. Норвежец живет рядом с голубым домом
  14. Немец курит rothmanns
  15. У курильщика мальборо есть сосед, который пьет воду

Я пытался решить ее следующим образом:

Каждый атрибут, который может иметь дом, моделируется как переменная, например "британский", "Собака", "Зеленый" и т.д. Атрибуты могут принимать значения от 1 до 5, в зависимости от дома в котором они происходят, т.е. если переменная «Собака» принимает значение 3, то собака живет в третий дом.

Этот подход упрощает моделирование ограничений соседей следующим образом:

def neighbor(X, Y) :-
    (X #= Y-1) #\/ (X #= Y+1).

Но каким-то образом пакет clpfdне дает решения, хотя (IMO) проблема смоделирована правильно (я использовал точно такая же модель с решателем ограничений Choco, и результат был правильным).

Вот полный код:

:- use_module(library(clpfd)).

neighbor(X, Y) :-
    (X #= (Y - 1)) #\/ (X #= (Y + 1)).

solve([British, Swedish, Danish, Norwegian, German], Fish) :-

    Nationalities = [British, Swedish, Danish, Norwegian, German],
    Colors = [Red, Green, Blue, White, Yellow],
    Beverages = [Tea, Coffee, Milk, Beer, Water],
    Cigarettes = [PallMall, Marlboro, Dunhill, Winfield, Rothmanns],
    Pets = [Dog, Bird, Cat, Horse, Fish],

    all_different(Nationalities),
    all_different(Colors),
    all_different(Beverages),
    all_different(Cigarettes),
    all_different(Pets),

    Nationalities ins 1..5,
    Colors ins 1..5,
    Beverages ins 1..5,
    Cigarettes ins 1..5,
    Pets ins 1..5,

    British #= Red, % Hint 1
    Swedish #= Dog, % Hint 2
    Danish #= Tea, % Hint 3

    Green #= White - 1 , % Hint 4
    Green #= Coffee, % Hint 5,
    PallMall #= Bird, % Hint 6

    Milk #= 3, % Hint 7
    Yellow #= Dunhill, % Hint 8,
    Norwegian #= 1, % Hint 9

    neighbor(Marlboro, Cat), % Hint 10
    neighbor(Horse, Dunhill), % Hint 11
    Winfield #= Beer, % Hint 12

    neighbor(Norwegian, Blue), % Hint 13
    German #= Rothmanns, % Hint 14,
    neighbor(Marlboro, Water). % Hint 15

Я неправильно понял концепцию в clpfd, или я просто упустил что-то очевидное? Если это поможет, здесьвы можете найти тот же подход, реализованный с использованием Choco и Scala.


Редактировать: Причина, по которой я считаю, что решатель не может решить проблему, заключается в том, что он никогда не дает определенных значений для переменных, а только с диапазонами, например. «Рыба 1..3/5».

7
задан false 24 November 2013 в 16:04
поделиться