Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Готовые отчеты / ЛиФП. Лабораторная работа 5

.pdf
Скачиваний:
67
Добавлен:
29.01.2021
Размер:
100.5 Кб
Скачать

Федеральное агентство связи ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ

ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ «САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ТЕЛЕКОММУНИКАЦИЙ ИМ. ПРОФ. М. А. БОНЧ-БРУЕВИЧА» (СПбГУТ)

Факультет инфокоммуникационных сетей и систем Кафедра программной инженерии и вычислительной техники

ЛАБОРАТОРНАЯ РАБОТА №5 по дисциплине «Логическое и функциональное программирование»

Выполнил: студент 3-го курса дневного отделения группы ИКПИ-85

Коваленко Леонид Александрович Преподаватель:

доцент кафедры ПИиВТ Ерофеев Сергей Анатольевич

Санкт-Петербург

2020

Постановка задачи

Написать программу на языке Turbo Prolog 2.0 для нахождения кратчайшего маршрута между двумя ячейками в лабиринте через заданные ячейки-монеты. Причем дважды проходить через одну и ту же ячейку нельзя.

Схема решения

Алгоритм основан на поиске в глубину (англ. Depth-first search, DFS). Алгоритм поиска описывается рекурсивно: перебираем всех соседей

текущей ячейки. Если ячейка-сосед ещё не была рассмотрена ранее и является свободной (не является стеной), то запускаем алгоритм от этой ячейки-соседа, а после возвращаемся и продолжаем перебирать других соседей. Конец рекурсии происходит в том случае, если все соседи были посещены или являются стенами. Пути, не содержащие все ячейки-монеты, не считаются результатом работы алгоритма, т. е. отбрасываются.

Этот алгоритм — пример алгоритма полного перебора. Достоинством является то, что результат получается точным. Недостатком является то, что время работы быстро возрастает с ростом свободных ячеек. Поэтому вполне приемлемым вариантом входных данных для алгоритма является лабиринт.

Код программы Входные данные поступают с клавиатуры либо файла, пример

содержимого которого приведен в табл. 1.

Таблица 1 — Входные данные в файле (слева) и описание ячеек (справа)

#####################

S — стартовая ячейка, с которой начинается путь

#

 

#

#

#

 

 

### #####

# ###

### #

F — финишная ячейка, на которой заканчивается путь

#

 

# S

# # #

 

 

# # # ##

# ###

# # #

* — ячейка-монета, через которую обязательно должен

# # # #

# # #

#

#

проходить путь

### # #

*## #

# ###

 

# # #

#

#

#

#

— пустая ячейка, через которую можно пройти

# #*

# #

### #

# # #

 

#F

*# #

#

 

# #

# — ячейка-стена, через которую нельзя пройти

#####################

 

Код программы приведен в табл. 2.

2

Таблица 2 — Код программы

NOWARNINGS

%Раздел описания доменов

DOMAINS

file = datafile % Файл datafile char_list = char* % Строка из символов matrix = char_list* % Матрица

pair = pair(integer, integer) % Пара значений координат (Left, Top) solution = pair* % Решение является массивом пар значений координат solutions = solution* % Множество решений

%Раздел описания предикатов

PREDICATES

length(matrix, integer) length(solution, integer) input(matrix) input_action(matrix, integer) read_matrix_from_console(matrix) read_matrix_from_file(matrix)

string_to_char_list(string, char_list) find_solution(matrix, solution) calc_stars_in_matrix(matrix, integer) calc_stars_in_list(char_list, integer) find_in_matrix(matrix, char, integer, integer) find_in_matrix(matrix, char, integer, integer, integer) find_in_list(char_list, char, integer, integer, integer)

find_in_list(char_list, char, integer, integer, integer, integer) find_path(matrix, integer, integer, integer, integer, integer, solution, solution) is_free_then_update(char, integer, integer)

contains(solution, pair) get(matrix, integer, char_list) get(char_list, integer, char) merge(solution, solution, solution) min_solution(solutions, solution) output(matrix, solution)

