lab 9 task 3

main
Artem-Darius Weber 6 months ago
parent 0db12aa71f
commit c02b049b48

@ -1,4 +1,4 @@
.PHONY: run build clean task1 build-task1 clean-task1 interactive-task1 test-task1 demo-task1 trace-task1 info-task1 task2 build-task2 clean-task2 interactive-task2 test-task2 demo-task2 trace-task2 info-task2
.PHONY: run build clean task1 build-task1 clean-task1 interactive-task1 test-task1 demo-task1 trace-task1 info-task1 task2 build-task2 clean-task2 interactive-task2 test-task2 demo-task2 trace-task2 info-task2 task3 build-task3 clean-task3 interactive-task3 test-task3 demo-task3 trace-task3 info-task3
# task1 (default)
run:
@ -62,6 +62,31 @@ trace-task2:
info-task2:
cd task2 && make info
# task3
task3:
cd task3 && make run
build-task3:
cd task3 && make build
clean-task3:
cd task3 && make clean
interactive-task3:
cd task3 && make interactive
test-task3:
cd task3 && make test
demo-task3:
cd task3 && make demo
trace-task3:
cd task3 && make trace
info-task3:
cd task3 && make info
# Help
help:
@echo "Available commands for lab9:"
@ -76,6 +101,26 @@ help:
@echo " make build-task1 - Build task1 Docker image"
@echo " make clean-task1 - Clean task1 Docker images"
@echo ""
@echo "Task 2 (Specialized predicates):"
@echo " make task2 - Run task2 (basic info)"
@echo " make info-task2 - Show detailed task2 info"
@echo " make demo-task2 - Run task2 demonstration"
@echo " make test-task2 - Run task2 tests"
@echo " make interactive-task2 - Start task2 interactive session"
@echo " make trace-task2 - Run task2 with tracing"
@echo " make build-task2 - Build task2 Docker image"
@echo " make clean-task2 - Clean task2 Docker images"
@echo ""
@echo "Task 3 (Array problems):"
@echo " make task3 - Run task3 (basic info)"
@echo " make info-task3 - Show detailed task3 info"
@echo " make demo-task3 - Run task3 demonstration"
@echo " make test-task3 - Run task3 tests"
@echo " make interactive-task3 - Start task3 interactive session"
@echo " make trace-task3 - Run task3 examples"
@echo " make build-task3 - Build task3 Docker image"
@echo " make clean-task3 - Clean task3 Docker images"
@echo ""
@echo "Default commands (task1):"
@echo " make run - Run task1"
@echo " make build - Build task1"

@ -0,0 +1,7 @@
FROM swipl:stable
WORKDIR /app
COPY *.pl ./
CMD ["swipl"]

@ -0,0 +1,45 @@
.PHONY: build run interactive clean test trace demo info
# Build Docker image
build:
docker build -t lab9-task3-prolog .
# Run Prolog with predicates (show basic info and exit)
run: build
docker run --rm -v $(PWD):/app lab9-task3-prolog swipl -g "consult('predicates.pl'), write('=== LAB9 TASK3 PREDICATES ==='), nl, task_info, halt"
# Interactive Prolog session
interactive: build
docker run -it --rm -v $(PWD):/app lab9-task3-prolog swipl predicates.pl
# Run test queries
test: build
docker run --rm -v $(PWD):/app lab9-task3-prolog swipl -g "consult('predicates.pl'), consult('tests.pl'), run_tests, halt"
# Run with tracing enabled
trace: build
docker run --rm -v $(PWD):/app lab9-task3-prolog swipl -g "consult('predicates.pl'), trace, task4_logic([3,1,4,1,5], R1), write('Result: '), write(R1), nl, notrace, halt"
# Show basic info about task3
info: build
docker run --rm -v $(PWD):/app lab9-task3-prolog swipl -g "consult('predicates.pl'), write('=== TASK3 INFO ==='), nl, task_info, show_examples, halt"
# Run demo
demo: build
docker run --rm -v $(PWD):/app lab9-task3-prolog swipl -g "consult('predicates.pl'), consult('demo.pl'), demo, halt"
# Clean Docker images
clean:
docker rmi lab9-task3-prolog || true
# Help
help:
@echo "Available commands for lab9 task3:"
@echo " make build - Build Docker image"
@echo " make run - Run and show basic predicates info"
@echo " make info - Show detailed task3 information"
@echo " make demo - Run demonstration queries"
@echo " make test - Run test queries"
@echo " make interactive - Start interactive Prolog session"
@echo " make trace - Run examples without tracing"
@echo " make clean - Clean Docker images"

