You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

427 lines
21 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

% ===============================================
% LAB9 TASK3 - МОДУЛЬНЫЕ РЕШЕНИЯ ЗАДАЧ С МАССИВАМИ
% Вариант 4: Задачи 4, 16, 28
% ===============================================
% ===============================================
% ЗАДАЧА 4: Индексы элементов в убывающем порядке
% ===============================================
/**
* task4_main(-Result)
* Главный предикат задачи 4: находит индексы массива в порядке убывания элементов
*
* @param Result - список индексов в порядке убывания элементов (неунифицированная)
*
* Назначение: Объединяет чтение, логику и вывод для задачи 4
* При вызове: Result неунифицированная
* По завершении: Result содержит отсортированные по убыванию элементов индексы
*/
task4_main(Result) :-
task4_read(List),
task4_logic(List, Result),
task4_output(Result).
/**
* task4_read(-List)
* Предикат чтения для задачи 4
*
* @param List - считанный список (неунифицированная переменная)
*
* Назначение: Читает массив с клавиатуры
* При вызове: List неунифицированная
* По завершении: List содержит введенные пользователем элементы
*/
task4_read(List) :-
write('Введите элементы массива (завершите ввод точкой): '), nl,
read_list(List).
/**
* task4_logic(+List, -SortedIndices)
* Предикат логики работы для задачи 4
*
* @param List - исходный список (унифицированная переменная)
* @param SortedIndices - индексы в порядке убывания элементов (неунифицированная)
*
* Назначение: Создает пары (индекс, элемент), сортирует по убыванию элементов, извлекает индексы
* При вызове: List унифицированная с исходным массивом, SortedIndices неунифицированная
* По завершении: SortedIndices содержит индексы (начиная с 1) в порядке убывания соответствующих элементов
*/
task4_logic(List, SortedIndices) :-
create_index_value_pairs(List, 1, Pairs),
sort_pairs_by_value_desc(Pairs, SortedPairs),
extract_indices(SortedPairs, SortedIndices).
/**
* task4_output(+Result)
* Предикат вывода для задачи 4
*
* @param Result - результирующий список индексов (унифицированная переменная)
*
* Назначение: Выводит результат на экран
* При вызове: Result унифицированная со списком индексов
* По завершении: результат выведен, переменные остаются без изменений
*/
task4_output(Result) :-
write('Индексы в порядке убывания элементов: '), write(Result), nl.
% ===============================================
% ЗАДАЧА 16: Элементы между первым и вторым максимальным
% ===============================================
/**
* task16_main(-Result)
* Главный предикат задачи 16: находит элементы между первым и вторым максимальным
*
* @param Result - элементы между первым и вторым максимумом (неунифицированная)
*
* Назначение: Объединяет чтение, логику и вывод для задачи 16
* При вызове: Result неунифицированная
* По завершении: Result содержит элементы между первым и вторым максимумом
*/
task16_main(Result) :-
task16_read(List),
task16_logic(List, Result),
task16_output(Result).
/**
* task16_read(-List)
* Предикат чтения для задачи 16
*
* @param List - считанный список (неунифицированная переменная)
*
* Назначение: Читает массив с клавиатуры
* При вызове: List неунифицированная
* По завершении: List содержит введенные пользователем элементы
*/
task16_read(List) :-
write('Введите элементы массива (завершите ввод точкой): '), nl,
read_list(List).
/**
* task16_logic(+List, -ElementsBetween)
* Предикат логики работы для задачи 16
*
* @param List - исходный список (унифицированная переменная)
* @param ElementsBetween - элементы между первым и вторым максимумом (неунифицированная)
*
* Назначение: Находит максимальный элемент, первую и вторую его позицию, извлекает элементы между ними
* При вызове: List унифицированная с исходным массивом, ElementsBetween неунифицированная
* По завершении: ElementsBetween содержит элементы между первым и вторым вхождением максимума
*/
task16_logic(List, ElementsBetween) :-
find_max_element(List, MaxElement),
find_first_occurrence(List, MaxElement, 1, FirstPos),
( find_second_occurrence(List, MaxElement, 1, FirstPos, SecondPos) ->
extract_elements_between_positions(List, FirstPos, SecondPos, ElementsBetween)
; ElementsBetween = []
).
/**
* task16_output(+Result)
* Предикат вывода для задачи 16
*
* @param Result - результирующий список элементов (унифицированная переменная)
*
* Назначение: Выводит результат на экран
* При вызове: Result унифицированная со списком элементов
* По завершении: результат выведен, переменные остаются без изменений
*/
task16_output(Result) :-
write('Элементы между первым и вторым максимальным: '), write(Result), nl.
% ===============================================
% ЗАДАЧА 28: Элементы между первым и последним максимальным
% ===============================================
/**
* task28_main(-Result)
* Главный предикат задачи 28: находит элементы между первым и последним максимальным
*
* @param Result - элементы между первым и последним максимумом (неунифицированная)
*
* Назначение: Объединяет чтение, логику и вывод для задачи 28
* При вызове: Result неунифицированная
* По завершении: Result содержит элементы между первым и последним максимумом
*/
task28_main(Result) :-
task28_read(List),
task28_logic(List, Result),
task28_output(Result).
/**
* task28_read(-List)
* Предикат чтения для задачи 28
*
* @param List - считанный список (неунифицированная переменная)
*
* Назначение: Читает массив с клавиатуры
* При вызове: List неунифицированная
* По завершении: List содержит введенные пользователем элементы
*/
task28_read(List) :-
write('Введите элементы массива (завершите ввод точкой): '), nl,
read_list(List).
/**
* task28_logic(+List, -ElementsBetween)
* Предикат логики работы для задачи 28
*
* @param List - исходный список (унифицированная переменная)
* @param ElementsBetween - элементы между первым и последним максимумом (неунифицированная)
*
* Назначение: Находит максимальный элемент, первую и последнюю его позицию, извлекает элементы между ними
* При вызове: List унифицированная с исходным массивом, ElementsBetween неунифицированная
* По завершении: ElementsBetween содержит элементы между первым и последним вхождением максимума
*/
task28_logic(List, ElementsBetween) :-
find_max_element(List, MaxElement),
find_first_occurrence(List, MaxElement, 1, FirstPos),
find_last_occurrence(List, MaxElement, LastPos),
extract_elements_between_positions(List, FirstPos, LastPos, ElementsBetween).
/**
* task28_output(+Result)
* Предикат вывода для задачи 28
*
* @param Result - результирующий список элементов (унифицированная переменная)
*
* Назначение: Выводит результат на экран
* При вызове: Result унифицированная со списком элементов
* По завершении: результат выведен, переменные остаются без изменений
*/
task28_output(Result) :-
write('Элементы между первым и последним максимальным: '), write(Result), nl.
% ===============================================
% ВСПОМОГАТЕЛЬНЫЕ ПРЕДИКАТЫ
% ===============================================
% Переиспользуем предикат из task1 для чтения списка
/**
* read_list(-List)
* Читает список целых чисел с клавиатуры
* Переиспользуется из task1
*/
read_list(List) :-
write('Введите элементы списка через пробел, завершив точкой: '),
read_term(List, []).
% ----------------------------------------------
% Вспомогательные предикаты для задачи 4
% ----------------------------------------------
/**
* create_index_value_pairs(+List, +CurrentIndex, -Pairs)
* Создает список пар (индекс, значение)
*
* @param List - исходный список (унифицированная)
* @param CurrentIndex - текущий индекс (унифицированная)
* @param Pairs - результирующий список пар (неунифицированная)
*/
create_index_value_pairs([], _, []).
create_index_value_pairs([Head|Tail], Index, [(Index, Head)|RestPairs]) :-
NextIndex is Index + 1,
create_index_value_pairs(Tail, NextIndex, RestPairs).
/**
* sort_pairs_by_value_desc(+Pairs, -SortedPairs)
* Сортирует пары по убыванию значений
*
* @param Pairs - список пар (индекс, значение) (унифицированная)
* @param SortedPairs - отсортированные пары (неунифицированная)
*/
sort_pairs_by_value_desc(Pairs, SortedPairs) :-
sort(2, @>=, Pairs, SortedPairs).
/**
* extract_indices(+Pairs, -Indices)
* Извлекает индексы из списка пар
*
* @param Pairs - список пар (индекс, значение) (унифицированная)
* @param Indices - список индексов (неунифицированная)
*/
extract_indices([], []).
extract_indices([(Index, _)|RestPairs], [Index|RestIndices]) :-
extract_indices(RestPairs, RestIndices).
% ----------------------------------------------
% Вспомогательные предикаты для задач 16 и 28
% ----------------------------------------------
/**
* find_max_element(+List, -MaxElement)
* Находит максимальный элемент в списке
*
* @param List - исходный список (унифицированная)
* @param MaxElement - максимальный элемент (неунифицированная)
*/
find_max_element([Head|Tail], MaxElement) :-
find_max_element_helper(Tail, Head, MaxElement).
/**
* find_max_element_helper(+List, +CurrentMax, -MaxElement)
* Вспомогательный предикат для поиска максимума
*/
find_max_element_helper([], CurrentMax, CurrentMax).
find_max_element_helper([Head|Tail], CurrentMax, MaxElement) :-
( Head > CurrentMax ->
find_max_element_helper(Tail, Head, MaxElement)
; find_max_element_helper(Tail, CurrentMax, MaxElement)
).
/**
* find_first_occurrence(+List, +Element, +CurrentPos, -Position)
* Находит первое вхождение элемента в список
*
* @param List - исходный список (унифицированная)
* @param Element - искомый элемент (унифицированная)
* @param CurrentPos - текущая позиция (унифицированная)
* @param Position - позиция первого вхождения (неунифицированная)
*/
find_first_occurrence([Element|_], Element, CurrentPos, CurrentPos) :- !.
find_first_occurrence([_|Tail], Element, CurrentPos, Position) :-
NextPos is CurrentPos + 1,
find_first_occurrence(Tail, Element, NextPos, Position).
/**
* find_second_occurrence(+List, +Element, +CurrentPos, +FirstPos, -SecondPos)
* Находит второе вхождение элемента в список
*
* @param List - исходный список (унифицированная)
* @param Element - искомый элемент (унифицированная)
* @param CurrentPos - текущая позиция (унифицированная)
* @param FirstPos - позиция первого вхождения (унифицированная)
* @param SecondPos - позиция второго вхождения (неунифицированная)
*/
find_second_occurrence([], _, _, _, fail) :- !, fail.
find_second_occurrence([Element|Tail], Element, CurrentPos, FirstPos, SecondPos) :-
CurrentPos > FirstPos, !,
SecondPos = CurrentPos.
find_second_occurrence([_|Tail], Element, CurrentPos, FirstPos, SecondPos) :-
NextPos is CurrentPos + 1,
find_second_occurrence(Tail, Element, NextPos, FirstPos, SecondPos).
/**
* find_last_occurrence(+List, +Element, -LastPos)
* Находит последнее вхождение элемента в список
*
* @param List - исходный список (унифицированная)
* @param Element - искомый элемент (унифицированная)
* @param LastPos - позиция последнего вхождения (неунифицированная)
*/
find_last_occurrence(List, Element, LastPos) :-
find_last_occurrence_helper(List, Element, 1, -1, LastPos).
/**
* find_last_occurrence_helper(+List, +Element, +CurrentPos, +LastFound, -LastPos)
* Вспомогательный предикат для поиска последнего вхождения
*/
find_last_occurrence_helper([], _, _, LastFound, LastFound).
find_last_occurrence_helper([Element|Tail], Element, CurrentPos, _, LastPos) :-
NextPos is CurrentPos + 1,
find_last_occurrence_helper(Tail, Element, NextPos, CurrentPos, LastPos).
find_last_occurrence_helper([_|Tail], Element, CurrentPos, LastFound, LastPos) :-
NextPos is CurrentPos + 1,
find_last_occurrence_helper(Tail, Element, NextPos, LastFound, LastPos).
/**
* extract_elements_between_positions(+List, +StartPos, +EndPos, -Elements)
* Извлекает элементы между двумя позициями (исключая границы)
*
* @param List - исходный список (унифицированная)
* @param StartPos - начальная позиция (унифицированная)
* @param EndPos - конечная позиция (унифицированная)
* @param Elements - элементы между позициями (неунифицированная)
*/
extract_elements_between_positions(List, StartPos, EndPos, Elements) :-
StartPos < EndPos,
extract_elements_between_helper(List, StartPos, EndPos, 1, Elements).
extract_elements_between_positions(_, StartPos, EndPos, []) :-
StartPos >= EndPos.
/**
* extract_elements_between_helper(+List, +StartPos, +EndPos, +CurrentPos, -Elements)
* Вспомогательный предикат для извлечения элементов между позициями
*/
extract_elements_between_helper([], _, _, _, []).
extract_elements_between_helper([Head|Tail], StartPos, EndPos, CurrentPos, Elements) :-
CurrentPos > StartPos,
CurrentPos < EndPos, !,
Elements = [Head|RestElements],
NextPos is CurrentPos + 1,
extract_elements_between_helper(Tail, StartPos, EndPos, NextPos, RestElements).
extract_elements_between_helper([_|Tail], StartPos, EndPos, CurrentPos, Elements) :-
NextPos is CurrentPos + 1,
extract_elements_between_helper(Tail, StartPos, EndPos, NextPos, Elements).
% ===============================================
% ИНФОРМАЦИОННЫЕ И ТЕСТОВЫЕ ПРЕДИКАТЫ
% ===============================================
/**
* task_info/0
* Выводит информацию о реализованных задачах
*/
task_info :-
write('РЕАЛИЗОВАННЫЕ ЗАДАЧИ TASK3 (Вариант 4):'), nl,
write('Задача 4: Индексы элементов в убывающем порядке'), nl,
write('Задача 16: Элементы между первым и вторым максимальным'), nl,
write('Задача 28: Элементы между первым и последним максимальным'), nl, nl,
write('Использование:'), nl,
write('?- task4_main(Result). % Задача 4'), nl,
write('?- task16_main(Result). % Задача 16'), nl,
write('?- task28_main(Result). % Задача 28'), nl.
/**
* show_examples/0
* Показывает примеры использования с готовыми данными
*/
show_examples :-
write('ПРИМЕРЫ РАБОТЫ ЗАДАЧ:'), nl, nl,
write('Задача 4 - Индексы в убывающем порядке для [3,1,4,1,5]:'), nl,
task4_logic([3,1,4,1,5], Result4),
write('Результат: '), write(Result4), nl, nl,
write('Задача 16 - Элементы между первым и вторым максимальным для [1,5,2,3,5,4]:'), nl,
task16_logic([1,5,2,3,5,4], Result16),
write('Результат: '), write(Result16), nl, nl,
write('Задача 28 - Элементы между первым и последним максимальным для [1,5,2,3,5,4]:'), nl,
task28_logic([1,5,2,3,5,4], Result28),
write('Результат: '), write(Result28), nl.
/**
* interactive_demo/0
* Интерактивная демонстрация всех задач
*/
interactive_demo :-
write('=== ИНТЕРАКТИВНАЯ ДЕМОНСТРАЦИЯ TASK3 ==='), nl,
write('Выберите задачу:'), nl,
write('4. Индексы в убывающем порядке'), nl,
write('16. Элементы между первым и вторым максимальным'), nl,
write('28. Элементы между первым и последним максимальным'), nl,
write('0. Выход'), nl,
write('Введите номер задачи: '),
read(Choice),
handle_choice(Choice).
/**
* handle_choice(+Choice)
* Обрабатывает выбор пользователя в интерактивном режиме
*/
handle_choice(4) :-
task4_main(_),
interactive_demo.
handle_choice(16) :-
task16_main(_),
interactive_demo.
handle_choice(28) :-
task28_main(_),
interactive_demo.
handle_choice(0) :-
write('До свидания!'), nl.
handle_choice(_) :-
write('Неверный выбор! Попробуйте снова.'), nl,
interactive_demo.