output_action(matrix, solution, integer) write_output_data(matrix, solution) write_output_data(matrix, solution, integer) write_row_with_solution(char_list, solution, integer)

write_row_with_solution(char_list, solution, integer, integer)

%Раздел описания внутренней цели

GOAL

input(InputMatrix), % Ввод исходных данных find_solution(InputMatrix, Solution), % Поиск минимального пути output(InputMatrix, Solution), % Вывод результата

readchar(_). % Завершение программы после нажатия клавиши клавиатуры

%Раздел описания предложений

CLAUSES

%Длина списка length([], 0). length([_|Xs], N) :-

length(Xs, P), N = P + 1.

%Ввод исходных данных input(Matrix) :-

write("-== MENU ==-"), nl, write("1. Read from console;"), nl, write("2. Read from file."), nl, write("Another button to exit"), nl,

readint(C), % Считывание целого числа input_action(Matrix, C), % Ввод length(Matrix, Length), Length >= 3;

write("Invalid input!"), nl, fail. % Если неверный ввод

%Ввод из диалогового окна

input_action(Matrix, 1) :- read_matrix_from_console(Matrix).

% Ввод из файла input_action(Matrix, 2) :-

write("File name: "), readln(FileName), % Ввод названия файла

existfile(FileName), % Существует ли файл openread(datafile, FileName), % Открытие файла для чтения readdevice(datafile), % Перенаправление ввода на файл read_matrix_from_file(Matrix), % Чтение closefile(datafile), !; % Закрытие файла

3

write("Error reading file!"), nl, fail.

% Чтение с консоли read_matrix_from_console([Head|Tail]) :-

write(">"), readln(T), % Чтение строки

string_to_char_list(T, Head), % Преобразование в список символов read_matrix_from_console(Tail).

read_matrix_from_console([]).

% Чтение с файла read_matrix_from_file([Head|Tail]) :-

readln(T), % Чтение строки

string_to_char_list(T, Head), % Преобразование в список символов read_matrix_from_file(Tail).

read_matrix_from_file([]).

%Конверт строки в список символов string_to_char_list("", []). string_to_char_list(String, [Head|ListTail]) :-

frontchar(String, Head, StringTail), % Head - первый символ, StringTail - остальные string_to_char_list(StringTail, ListTail).

%Поиск пути и генерация результата

find_solution(InputMatrix, Solution) :-

calc_stars_in_matrix(InputMatrix, Stars), % Считаем кол-во звездочек (монет) find_in_matrix(InputMatrix, 83, StartL, StartT), % Находим 'S' = 83 find_in_matrix(InputMatrix, 70, FinishL, FinishT), % Находим 'F' = 70

StartL >= 0, StartT >= 0, FinishL >= 0, FinishT >= 0, !, % Проверка (-1, если было

неуспешно find_in_matrix)

% Находим все решения

findall(List, find_path(InputMatrix, Stars, StartL, StartT, FinishL, FinishT, [], List), Solutions),

min_solution(Solutions, Solution). % Находим минимальное из всех решений

%Подсчет числа звездочек (монет) в матрице calc_stars_in_matrix([Head|Tail], N) :-

calc_stars_in_list(Head, NS), % Ищем в текущей строке calc_stars_in_matrix(Tail, NT), % Рекурсивно по каждой строке

N = NS + NT. % Суммируем calc_stars_in_matrix([], 0).

%Подсчет числа звездочек (монет) в списке

calc_stars_in_list([Head|Tail], N) :-

Head = 42, % Если текущий символ - '*' calc_stars_in_list(Tail, N1), % Рекурсивно смотрим хвост N = 1 + N1, !; % Подсчитываем

calc_stars_in_list(Tail, N). % Иначе просто рекурсивно смотрим хвост calc_stars_in_list([], 0).

% Поиск символа в матрице символов find_in_matrix([], _, -1, -1). find_in_matrix(Matrix, Char, Left, Top) :-

find_in_matrix(Matrix, Char, 0, Left, Top).

