Министерство цифрового развития, связи и массовых коммуникаций Российской Федерации
Федеральное государственное бюджетное образовательное учреждение Высшего образования «Санкт-Петербургский государственный университет телекоммуникаций им. Проф. М. А. Бонч-Бруевича» (СПбГУТ)
Факультет Информационных технологий и программной инженерии
Кафедра Программной инженерии
Лабораторная работа №4
По дисциплине: Разработка приложений искусственного интеллекта в киберфизических системах
Выполнил:
Студент 3 курса группы ИКПИ – 32
Яковлев М. А.
___________________
(подпись)
Проверил:
Ерофеев С. А.
___________________
(подпись)
г. Санкт-Петербург
2025 г.
Постановка задачи
Целью данной работы является разработка программы, обеспечивающей создание, хранение и управление базой данных. Разрабатываемая программа должна предоставлять пользователю базовые функции работы с данными, включая добавление новых записей, удаление и редактирование существующих, просмотр информации, а также возможность экспорта данных.
Для достижения этой цели необходимо выполнить следующие задачи:
Определить домены и предикаты для хранения информации;
Реализовать загрузку и сохранение базы данных из файла;
Организовать взаимодействие пользователя с базой данных через меню;
Реализовать операции добавления, удаления и редактирования элементов базы;
Обеспечить возможность подсчёта количества элементов и экспорта данных в CSV-файл;
Протестировать программу на различных наборах данных.
Входные данные:
Входными данными являются:
Файл базы данных (по умолчанию bicycles.txt), содержащий записи о велосипедах в формате:
bicycle(“Brand”, “Type”, “Color”, “Frame”, Dia, Price, Qty)
Пользовательский ввод для взаимодействия с меню программы: выбор опций, ввод значений для добавления или редактирования элементов.
Выходные данные:
Программа формирует следующие результаты:
Отображение базы данных в консоли:
полный вывод всех элементов базы;
пошаговый вывод с ожиданием ввода пользователя;
Информация о конкретном велосипеде;
Подсчёт количества элементов в базе;
Файл базы данных после сохранения;
CSV-файл с экспортированными данными;
Сообщения о выполненных действиях (добавление, удаление, редактирование, ошибки).
Суть алгоритма заключается в следующем:
Программа организована как интерактивная система управления базой данных, состоящая из следующих модулей:
Модуль загрузки и сохранения базы данных.
Проверяет существование файла базы данных и загружает записи;
Обеспечивает сохранение текущего состояния базы в файл и экспорт в CSV;
Позволяет изменять имя текущего файла базы данных.
Модуль управления записями базы данных.
Добавление новой записи с проверкой корректности введённых данных;
Удаление записи по имени;
Редактирование существующей записи;
Подсчёт количества элементов в базе.
Модуль пользовательского меню.
Отображает список возможных действий;
Обеспечивает обработку выбора пользователя и вызов соответствующих функций;
Поддерживает рекурсивное возвращение в меню после выполнения действия.
Вспомогательные модули
Проверка корректности ввода положительных чисел;
Вывод информации в консоль и управление ожиданием ввода пользователя.
Программа гарантирует целостность данных, корректную обработку ошибок и взаимодействие с пользователем.
Перечень предикатов
Для реализации программы базы данных были определены следующие предикаты:
1. load_database_from_file — загружает базу данных из текущего файла (по умолчанию или указанного).
2. load_database_from_file(Filename) — загружает базу данных из указанного файла.
3. save_database_to_file — сохраняет базу данных в текущий файл.
4. save_database_to_file(Filename) — сохраняет базу данных в указанный файл.
5. save_database_to_csv — сохраняет базу данных в CSV-файл.
6. save_database_to_csv(Filename) — сохраняет базу данных в CSV-файл с заданным именем.
7. show_current_filename — выводит текущее имя файла базы данных.
8. set_current_filename(Filename) — устанавливает текущее имя файла.
9. change_filename — изменяет имя текущего файла базы данных.
10. reload_database — перезагружает базу данных из файла.
11. ensure_database_loaded — проверяет наличие загруженной базы и при необходимости загружает её.
12. print_all_bicycles — выводит все записи базы данных.
13. print_all_bicycles_stepwise — выводит записи базы данных по одной с ожиданием ввода.
14. print_bicycles(Brand) — выводит информацию об одной записи.
15. add_bicycle — добавляет новую запись в базу данных.
16. delete_bicycle — удаляет запись по имени.
17. delete_bicycle_by_brand(Name) — удаляет запись с заданным именем.
18. edit_bicycle — редактирует существующую запись по имени.
19. edit_bicycle_by_brand(Brand) — редактирует конкретную запись с указанным именем.
20. read_positive_integer(Prompt, Value) — считывает положительное целое число с проверкой.
21. menu — отображает меню программы и ожидает выбор пользователя.
22. action(Option) — выполняет действие, соответствующее выбранному пункту меню.
23. wait_for_enter — ожидание нажатия клавиши Enter для продолжения.
24. get_current_filename(Filename) — получает текущее имя файла базы данных.
25. save_all_bicycles — сохраняет все записи в открытый файл (для внутреннего использования).
26. save_all_bicycles_csv — сохраняет все записи в CSV-формате.
Блок-схемы
Рисунок
2. Изменение имени файла
Рисунок
1. Общая структура программы
Рисунок 3. Загрузка данных из файла
Рисунок
4. Вывод данных из БД
Рисунок 5. Добавление новой записи
Рисунок 6. Удаление записи из БД
Рисунок 7. Редактирование записи
Тестирование
Для проверки работоспособности программы были выполнены тестовые запросы к базе знаний в среде Prolog. Результаты выполнения запросов приведены ниже в виде скриншотов, подтверждающих корректность работы предикатов и правил.
Рисунок 8. Меню
Рисунок 9. Вывод записей
Рисунок 10. Последовательный вывод записей
Рисунок 11. Редактирование записи
Программа
NOWARNINGS
DOMAINS
name, brand, type, color, material = string
price, quantity, diameter = integer
file = file_pointer
bicycle_domain = bicycle(brand, type, color, material, diameter, price, quantity)
menu_option = integer
DATABASE
bicycle(
brand,
type,
color,
material,
diameter,
price,
quantity
)
current_filename(string)
PREDICATES
load_database_from_file
load_database_from_file(string)
print_all_bicycles
print_all_bicycles_stepwise
print_bicycle(bicycle_domain)
wait_for_enter
menu
action(menu_option)
add_bicycle
delete_bicycle
delete_bicycle_by_brand(string)
edit_bicycle
edit_bicycle_by_brand(string)
edit_bicycle_menu(bicycle_domain)
edit_bicycle_field(integer, bicycle_domain)
save_all_bicycles
save_database_to_file
save_database_to_file(string)
ensure_database_loaded
get_current_filename(string)
set_current_filename(string)
change_filename
show_current_filename
reload_database
add_bicycle_fact(brand, type, color, material, diameter, price, quantity) % helper insert
read_positive_integer(string, integer)
save_all_bicycles_csv
save_database_to_csv
save_database_to_csv(string)
CLAUSES
get_current_filename(Filename) :-
current_filename(Filename), !.
get_current_filename("bicycles.txt").
set_current_filename(Filename) :-
retractall(current_filename(_)),
assertz(current_filename(Filename)).
show_current_filename :-
get_current_filename(Filename),
write("Current database file: ", Filename), nl.
% Загрузка базы данных
load_database_from_file :-
get_current_filename(Filename),
load_database_from_file(Filename).
load_database_from_file(Filename) :-
existfile(Filename), !,
write("Loading bicycle database from file: ", Filename), nl,
retractall(bicycle(_, _, _, _, _, _, _)),
consult(Filename),
write("Database loaded successfully!"), nl.
load_database_from_file(Filename) :-
write("File ", Filename, " not found. Creating empty bicycle database."), nl,
retractall(bicycle(_, _, _, _, _, _, _)).
reload_database :-
get_current_filename(Filename),
retractall(bicycle(_, _, _, _, _, _, _)),
load_database_from_file(Filename),
write("Database reloaded from file!"), nl,
wait_for_enter.
% Проверка загрузки
ensure_database_loaded :-
bicycle(_, _, _, _, _, _, _), !.
ensure_database_loaded :-
load_database_from_file.
% Сохранение базы данных
save_database_to_file :-
get_current_filename(Filename),
save_database_to_file(Filename).
save_database_to_file(Filename) :-
write("Saving bicycle database to file: ", Filename), nl,
openwrite(file_pointer, Filename),
writedevice(file_pointer),
save_all_bicycles,
closefile(file_pointer),
writedevice(screen),
write("Database saved successfully!"), nl.
save_all_bicycles :-
bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity),
write("bicycle(\"", Brand, "\",\"", Type, "\",\"", Color, "\",\"", Material, "\",",
Diameter, ",", Price, ",", Quantity, ")"),
nl,
fail.
save_all_bicycles.
% Сохранение в csv
save_database_to_csv :-
ensure_database_loaded,
write("Enter CSV filename: "),
readln(Filename), nl,
save_database_to_csv(Filename).
save_database_to_csv(Filename) :-
ensure_database_loaded,
write("Saving bicycle database to CSV file: ", Filename), nl,
openwrite(file_pointer, Filename),
writedevice(file_pointer),
write("\"Brand\",\"Type\",\"Color\",\"FrameMaterial\",\"WheelDiameter\",\"Price\",\"Quantity\""), nl,
save_all_bicycles_csv,
closefile(file_pointer),
writedevice(screen),
write("CSV file saved"), nl.
save_all_bicycles_csv :-
bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity),
write("\"", Brand, "\",\"", Type, "\",\"", Color, "\",\"", Material, "\",",
Diameter, ",", Price, ",", Quantity),
nl,
fail.
save_all_bicycles_csv.
% Добавление записи
add_bicycle_fact(Brand, Type, Color, Material, Diameter, Price, Quantity) :-
assertz(bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)).
% Редактирование записи
edit_bicycle :-
ensure_database_loaded,
write("Enter brand of bicycle to edit: "),
readln(Brand), nl,
edit_bicycle_by_brand(Brand).
edit_bicycle_by_brand(Brand) :-
bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity), !,
retract(bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)),
write("Found bicycle: "), nl,
print_bicycle(bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)),
nl,
edit_bicycle_menu(bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)),
write("Bicycle updated successfully!"), nl,
wait_for_enter.
edit_bicycle_by_brand(Brand) :-
write("Bicycle '", Brand, "' not found."), nl,
wait_for_enter.
% Меню редактирования
edit_bicycle_menu(bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)) :-
write("=== EDIT BICYCLE ==="), nl,
write("1. Brand: ", Brand), nl,
write("2. Type: ", Type), nl,
write("3. Color: ", Color), nl,
write("4. Frame Material: ", Material), nl,
write("5. Wheel Diameter: ", Diameter), nl,
write("6. Price: ", Price), nl,
write("7. Quantity: ", Quantity), nl,
write("8. Save and exit"), nl,
write("0. Cancel (restore original)"), nl, nl,
write("Select field to edit (0-8): "),
readint(Choice), nl,
edit_bicycle_field(Choice, bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)).
edit_bicycle_field(0, bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)) :-
assertz(bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)),
write("Edit cancelled. Original bicycle restored."), nl.
edit_bicycle_field(8, bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)) :-
assertz(bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)),
write("Changes saved."), nl.
edit_bicycle_field(1, bicycle(_, Type, Color, Material, Diameter, Price, Quantity)) :-
write("Enter new brand: "),
readln(NewBrand), nl,
edit_bicycle_menu(bicycle(NewBrand, Type, Color, Material, Diameter, Price, Quantity)).
edit_bicycle_field(2, bicycle(Brand, _, Color, Material, Diameter, Price, Quantity)) :-
write("Enter new type: "),
readln(NewType), nl,
edit_bicycle_menu(bicycle(Brand, NewType, Color, Material, Diameter, Price, Quantity)).
edit_bicycle_field(3, bicycle(Brand, Type, _, Material, Diameter, Price, Quantity)) :-
write("Enter new color: "),
readln(NewColor), nl,
edit_bicycle_menu(bicycle(Brand, Type, NewColor, Material, Diameter, Price, Quantity)).
edit_bicycle_field(4, bicycle(Brand, Type, Color, _, Diameter, Price, Quantity)) :-
write("Enter new frame material: "),
readln(NewMaterial), nl,
edit_bicycle_menu(bicycle(Brand, Type, Color, NewMaterial, Diameter, Price, Quantity)).
edit_bicycle_field(5, bicycle(Brand, Type, Color, Material, _, Price, Quantity)) :-
read_positive_integer("Enter new wheel diameter (inches): ", NewDiameter), nl,
edit_bicycle_menu(bicycle(Brand, Type, Color, Material, NewDiameter, Price, Quantity)).
edit_bicycle_field(6, bicycle(Brand, Type, Color, Material, Diameter, _, Quantity)) :-
read_positive_integer("Enter new price: ", NewPrice), nl,
edit_bicycle_menu(bicycle(Brand, Type, Color, Material, Diameter, NewPrice, Quantity)).
edit_bicycle_field(7, bicycle(Brand, Type, Color, Material, Diameter, Price, _)) :-
read_positive_integer("Enter new quantity: ", NewQuantity), nl,
edit_bicycle_menu(bicycle(Brand, Type, Color, Material, Diameter, Price, NewQuantity)).
edit_bicycle_field(_, Bike) :-
write("Invalid choice. Please try again."), nl,
edit_bicycle_menu(Bike).
% Вывод
print_all_bicycles :-
ensure_database_loaded,
write("=== BICYCLES DATABASE ==="), nl, nl,
bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity),
print_bicycle(bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)),
fail.
print_all_bicycles :-
write("=== END OF DATABASE ==="), nl.
print_all_bicycles_stepwise :-
ensure_database_loaded,
write("=== BICYCLES DATABASE ==="), nl, nl,
bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity),
print_bicycle(bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)),
wait_for_enter,
fail.
print_all_bicycles_stepwise :-
write("=== END OF DATABASE ==="), nl.
print_bicycle(bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)) :-
write("Brand: ", Brand), nl,
write("Type: ", Type), nl,
write("Color: ", Color), nl,
write("Frame Material: ", Material), nl,
write("Wheel Diameter: ", Diameter, "\""), nl,
write("Price: ", Price, " rub"), nl,
write("Quantity: ", Quantity), nl,
write("-----------------------------------"), nl.
% Чтение числа
read_positive_integer(Prompt, Value) :-
write(Prompt),
readint(Value),
Value > 0, !.
read_positive_integer(Prompt, Value) :-
write("Error: Value must be greater than 0. Please try again."), nl,
read_positive_integer(Prompt, Value).
% Добавление записи
add_bicycle :-
ensure_database_loaded,
write("Enter bicycle brand: "),
readln(Brand), nl,
write("Enter bicycle type: "),
readln(Type), nl,
write("Enter color: "),
readln(Color), nl,
write("Enter frame material: "),
readln(Material), nl,
read_positive_integer("Enter wheel diameter (inches): ", Diameter), nl,
read_positive_integer("Enter price: ", Price), nl,
read_positive_integer("Enter quantity: ", Quantity), nl,
assertz(bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)),
write("Bicycle added successfully!"), nl,
wait_for_enter.
% Удаление записи
delete_bicycle :-
ensure_database_loaded,
write("Enter brand of bicycle to delete: "),
readln(Brand), nl,
delete_bicycle_by_brand(Brand).
delete_bicycle_by_brand(Brand) :-
retract(bicycle(Brand, Type, Color, Material, Diameter, Price, Quantity)), !,
write("Bicycle '", Brand, "' deleted successfully!"), nl,
wait_for_enter.
delete_bicycle_by_brand(Brand) :-
write("Bicycle '", Brand, "' not found."), nl,
wait_for_enter.
change_filename :-
write("Enter new filename (e.g. bikes.txt): "),
readln(NewFilename),
set_current_filename(NewFilename),
write("Current filename changed to: ", NewFilename), nl,
wait_for_enter.
% Ожидание enter
wait_for_enter :-
write("Press Enter to continue..."),
readchar(_),
nl.
% Меню
menu :-
clearwindow,
makewindow(1, 2, 11, "Bicycle Database", 0, 0, 25, 80),
show_current_filename,
write("========================================="), nl,
write(" BICYCLE DATABASE MENU "), nl,
write("========================================="), nl, nl,
write("1. Change database filename"), nl,
write("2. Reload database from file"), nl,
write("3. Show all bicycles"), nl,
write("4. Show bicycles step by step"), nl,
write("5. Save database to file"), nl,
write("6. Add new bicycle"), nl,
write("7. Delete bicycle"), nl,
write("8. Edit bicycle"), nl,
write("9. Export database to CSV"), nl,
write("0. Exit program"), nl, nl,
write("Select option (0-9): "),
readint(N), nl,
action(N).
action(1) :- change_filename, menu.
action(2) :- reload_database, menu.
action(3) :- print_all_bicycles, wait_for_enter, menu.
action(4) :- print_all_bicycles_stepwise, wait_for_enter, menu.
action(5) :- save_database_to_file, wait_for_enter, menu.
action(6) :- add_bicycle, menu.
action(7) :- delete_bicycle, menu.
action(8) :- edit_bicycle, menu.
action(9) :- save_database_to_csv, wait_for_enter, menu.
action(0) :-
write("Exiting Bicycle Database..."), nl,
write("Goodbye!"), nl.
action(_) :-
write("Invalid option. Please try again."), nl,
wait_for_enter,
menu.
GOAL
clearwindow,
set_current_filename("bicycles.txt"),
load_database_from_file,
menu.
Выводы
В ходе выполнения лабораторной работы была разработана функциональная база данных на языке логического программирования Prolog (Turbo Prolog 2.0) для управления базой данных.
