среда, 25 января 2012 г.

Системы искусственного интеллекта. SWI-Prolog + Qt

В этой статье я бы хотел поговорить о ещё одном предмете, который преподаётся в 1 семестре 4 курса. Называется он системы искусственного интеллекта=)


Суть курса передать очень трудно, потому что особо ничего не было понятно с самого начала и до конца)


А рассказать хочется о семестровой работе, в которой было необходимо написать игру с искусственным интеллектом на прологе. К слову, писали мы её около 2-3 недель в конце декабря-начале января, уже после зачёта.
Мы выбрали игру "Поддавки" и основным мотивом было то, что у нас был неплохой пример=)
Задачу осложняло то, что этот пример был дважды сдан однокурсниками и дважды преподаватель их спалил)


Пример был взят отсюда - визуальная часть на Delphi, интеллект на прологе.


Переписывание я начал с визуальной части. Так как мы довольно много пишем на С++ с Qt, и есть опыт, я решил, что это будет самым быстрым и практичным вариантом. Однако самому писать не хотелось, поэтому интерфейс был выпилен отсюда.


Сразу встал вопрос о связи визуальной части и интеллекта. Гугл выдал несколько вариантов, но самым практичным оказался этот.


В первой части я попытаюсь переписать его в нормальном стиле и укажу некоторые проблемы, которые возникли у меня.


Часть 1. Связь SWI-Prolog и Qt.


Для разработки использовался Qt Creator и SWI-Prolog.
Итак, первое что нам необходимо сделать - скачать SWI-Prolog с их официального сайта.
Отмечу, что у меня на 64х битной Windows версия пролога для 64 не заработала, так что нужно качать версию для 32!
После скачки её необходимо установить(желательно в стандартную папку).


Чтобы начать использование SWI в Qt, необходимо скопировать некоторые файлы из папки, в которую мы его установили, в папку с нашим проектом. В нашем проекте папка называется swi-prolog. Копируем папки lib и include полностью и из папки bin 2 файла - swipl.dll и pthreadVC.dll.
Внимание! эти 2 .dll файла необходимо помещать в папку, где находится запускаемый файл! Без них проект работать не будет и будет выдавать "During startup program exited with code 0xc0000135".

Далее необходимо сделать инклуд библиотеки и include-файлов в файл qt-проекта .pro:


LIBS += ./swi-prolog/bin/swipl.dll
INCLUDEPATH += ./swi-prolog/include


Теперь перейдём к коду.
1.Прописать переменные среды. В них нужно указать путь к установленному SWI-Prolog и сделать это можно так:

  1. char env[] = "SWI_HOME_DIR=C:\\Program Files\\pl";
  2. putenv(env);

2. Заинклудить .dll файл swi-prolog'а.

  1. //инклуд файла
  2. static char * av []  =  {"libpl.dll"NULL} ;
  3. if (PL_initialise(1 , av) == 0)
  4. {
  5.     PL_halt(1);
  6.     qDebug() << "lib initialize error -(";
  7. }
  8. else
  9.     qDebug() << "lib initialize ok!";

3. Подключим файл с интеллектом. Здесь стоит сказать, что любые сообщения, которые мы посылаем через PlCall(подробнее можно прочитать на оф.сайте swi-prolog'а), необходимо заключать в блоки try{}catch(){}.

  1. //открытие файла пролога
  2. try
  3. {
  4.      if(PlCall("call", PlTermv(PlCompound("consult('Anti-checkers.pl')"))))
  5.          qDebug() << "database opening ok!";
  6.      else
  7.          qDebug() << "database opening fail!";
  8. }
  9. catch (PlException & ex)
  10. {
  11.     QMessageBox::warning(this"Prolog Exception", QString("Prolog has thrown an exception:") + QString((char *)ex));
  12. }



Всё! Теперь мы можем обращаться с запросами к файлу интеллекта.
Рассмотрим подробнее наш пример.


PlCall - это макрос, он отправляет запрос - это первый аргумент(retractall), а второй - это принимаемые им аргументы. Данный запрос удалит все данные о computer_checker из базы. Обратная операции удаления - операция записи, называется assert. 

  1. //обнуляем значения
  2. PlCall("retractall", PlTermv(PlCompound("computer_checker(_,_)")));


Здесь стоит отметить, что если мы хотим узнать что-нибудь из базы, например, проверить справедливость утверждения, нам нужно проверять возвращаемое PlCall-ом значение.


Пример: мы хотим, чтобы значение в массиве было WHITE, если на этих координатах находится пешка игрока (player_checker). Это будет выглядеть так:

  1. PlTermv args = PlTermv(PlCompound(str_i), PlCompound(str_j));
  2. if(PlCall("player_checker", args))
  3.     checkers[i][j] = WHITE;



На этом я пожалуй закончу. О второй части - организации и реализации интеллекта мы поговорим чуть позже с Евгением Ли, который был ответственным за эту часть.


Ссылка на репозиторий:
http://code.google.com/p/poddavki/

3 комментария:

  1. очень интересный обзор.
    я ломаю голову над подобной проблемой, я хочу подключить swi-prolog к microsoft visual studio, но совсем не знаю как это сделать. есть ли какие-нибудь соображения на данный счет?

    ps я правильно понимаю что если я сделаю это то я смогу использовать возможности пролога программируя в MVS ??

    ОтветитьУдалить
    Ответы
    1. Смотря к какому проекту нужно подключить. Вот здесь есть варианты подключения к
      c#, c++, и другим.
      http://www.swi-prolog.org/contrib/
      Если подключите - то да, безусловно, всё будет работать.

      Удалить
  2. Интересно бы продолжение темы..

    ОтветитьУдалить