find_in_matrix([Head|Tail], Char, T, Left, Top) :- find_in_list(Head, Char, T, Lr, Tr), % Ищем в списке

Lr >= 0, Tr >= 0, Left = Lr, Top = Tr, !; % Если элемент найден

NewT = T + 1, find_in_matrix(Tail, Char, NewT, Left, Top). % Иначе смотрим другие строки find_in_matrix([], _, _, -1, -1).

% Поиска символа в списке символов find_in_list([], _, _, -1, -1). find_in_list(List, Char, T, Left, Top) :-

find_in_list(List, Char, 0, T, Left, Top).

find_in_list([], _, _, _, -1, -1). find_in_list([Head|Tail], Char, L, T, Left, Top) :-

Head = Char, Left = L, Top = T, !; % Если элемент найден

L1 = L + 1, find_in_list(Tail, Char, L1, T, Left, Top). % Иначе смотрим другие строки

% Нахождение пути

find_path(_, 0, CurrentL, CurrentT, CurrentL, CurrentT, SList, List) :-

List = SList, !. % Если все звездочки собраны и мы в нужной точке, то нужный путь найден find_path(_, _, CurrentL, CurrentT, CurrentL, CurrentT, _, _) :-

!, fail. % Если не все звездочки собраны и мы в нужной точке, то нужный путь не найден find_path(InputMatrix, Stars, CurrentL, CurrentT, FinishL, FinishT, SList, List) :-

% Если слева свободная ячейка (не '#'), то рекурсия туда

C = CurrentL - 1, not(contains(SList, pair(C, CurrentT))),

get(InputMatrix, CurrentT, CurrentList), get(CurrentList, C, X), is_free_then_update(X, Stars, S),

merge([pair(C, CurrentT)], SList, MList),

find_path(InputMatrix, S, C, CurrentT, FinishL, FinishT, MList, List);

4

% Если справа свободная ячейка (не '#'), то рекурсия туда C = CurrentL + 1, not(contains(SList, pair(C, CurrentT))),

get(InputMatrix, CurrentT, CurrentList), get(CurrentList, C, X), is_free_then_update(X,

Stars, S),

merge([pair(C, CurrentT)], SList, MList),

find_path(InputMatrix, S, C, CurrentT, FinishL, FinishT, MList, List);

% Если сверху свободная ячейка (не '#'), то рекурсия туда C = CurrentT - 1, not(contains(SList, pair(CurrentL, C))),

get(InputMatrix, C, CurrentList), get(CurrentList, CurrentL, X), is_free_then_update(X, Stars, S),

merge([pair(CurrentL, C)], SList, MList),

find_path(InputMatrix, S, CurrentL, C, FinishL, FinishT, MList, List);

% Если снизу свободная ячейка (не '#'), то рекурсия туда

C = CurrentT + 1, not(contains(SList, pair(CurrentL, C))),

get(InputMatrix, C, CurrentList), get(CurrentList, CurrentL, X), is_free_then_update(X,

Stars, S),

merge([pair(CurrentL, C)], SList, MList),

find_path(InputMatrix, S, CurrentL, C, FinishL, FinishT, MList, List).

%Проверка на пустоту и изменение Stars (если нужно) is_free_then_update(X, Stars, S) :-

X = 42, !, S = Stars - 1; % Если '*', то обновляем Stars

not(X = 35), S = Stars. % Если не '*' и не '#', то не обновляем Stars (иначе fail)

%Содержит ли список элемент X

contains([X|_], X).

contains([_|Tail], X) :- contains(Tail, X). contains([], _) :- fail.

%Получение элемента списка по индексу get([Head|_], 0, X) :- X = Head.

get([_|Tail], I, X) :- I1 = I - 1, get(Tail, I1, X). get([], _, _) :- fail.

%Объединение двух списков

merge([H|Xs], Zs, [H|Ts]) :- merge(Xs, Zs, Ts). merge([], Zs, Zs).

%Поиск минимального решения min_solution([Min], Min). min_solution([Head, Next|T], M) :-

length(Head, HL), length(Next, NL), HL <= NL,