@ -0,0 +1,304 @@
% ===============================================
% ДЕМОНСТРАЦИЯ LAB9 TASK3
% Полная демонстрация решений задач с массивами
% ===============================================
% Главная демонстрация
demo :-
write('=== ДЕМОНСТРАЦИЯ LAB9 TASK3: ЗАДАЧИ С МАССИВАМИ ==='), nl,
write('Вариант 4: Задачи 4, 16, 28'), nl, nl,
% Демонстрация задачи 4
write('ЗАДАЧА 4: ИНДЕКСЫ ЭЛЕМЕНТОВ В УБЫВАЮЩЕМ ПОРЯДКЕ'), nl,
write('================================================'), nl,
demo_task4,
nl,
% Демонстрация задачи 16
write('ЗАДАЧА 16: ЭЛЕМЕНТЫ МЕЖДУ ПЕРВЫМ И ВТОРЫМ МАКСИМАЛЬНЫМ'), nl,
write('======================================================'), nl,
demo_task16,
nl,
% Демонстрация задачи 28
write('ЗАДАЧА 28: ЭЛЕМЕНТЫ МЕЖДУ ПЕРВЫМ И ПОСЛЕДНИМ МАКСИМАЛЬНЫМ'), nl,
write('========================================================='), nl,
demo_task28,
nl,
% Анализ модульной структуры
write('АНАЛИЗ МОДУЛЬНОЙ СТРУКТУРЫ'), nl,
write('=========================='), nl,
demo_modular_structure,
nl,
% Практические примеры
write('ПРАКТИЧЕСКИЕ ПРИМЕРЫ'), nl,
write('==================='), nl,
demo_practical_examples,
nl,
write('=== ДЕМОНСТРАЦИЯ TASK3 ЗАВЕРШЕНА ==='), nl.
% -----------------------------------------------
% Демонстрация задачи 4
% -----------------------------------------------
demo_task4 :-
write('Задача: Дан целочисленный массив. Вывести индексы массива'), nl,
write('в том порядке, в котором соответствующие им элементы'), nl,
write('образуют убывающую последовательность.'), nl, nl,
write('ПРИНЦИП РАБОТЫ:'), nl,
write('1. Создаем пары (индекс, значение)'), nl,
write('2. Сортируем пары по убыванию значений'), nl,
write('3. Извлекаем индексы из отсортированных пар'), nl, nl,
% Примеры
TestCases4 = [
([3,1,4,1,5], "Смешанные числа"),
([5,4,3,2,1], "Уже убывающая"),
([1,2,3,4,5], "Возрастающая"),
([2,2,2,2], "Одинаковые элементы"),
([7], "Один элемент")
],
write('ПРИМЕРЫ РАБОТЫ:'), nl,
write('Массив | Индексы в порядке убывания | Пояснение'), nl,
write('----------------|----------------------------|----------'), nl,
forall(member((List, Description), TestCases4), demo_task4_case(List, Description)),
nl,
write('МОДУЛЬНАЯ СТРУКТУРА ЗАДАЧИ 4:'), nl,
write('• task4_read/1 - чтение массива (List неунифицированная)'), nl,
write('• task4_logic/2 - логика работы (List унифицированная, Result неунифицированная)'), nl,
write('• task4_output/1 - вывод результата (Result унифицированная)'), nl, nl,
write('УНИФИКАЦИЯ В task4_logic([3,1,4,1,5], Result):'), nl,
write('1. List = [3,1,4,1,5] (унифицированная при вызове)'), nl,
write('2. create_index_value_pairs создает [(1,3),(2,1),(3,4),(4,1),(5,5)]'), nl,
write('3. sort_pairs_by_value_desc сортирует по убыванию: [(5,5),(3,4),(1,3),(2,1),(4,1)]'), nl,
write('4. extract_indices извлекает индексы: [5,3,1,2,4]'), nl,
write('5. Result унифицируется с [5,3,1,2,4]'), nl.
demo_task4_case(List, Description) :-
task4_logic(List, Result),
format('~w~15| | ~w~25| | ~w~n', [List, Result, Description]).
% -----------------------------------------------
% Демонстрация задачи 16
% -----------------------------------------------
demo_task16 :-
write('Задача: Дан целочисленный массив. Найти элементы,'), nl,
write('расположенные между первым и вторым максимальным.'), nl, nl,
write('ПРИНЦИП РАБОТЫ:'), nl,
write('1. Находим максимальный элемент массива'), nl,
write('2. Находим позицию первого вхождения максимума'), nl,
write('3. Находим позицию второго вхождения максимума'), nl,
write('4. Извлекаем элементы между этими позициями'), nl, nl,
% Примеры
TestCases16 = [
([1,5,2,3,5,4], "Максимум встречается дважды"),
([9,1,2,3,9], "Максимум в начале и конце"),
([1,7,7,2], "Максимумы рядом"),
([3,8,1,4,8,2,8], "Максимум встречается трижды"),
([1,2,9,3,4], "Только один максимум")
],
write('ПРИМЕРЫ РАБОТЫ:'), nl,
write('Массив | Элементы между 1-м и 2-м макс. | Пояснение'), nl,
write('-------------------|----------------------------------|----------'), nl,
forall(member((List, Description), TestCases16), demo_task16_case(List, Description)),
nl,
write('МОДУЛЬНАЯ СТРУКТУРА ЗАДАЧИ 16:'), nl,
write('• task16_read/1 - чтение массива'), nl,
write('• task16_logic/2 - логика работы'), nl,
write('• task16_output/1 - вывод результата'), nl, nl,
write('УНИФИКАЦИЯ В task16_logic([1,5,2,3,5,4], Result):'), nl,
write('1. List = [1,5,2,3,5,4] (унифицированная)'), nl,
write('2. find_max_element находит MaxElement = 5'), nl,
write('3. find_first_occurrence находит FirstPos = 2'), nl,
write('4. find_second_occurrence находит SecondPos = 5'), nl,
write('5. extract_elements_between_positions извлекает элементы: [2,3]'), nl,
write('6. Result унифицируется с [2,3]'), nl.
demo_task16_case(List, Description) :-
( task16_logic(List, Result) ->
format('~w~18| | ~w~31| | ~w~n', [List, Result, Description])
; format('~w~18| | ~w~31| | ~w~n', [List, "Ошибка/Нет второго макс.", Description])
).
% -----------------------------------------------
% Демонстрация задачи 28
% -----------------------------------------------
demo_task28 :-
write('Задача: Дан целочисленный массив. Найти элементы,'), nl,
write('расположенные между первым и последним максимальным.'), nl, nl,
write('ПРИНЦИП РАБОТЫ:'), nl,
write('1. Находим максимальный элемент массива'), nl,
write('2. Находим позицию первого вхождения максимума'), nl,
write('3. Находим позицию последнего вхождения максимума'), nl,
write('4. Извлекаем элементы между этими позициями'), nl, nl,
% Примеры
TestCases28 = [
([1,5,2,3,5,4,5], "Максимум встречается трижды"),
([9,1,2,3,9], "Максимум в начале и конце"),
([1,2,9,3,4], "Только один максимум"),
([1,8,8,8,2], "Максимум повторяется подряд"),
([6,3,6,1,4,6], "Максимум в разных местах")
],
write('ПРИМЕРЫ РАБОТЫ:'), nl,
write('Массив | Элементы между 1-м и последним макс. | Пояснение'), nl,
write('---------------------|---------------------------------------|----------'), nl,
forall(member((List, Description), TestCases28), demo_task28_case(List, Description)),
nl,
write('МОДУЛЬНАЯ СТРУКТУРА ЗАДАЧИ 28:'), nl,
write('• task28_read/1 - чтение массива'), nl,
write('• task28_logic/2 - логика работы'), nl,
write('• task28_output/1 - вывод результата'), nl, nl,
write('УНИФИКАЦИЯ В task28_logic([1,5,2,3,5,4,5], Result):'), nl,
write('1. List = [1,5,2,3,5,4,5] (унифицированная)'), nl,
write('2. find_max_element находит MaxElement = 5'), nl,
write('3. find_first_occurrence находит FirstPos = 2'), nl,
write('4. find_last_occurrence находит LastPos = 7'), nl,
write('5. extract_elements_between_positions извлекает: [2,3,5,4]'), nl,
write('6. Result унифицируется с [2,3,5,4]'), nl.
demo_task28_case(List, Description) :-
task28_logic(List, Result),
format('~w~20| | ~w~36| | ~w~n', [List, Result, Description]).
% -----------------------------------------------
% Анализ модульной структуры
% -----------------------------------------------
demo_modular_structure :-
write('ПРИНЦИПЫ МОДУЛЬНОЙ СТРУКТУРЫ В TASK3:'), nl, nl,
write('1. РАЗДЕЛЕНИЕ ОБЯЗАННОСТЕЙ:'), nl,
write(' • Предикат чтения: отвечает только за ввод данных'), nl,
write(' • Предикат логики: содержит основной алгоритм'), nl,
write(' • Предикат вывода: отвечает только за отображение результата'), nl, nl,
write('2. МИНИМАЛЬНОЕ КОЛИЧЕСТВО АРГУМЕНТОВ:'), nl,
write(' ✓ Правильно: task4_logic(List, Result)'), nl,
write(' ✗ Неправильно: task4_logic(List, 0, Helper, Result)'), nl,
write(' Логический предикат не содержит вспомогательных переменных'), nl, nl,
write('3. СОСТОЯНИЯ УНИФИКАЦИИ:'), nl,
write(' • При вызове логики: входные данные унифицированы'), nl,
write(' • При завершении: результат унифицирован с ответом'), nl,
write(' • Промежуточные переменные унифицируются в процессе'), nl, nl,
write('4. ПЕРЕИСПОЛЬЗОВАНИЕ ПРЕДИКАТОВ:'), nl,
write(' • read_list/1 переиспользуется из task1'), nl,
write(' • Общие алгоритмы вынесены в отдельные предикаты'), nl,
write(' • Избегается дублирование кода'), nl, nl,
write('5. ПРИМЕРЫ КОРРЕКТНОЙ УНИФИКАЦИИ:'), nl,
demo_unification_examples.
demo_unification_examples :-
write(' Пример для task4_logic([3,1,4], Result):'), nl,
write(' ├─ Входные: List=[3,1,4] (унифицированная)'), nl,
write(' ├─ Выходные: Result (неунифицированная)'), nl,
write(' ├─ Промежуточные переменные унифицируются пошагово:'), nl,
write(' │ ├─ Pairs = [(1,3),(2,1),(3,4)]'), nl,
write(' │ ├─ SortedPairs = [(3,4),(1,3),(2,1)]'), nl,
write(' │ └─ SortedIndices = [3,1,2]'), nl,
write(' └─ Result унифицируется с [3,1,2]'), nl.
% -----------------------------------------------
% Практические примеры
% -----------------------------------------------
demo_practical_examples :-
write('ПРАКТИЧЕСКИЕ ПРИМЕНЕНИЯ РЕШЕННЫХ ЗАДАЧ:'), nl, nl,
write('СЦЕНАРИЙ 1: Анализ результатов соревнований'), nl,
write('─────────────────────────────────────────'), nl,
demo_competition_analysis,
nl,
write('СЦЕНАРИЙ 2: Обработка временных рядов'), nl,
write('────────────────────────────────────'), nl,
demo_time_series_analysis,
nl,
write('СЦЕНАРИЙ 3: Игровая механика'), nl,
write('────────────────────────────'), nl,
demo_game_mechanics.
demo_competition_analysis :-
CompetitionScores = [85, 92, 78, 92, 88, 90, 92],
write('Результаты участников: '), write(CompetitionScores), nl,
% Задача 4: Ранжирование участников
task4_logic(CompetitionScores, RankOrder),
write('Ранжирование (лучшие первые): участники '), write(RankOrder), nl,
% Задача 16: Участники между первым и вторым призером
task16_logic(CompetitionScores, BetweenWinners),
write('Участники между 1-м и 2-м призером: '), write(BetweenWinners), nl,
% Задача 28: Все участники между призерами
task28_logic(CompetitionScores, AllBetween),
write('Все участники между призерами: '), write(AllBetween), nl.
demo_time_series_analysis :-
TemperatureData = [22, 25, 23, 25, 24, 26, 25],
write('Температурные данные: '), write(TemperatureData), nl,
% Задача 4: Дни по убыванию температуры
task4_logic(TemperatureData, TempOrder),
write('Дни по убыванию температуры: '), write(TempOrder), nl,
% Задача 28: Данные между пиками
task28_logic(TemperatureData, BetweenPeaks),
write('Данные между температурными пиками: '), write(BetweenPeaks), nl.
demo_game_mechanics :-
PlayerScores = [100, 150, 120, 150, 140, 160, 150],
write('Очки игроков: '), write(PlayerScores), nl,
% Задача 4: Таблица лидеров
task4_logic(PlayerScores, Leaderboard),
write('Таблица лидеров (игроки): '), write(Leaderboard), nl,
% Задача 16: Игроки между лидерами
task16_logic(PlayerScores, BetweenLeaders),
write('Игроки между лидерами: '), write(BetweenLeaders), nl.
% -----------------------------------------------
% Интерактивные примеры
% -----------------------------------------------
demo_interactive_examples :-
write('=== ИНТЕРАКТИВНЫЕ ПРИМЕРЫ TASK3 ==='), nl,
write('Вы можете попробовать следующие запросы:'), nl, nl,
write('1. Задача 4 - Индексы в убывающем порядке:'), nl,
write(' ?- task4_logic([3,1,4,1,5], Result).'), nl,
write(' Result = [5,3,1,2,4]'), nl, nl,
write('2. Задача 16 - Между первым и вторым максимальным:'), nl,
write(' ?- task16_logic([1,5,2,3,5,4], Result).'), nl,
write(' Result = [2,3]'), nl, nl,
write('3. Задача 28 - Между первым и последним максимальным:'), nl,
write(' ?- task28_logic([1,5,2,3,5,4,5], Result).'), nl,
write(' Result = [2,3,5,4]'), nl, nl,
write('4. Полный интерактивный режим:'), nl,
write(' ?- interactive_demo.'), nl, nl,
write('5. Примеры с готовыми данными:'), nl,
write(' ?- show_examples.'), nl, nl.

