% =============================================== % 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.