min_solution([Head|T], M). min_solution([Head, Next|T], M) :-

length(Head, HL), length(Next, NL), HL > NL,

min_solution([Next|T], M).

%Вывод результата

output(InputMatrix, Solution) :- write("1. Write to console;"), nl, write("2. Write to file."), nl, write("Another button to exit"), nl, readint(C), % Считывание числа

output_action(InputMatrix, Solution, C); % Вывод write("The program = complete.").

% Вывод в диалоговое окно output_action(InputMatrix, Solution, 1) :-

write_output_data(InputMatrix, Solution).

% Вывод в файл

output_action(InputMatrix, Solution, 2) :- write("File name: "), readln(FileName), % Ввод названия файла

openwrite(datafile, FileName), % Открытие файла для записи writedevice(datafile), % Перенаправление вывода на файл write_output_data(InputMatrix, Solution), % Вывод closefile(datafile). % Закрытие файла

% Вывод результата в файл в виде write_output_data([], []).

write_output_data(Matrix, Solution) :- write_output_data(Matrix, Solution, 0).

write_output_data([Head|Tail], Solution, N) :- write_row_with_solution(Head, Solution, N), nl, % Запись строки N1 = N + 1, % Переход к следующей

write_output_data(Tail, Solution, N1).

5

write_output_data([], Solution, N).

write_row_with_solution(List, Solution, N) :- write_row_with_solution(List, Solution, N, 0). write_row_with_solution([], Solution, N).

write_row_with_solution([Head|Tail], Solution, N, M) :-

Head = 32, contains(Solution, pair(M, N)), % Если пробел и есть в решении, записываем + write("+"), M1 = M + 1, write_row_with_solution(Tail, Solution, N, M1), !; write(Head), M1 = M + 1, % Иначе просто записываем исходный символ write_row_with_solution(Tail, Solution, N, M1).

write_row_with_solution([], Solution, N, M).

Тестирование

Результаты тестирования представлены в табл. 3. Таблица 3 — Результаты тестирования

 

Входные данные

Выходные данные

 

 

 

 

 

 

###############

 

###############

 

 

#S

 

#

 

 

#

 

#S+++++#

 

+++#

 

 

#

#

#

 

 

*#

 

#

 

#+#

 

++*#

 

 

#

# #

 

 

*F#

 

#

 

#+#

 

+*F#

 

 

#

#

 

 

 

*#

 

#

 

#+++++++*#

 

 

###############

 

###############

 

 

 

#####################

#####################

#

 

 

 

#

 

#

#

#

 

 

 

#

#

#

### #####

#

###

### #

### #####

#

### ### #

#

 

 

# S

 

# # #

#

 

 

#

 

S++# # #

#

# # ##

# ###

# # #

# # # ##

#

###+# # #

# # # #

# # # #

#

# # # #

 

# # #+#

#

### # #

*##

#

# ###

### # #+++*## #+# ###

# # #

#

 

 

#

#

#

# # #+++#

++++#+#

#

# #*

# #

###

#

# # #

# #*++# #

###+#+# # #

#F

 

*# #

 

#

 

 

# #

#F+++*# #

 

#+++

# #

#####################

#####################

 

 

#####################

#####################

#F

 

 

 

 

#

 

#

#F++++

 

+++++#

#

# ###*###*###

### ###

# ###*###*###+### ###

#

 

 

 

#

 

 

#

#

+++++ # +++

#

# # # *######

#

# # #

# # #+*###### #+# # #

#

#

# #

 

# # # #

#

#

# #

 

#+# # #

### # # #

# ###

### #

### # # #

#

###+### #

# #

#

#

 

#

 

#

# #

#

 

#

 

#+++

#

# #######

###

### ###

# #######

### ###+###

#

 

 

#

 

#

 

S#

#

 

 

#

 

# ++S#

#####################

#####################

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

6

 

Входные данные

Выходные данные

 

 

#####################

#####################

#

 

 

 

 

#

#

#

 

#

#

# ###

###

#### ## ###