@ -0,0 +1,427 @@
% ===============================================
% 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.

@ -0,0 +1,258 @@
% ===============================================
% ТЕСТЫ ДЛЯ LAB9 TASK3
% Автоматические тесты всех задач
% ===============================================
% Запуск всех тестов
run_tests :-
write('=== ЗАПУСК АВТОМАТИЧЕСКИХ ТЕСТОВ TASK3 ==='), nl,
test_task4,
test_task16,
test_task28,
test_edge_cases,
write('=== ВСЕ ТЕСТЫ TASK3 ЗАВЕРШЕНЫ ==='), nl.
% ===============================================
% ТЕСТЫ ДЛЯ ЗАДАЧИ 4
% ===============================================
test_task4 :-
write('--- Тестирование задачи 4: Индексы в убывающем порядке ---'), nl,
% Тест 1: Простой случай
TestList1 = [3, 1, 4, 1, 5],
task4_logic(TestList1, Result1),
Expected1 = [5, 3, 1, 2, 4], % 5(индекс 5), 4(индекс 3), 3(индекс 1), 1(индекс 2), 1(индекс 4)
write('Тест 1 - [3,1,4,1,5]: '), write(Result1),
(Result1 = Expected1 -> write(' ✓') ; write(' ✗')), nl,
% Тест 2: Убывающая последовательность
TestList2 = [5, 4, 3, 2, 1],
task4_logic(TestList2, Result2),
Expected2 = [1, 2, 3, 4, 5],
write('Тест 2 - [5,4,3,2,1]: '), write(Result2),
(Result2 = Expected2 -> write(' ✓') ; write(' ✗')), nl,
% Тест 3: Возрастающая последовательность
TestList3 = [1, 2, 3, 4, 5],
task4_logic(TestList3, Result3),
Expected3 = [5, 4, 3, 2, 1],
write('Тест 3 - [1,2,3,4,5]: '), write(Result3),
(Result3 = Expected3 -> write(' ✓') ; write(' ✗')), nl,
% Тест 4: Одинаковые элементы
TestList4 = [2, 2, 2],
task4_logic(TestList4, Result4),
write('Тест 4 - [2,2,2]: '), write(Result4), write(' ✓'), nl,
% Тест 5: Один элемент
TestList5 = [42],
task4_logic(TestList5, Result5),
Expected5 = [1],
write('Тест 5 - [42]: '), write(Result5),
(Result5 = Expected5 -> write(' ✓') ; write(' ✗')), nl,
nl.
% ===============================================
% ТЕСТЫ ДЛЯ ЗАДАЧИ 16
% ===============================================
test_task16 :-
write('--- Тестирование задачи 16: Элементы между первым и вторым максимальным ---'), nl,
% Тест 1: Максимум встречается дважды
TestList1 = [1, 5, 2, 3, 5, 4],
task16_logic(TestList1, Result1),
Expected1 = [2, 3], % Между позициями 2 и 5
write('Тест 1 - [1,5,2,3,5,4]: '), write(Result1),
(Result1 = Expected1 -> write(' ✓') ; write(' ✗')), nl,
% Тест 2: Максимум в начале и конце
TestList2 = [9, 1, 2, 3, 9],
task16_logic(TestList2, Result2),
Expected2 = [1, 2, 3], % Между позициями 1 и 5
write('Тест 2 - [9,1,2,3,9]: '), write(Result2),
(Result2 = Expected2 -> write(' ✓') ; write(' ✗')), nl,
% Тест 3: Максимум рядом
TestList3 = [1, 7, 7, 2],
task16_logic(TestList3, Result3),
Expected3 = [], % Между позициями 2 и 3 нет элементов
write('Тест 3 - [1,7,7,2]: '), write(Result3),
(Result3 = Expected3 -> write(' ✓') ; write(' ✗')), nl,
% Тест 4: Только один максимум
TestList4 = [1, 2, 9, 3, 4],
task16_logic(TestList4, Result4),
% Должна обрабатывать случай, когда второго максимума нет
write('Тест 4 - [1,2,9,3,4]: '), write(Result4), write(' ✓'), nl,
nl.
% ===============================================
% ТЕСТЫ ДЛЯ ЗАДАЧИ 28
% ===============================================
test_task28 :-
write('--- Тестирование задачи 28: Элементы между первым и последним максимальным ---'), nl,
% Тест 1: Максимум встречается несколько раз
TestList1 = [1, 5, 2, 3, 5, 4, 5],
task28_logic(TestList1, Result1),
Expected1 = [2, 3, 5, 4], % Между позициями 2 и 7
write('Тест 1 - [1,5,2,3,5,4,5]: '), write(Result1),
(Result1 = Expected1 -> write(' ✓') ; write(' ✗')), nl,
% Тест 2: Максимум в начале и конце
TestList2 = [9, 1, 2, 3, 9],
task28_logic(TestList2, Result2),
Expected2 = [1, 2, 3], % Между позициями 1 и 5
write('Тест 2 - [9,1,2,3,9]: '), write(Result2),
(Result2 = Expected2 -> write(' ✓') ; write(' ✗')), nl,
% Тест 3: Только один максимум
TestList3 = [1, 2, 9, 3, 4],
task28_logic(TestList3, Result3),
Expected3 = [], % Первый и последний максимум совпадают
write('Тест 3 - [1,2,9,3,4]: '), write(Result3),
(Result3 = Expected3 -> write(' ✓') ; write(' ✗')), nl,
% Тест 4: Максимум повторяется подряд
TestList4 = [1, 8, 8, 8, 2],
task28_logic(TestList4, Result4),
Expected4 = [8], % Между позициями 2 и 4 (элемент на позиции 3)
write('Тест 4 - [1,8,8,8,2]: '), write(Result4),
(Result4 = Expected4 -> write(' ✓') ; write(' ✗')), nl,
nl.
% ===============================================
% ТЕСТЫ ГРАНИЧНЫХ СЛУЧАЕВ
% ===============================================
test_edge_cases :-
write('--- Тестирование граничных случаев ---'), nl,
% Пустой список для вспомогательных функций
write('Граничные случаи:'), nl,
% Тест поиска максимума в списке из одного элемента
find_max_element([5], Max1),
write('Максимум в [5]: '), write(Max1),
(Max1 = 5 -> write(' ✓') ; write(' ✗')), nl,
% Тест поиска первого вхождения
find_first_occurrence([1,2,3,2,4], 2, 1, Pos1),
write('Первое вхождение 2 в [1,2,3,2,4]: позиция '), write(Pos1),
(Pos1 = 2 -> write(' ✓') ; write(' ✗')), nl,
% Тест поиска последнего вхождения
find_last_occurrence([1,2,3,2,4], 2, Pos2),
write('Последнее вхождение 2 в [1,2,3,2,4]: позиция '), write(Pos2),
(Pos2 = 4 -> write(' ✓') ; write(' ✗')), nl,
% Тест извлечения элементов между позициями
extract_elements_between_positions([a,b,c,d,e], 2, 5, Elements),
write('Элементы между позициями 2 и 5 в [a,b,c,d,e]: '), write(Elements),
(Elements = [c, d] -> write(' ✓') ; write(' ✗')), nl,
% Тест создания пар индекс-значение
create_index_value_pairs([a,b,c], 1, Pairs),
write('Пары для [a,b,c]: '), write(Pairs),
(Pairs = [(1,a), (2,b), (3,c)] -> write(' ✓') ; write(' ✗')), nl,
nl.
% ===============================================
% ДОПОЛНИТЕЛЬНЫЕ ТЕСТЫ ПРОИЗВОДИТЕЛЬНОСТИ
% ===============================================
test_performance :-
write('--- Тесты производительности ---'), nl,
% Создание большого списка для тестирования
create_test_list(100, TestList),
length(TestList, Len),
write('Создан тестовый список длиной: '), write(Len), nl,
% Тестирование задачи 4 на большом списке
get_time(T1),
task4_logic(TestList, _),
get_time(T2),
Time4 is T2 - T1,
write('Время выполнения задачи 4: '), write(Time4), write(' сек'), nl,
% Тестирование задачи 16 на большом списке
get_time(T3),
task16_logic(TestList, _),
get_time(T4),
Time16 is T4 - T3,
write('Время выполнения задачи 16: '), write(Time16), write(' сек'), nl,
% Тестирование задачи 28 на большом списке
get_time(T5),
task28_logic(TestList, _),
get_time(T6),
Time28 is T6 - T5,
write('Время выполнения задачи 28: '), write(Time28), write(' сек'), nl,
nl.
% Создание тестового списка заданной длины
create_test_list(N, List) :-
create_test_list_helper(N, 1, List).
create_test_list_helper(0, _, []) :- !.
create_test_list_helper(N, Current, [Element|Rest]) :-
N > 0,
Element is (Current mod 10) + 1, % Элементы от 1 до 10
N1 is N - 1,
Next is Current + 1,
create_test_list_helper(N1, Next, Rest).
% ===============================================
% СТРЕСС-ТЕСТЫ
% ===============================================
stress_test :-
write('--- Стресс-тесты ---'), nl,
% Тест с повторяющимися максимумами
RepeatList = [3,7,1,7,2,7,4,7],
write('Стресс-тест с повторяющимися максимумами [3,7,1,7,2,7,4,7]:'), nl,
task4_logic(RepeatList, Result4),
write(' Задача 4: '), write(Result4), nl,
task16_logic(RepeatList, Result16),
write(' Задача 16: '), write(Result16), nl,
task28_logic(RepeatList, Result28),
write(' Задача 28: '), write(Result28), nl,
% Тест с отрицательными числами
NegList = [-5, -1, -3, -1, -2],
write('Стресс-тест с отрицательными числами [-5,-1,-3,-1,-2]:'), nl,
task4_logic(NegList, Result4Neg),
write(' Задача 4: '), write(Result4Neg), nl,
task16_logic(NegList, Result16Neg),
write(' Задача 16: '), write(Result16Neg), nl,
task28_logic(NegList, Result28Neg),
write(' Задача 28: '), write(Result28Neg), nl,
nl.
% ===============================================
% ТЕСТ КОРРЕКТНОСТИ ВСПОМОГАТЕЛЬНЫХ ПРЕДИКАТОВ
% ===============================================
test_helper_predicates :-
write('--- Тест вспомогательных предикатов ---'), nl,
% Тест сортировки пар по убыванию значений
TestPairs = [(1,5), (2,3), (3,8), (4,1)],
sort_pairs_by_value_desc(TestPairs, SortedPairs),
write('Сортировка пар по убыванию: '), write(SortedPairs),
Expected = [(3,8), (1,5), (2,3), (4,1)],
(SortedPairs = Expected -> write(' ✓') ; write(' ✗')), nl,
% Тест извлечения индексов
extract_indices([(3,8), (1,5), (2,3)], Indices),
write('Извлечение индексов: '), write(Indices),
(Indices = [3, 1, 2] -> write(' ✓') ; write(' ✗')), nl,
nl.
Loading…
Cancel
Save