Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
PROLOG.DOC
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
502.27 Кб
Скачать

9.2. Макетування: задача маршрутизації.

Ця програма ілюструє особливості Прологу, які роблять його корисним при вирішенні задач макетування. Припустимо , ми хочемо створити систему, яка б допомогала вибрати маршрут при поїздці із одного міста в інше.

Початкову програму будемо використовувати для подальшого аналізу вирішення поставленої задачі.

Нас будуть цікавити питання типу:

* Чи існує пряма дорога з одного міста в інше?

* Які з міст знаходяться на віддалі меншій 10 км від конкретного міста?

Нехай ми будемо реалізовувати карту прототипу, зображену на мал.9.2.

KansasCity

O---------------

Gordon

O--------- O Houston --------O Tampa

Мал.9.2. Карта прототипу.

Наступна програма є класичним прикладом використання бектрекінгу і рекурсії для вирішення задачі планування маршруту.

domains

town = symbol

distance = integer

predicates

road(town, town, distance)

route(town, town, distance)

clauses

road(tampa, houston, 200).

road(gordon, tampa, 300).

road(houston, gordon, 100).

road(houston, kansas_city, 120).

road(gordon, kansas_city, 130).

route(Town1, Town2, Distance) :-

road(Town1, Town2, Distance).

route(Town1, Town2, Distance) :-

road(Town1, X, Dist1),

route(X, Town2, Dist2),

Distance=Dist1+Dist2, !.

Кожна фраза для предикату road є фактом, який описує дорогу із одного міста в інше, довжина якої визначається в кілометрах. Фрази route характеризують те, чи можна створити маршрут із одного міста в інше через декілька проміжних пунктів. Третій параметр визначає пройдену відстань між містами.

Предикат route визначається рекурсивно; маршрут може просто складатись із одного проміжку дороги ( перша фраза). В цьому випадку віддаль буде довжиною дороги. Ми також можемо сконструювати маршрут із Town1 в Town2, використовуючи проміжний пункт Х. Загальна віддаль буде тоді сумою віддалей між Town1 і Х а також із Х в Town 2, що й показано в другій фразі route.

При подальшому аналізі задачі на складнішій структурі міст приходимо до необхідності вирішення наступних проблем:

1.Пролог система не повинна вибирати маршрут, який приводить до відвідин одного міста двічі.

2.Попередження переміщень по колу, яке дасть впевненість в тому, що програма не прийде до нескінченного циклу. Ці проблеми досить просто можна вирішити, якщо ми в програмі створимо і будемо заповнювати, а потім аналізувати список міст, які вже були відвідані при прокладенні маршруту. Приклад реалізації такого списку приводиться далі.

9.3.Пригоди в дивних печерах.

Розв'яжемо модифіковану задачу пошуку шляху в лабіринті. Нехай ми маємо печеру з скарбами. Печера є лабіринтом галлерей, які з'єднують кімнати з монстрами та грабіжниками. В одній з кімнат знаходяться скарби. Будемо вважати, що вам треба зайти в печеру, забрать скарби і вийти живим з лабіринту. Розглянемо наступну карту печери:

Мал. 20.2. Лабіринт галлерей.

domains

room = symbol

roomlist = room*

predicates

gallery(room, room) /* існує коридор */

/* між двома кімнатами */

neighborroom(room, room) /* Визначення */

/* сусідських */

/* кімнат */

avoid(roomlist)

go(room, room)

route(room, room, roomlist) /* Тут roomlist */

/* містить кімнати */

/* відвідані */

member(room, roomlist)

clauses

gallery(entry, monsters).

gallery(entry,fountain).

gallery(fountain, hell).

gallery(fountain, food).

gallery(exit, gold_treasure).

gallery(fountain, mermaid).

gallery(robbers, gold_treasure).

gallery(fountain, robbers).

gallery(food, gold_treasure).

gallery(mermaid, exit).

gallery(monsters, gold_treasure).

gallery(gold_treasure,exit).

neighborroom(X, Y) :- gallery(X, Y).

neighborroom(X, Y) :- gallery(Y, X).

avoid([monsters, robbers]).

go(Here, There) :- route(Here, There, [Here]).

go(_, _).

route(Room, Room, VisitedRooms) :-

member(gold_treasure, 6 0VisitedRooms),

write(VisitedRooms), nl.

route(Room, Way_out, VisitedRooms):-

neighborroom(Room, Nextroom),

avoid(DangerousRooms),

not(member(NextRoom, DangerousRooms)),

not(member(NextRoom, VisitedRooms)),

route(NextRoom, Way_out, [NextRoom|VisitedRooms]).

member(X, [X|_]).

member(X, [_|H]) :- member (X, H).

Кожна печера описана фактом. Предикати go і route задають правила. Задавши програмі ціль go(entry,exit), отримаємо відповідь. Вона буде містити список кімнат, які ми повинні пройти, щоб забрати скарби і повернутись. Як ми і говорили, в попередньому розділі для усунення вад минулої програми використовується список уже пройдених кімнат. Ця дія виконується в рекурсивному предикаті route третім аргументом. Тому, якщо ви знаходитесь в кімнаті виходу, і цей список містить кімнату gold_treasure , тоді ви досягли поставленої мети.

Звернемо вашу увагу на наступне. Враховуючи нашу побудову предикату route, якщо задача може мати і декілька розв'язків, програма буде завжди видавати тільки один розв'язок. Для видачі всіх можливих розв'язків нам потрібно організувати бектрекінг за допомогою предикату fail в першому правилі визначення route:

route(Room,Room,VisitedRooms):-

member(gold_treasure, VisitedRooms),

write(VisitedRooms), nl, fail.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]