# ### ### #### ## ###

#

*S

#

#

 

 

# #

#++*S # #

 

# #

# #####

#

###

##### #

#+##### # ### ##### #

#

 

 

#

 

 

# #

#+++ +++#

 

# #

# # #

#

#

## ###### #

# #+#+#+# ## ###### #

# # *

#

 

 

 

#

# #+*+#+++++++ +++

#

# # #

#

#

# #

# # ###

# # # # # # #+#+#+###

#

 

 

 

# #

* #

F#

#

 

# #+*+#++F#

#####################

#####################

 

 

#####################

#####################

# #

 

#

 

#

#

# #

#

#+++++#

# # ###

#

###

# ### #

# # ### # ### #+###+#

# #*

#F

 

#

*#

#

# #*++#F

 

#++++*#+++#

# # #

#

### ##### # #

# #+#+#+###+#####+# #

#

*#

 

#

 

#*

# #

#++*#+++#+++ #*++# #

# # #

###

###

# ### #

#+# # ###+### #+### #

# # #

 

 

# #

#

#

#+# #

 

+# # #+ +++#

#*# #

###

# #

# # # #

#*# # ###+# # #+#+#+#

#

*

 

 

* #

*

#S#

#++*+++++* # *++#S#

#####################

#####################

Более интересный лабиринт приведен в табл. 4. Таблица 4 — Лабиринт 95x25

###############################################################################################

#S

 

#

# #

 

 

 

 

#

 

 

#

#

 

#

 

 

 

#

#

 

#

 

#

# #

#

#######

#

###

#

#######

### ###

### # # ###

### # ###

### #####

### ###

### ##### ##### # # ###

#

 

#

 

# # #

 

 

 

#

 

#

# #

 

#

# #

# #

 

 

#

 

# #

 

#

# # #

# ###

#

#

#####

# ###

##### #

###

# # ####### #####

### # # ###

##### ###

# #

#######

### # # #

# #

# #

 

 

 

# # #

# # # # #

 

# #

# #

# #

#

 

# #

 

#

#

 

#

#

### ###*### ###

###

#

#

#####

#

# # #######

# #

###

#

#########

# #####

### #########

# # # ###

# #

 

 

# #

# # # #

#

 

# #

#

# #

 

#

# # # # #

 

# # #

# # # #

#

# #####

#####

#

#######

#

# #

################# ####### # # #

#

# # # #

#

# # #####

# # ##### #

#

# #

 

#

 

#

 

 

#

 

#

# #

 

#

 

 

# # # #

 

#

# # #

#

# # #

#

#######

#####

#

#######

######### # ### #

##### ###

#

##### ######### ###

###

# ### ### #######

#

 

# #

# #

 

 

#

 

 

 

#

#

 

#

# # # #

#

 

#

# #

# # #

 

# # #

#

# ###

###

###

#

###

#####

###

###########

#

#########

# # # ###

# #####

#

###

### ###

# # ### #

# # #

 

 

 

# #

#

 

# # #

 

 

# # #

 

# # # # #

# #

 

# #

 

#

#

#

#

#

# # #

###

# ##### #####

### #

##### ### ##### # # #

#

### ######### ###

### #

# #####

##### # #

# # # #

 

# # #

#

 

 

# #

#

 

 

 

 

#

# # #

 

# #

# # # #

 

# # # #

### # ###

# #

#####

#

###

########### ###

#

#######

#

### # #

### # # ###

# ########### # # ###

# #

 

# #

# # # #

 

# # #

 

 

# #

#

 

#

# #

 

# # # # #

 

 

#

#

# ### #

#

###

#

# #

#

#

#

# #

#

#########

#

##### ####### ###

#

##### #

#

################### #

#

# #

# #

 

# #

 

#

# # #

# #

#

 

#

#

 

#

# # #

 

 

* # #

### ####### ###

###

###

######### # #######

# # ###

####### ###

### #####

# # #######

### # # #

# #

 

 

#

 

# # # #

# #

 

# #

 

# #

 

# #

#

 

#

 

#

#

 

# #

#

# #######

####### #

#

###

###

#

####### #

##### ###

#

# # ###

####### #

#

# #

### ####### # # #

# #

 

 

 

 

#

 

#

 

 

 

#

 

 

#

 

#

# #

 

#

 

#

# #

 

# # #F#

###############################################################################################

Решение этого лабиринта приведено в табл. 5.

7

Таблица 5 — Найденный кратчайший путь в лабиринте 95x25

###############################################################################################

#S++++++#

#

#+++++++++++++#

+++++++#

 

#+++++#+++++++++++++++#

#

 

#

 

#

#

#

#

#######+#

###

#+#######

###+###+### #+# ###+###+#+###

### #####+### ###

### ##### #####

# # ###

#

 

+#

 

#+# #

 

 

 

#+++++#

#+#

 

+++#+++#

#

 

# #

 

+

 

#

 

# #

 

#

 

# # #

# ###

#+#

#####+# ###

##### #

### #

#+#######+#####

### # #

###+##### ###

# #

####### ### # # #

# #

 

#+#

+++++

 

#

#

#

#

# # #

#+++++++#+# #

#

 

# #

 

#+++

# #

 

#

#

 

#

 

#

### ###*###+###

###

#

#

#####

# # #

#######+#+# ###

#

#########

#+#####

### ######### #

# # ###

#

#

+++++#

#

#

#

#

#

#

# #

 

 

#+++# #

 

#

 

 

#

#+# # #

 

# #

#

# #

# #

#

# ##### #####

#

#######

#

# #

################# ####### # #

#

#

#+# # #

#

# #

#####

# #

##### #

#

 

# #

 

#

 

#

 

 

#

#

#

#

 

#

 

# # #

#

 

#+++++#

#

#

#

# #

 

#

#

####### #####

#

#######

######### #

### #

##### ###

#

#####

#########+###

###

# ### ###

#######

#

 

#

#

#

#

 

 

#

 

#

 

 

#

#

#

# # #

 

#

#

+++#

#

# # #

#

# #

#

# ###

###

###

#

###

#####

###

###########

# #########

# # #

###

# #####+#

###

### ### #

# ### #

# # #

 

 

# #

#

 

# # #

#

# #

# # # # #

 

#

#

 

# # +

 

#

#

#

 

#

#

# # #

###

# ##### #####

### #

#####

### ##### # # #

#

### ######### ###+### #

# ##### ##### # #

# # #

#

# # #

#

 

 

# #

#

 

 

 

#

#

#

#

 

 

#

#+++#

# # #

 

# # # #

### #

###

# #

#####

#

###

########### ###

# #######

#

### # #

### # #+###

# ###########

# # ###

# #

 

# #

# # # #

 

# # #

 

 

# # #

#

 

 

# #

# #+# # #

 

#

 

 

#

# ###

# #

###

#

# #

#

#

#

# #

# #########

# ##### ####### ###

#

#####+#

#

################### #

#

 

# #

#

#

 

#

#

 

#

# #

#

 

# #

#

 

 

#

 

#

#+++

#

# #+++++++++++++*+# #

### ####### ###

###

###

######### #

####### # # ###

#######

###

###+#####

# #+####### ### #+# #

#

#

 

#

 

#

#

#

#

#

#

#

#

 

# #

 

#

#

 

#

 

+++#+++#+++

#

 

# #+++#

# #######

####### #

#

###

###

# ####### #

##### ###

#

# # ###

#######+#+#+#+#

### ####### # #+#

#

#

 

 

 

#

 

#

 

 

#

 

 

#

 

#

 

# #

 

 

#

+++#+++#

#

#

 

# #F#

###############################################################################################

Выводы В результате выполнения лабораторной работы мы разработали

программу на языке Turbo Prolog 2.0 для нахождения кратчайшего маршрута между двумя ячейками в лабиринте через заданные ячейки-монеты. Было проведено тестирование отдельных предикатов и всей программы в целом. Программа полностью удовлетворяет заданным требованиям.

8