diff --git a/readme.md b/readme.md index 2d8b453e7..3abf58db6 100644 --- a/readme.md +++ b/readme.md @@ -18,7 +18,8 @@ | № | ФИО | Directory name | #0 | #1 | #2 | #3 | #4 | #5 | #6 | #7 | Рейтинг | |----|------------------------------------------------------|-------------------------|----|-----|----|----|----|----|----|----|---------| -| 1 | [Бусень Артём](https:github.com/hudshiy1) |[ii02301](trunk/ii02301) | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | | | 8| + +| 1 | [Бусень Артём](https://github.com/hudshiy1) |[ii02301](trunk/ii02301) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | 8| | 2 | [Волкогон Никита](https://github.com/VolkogonNikita) |[ii02302](trunk/II02302) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | 9| | 3 | [Вышинский Артём](https://github.com/arciomwww) |[ii02303](trunk/ii02303) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | 8| | 4 | [Гавришук Владислав](https://github.com/VLadGavrishuk)|[ii02304](trunk/ii02304)| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | | 7| diff --git a/trunk/ii02301/task_03/doc/1.png b/trunk/ii02301/task_03/doc/1.png new file mode 100644 index 000000000..4da5ff806 Binary files /dev/null and b/trunk/ii02301/task_03/doc/1.png differ diff --git a/trunk/ii02301/task_03/doc/2.png b/trunk/ii02301/task_03/doc/2.png new file mode 100644 index 000000000..f8cbf6c85 Binary files /dev/null and b/trunk/ii02301/task_03/doc/2.png differ diff --git a/trunk/ii02301/task_03/doc/3.png b/trunk/ii02301/task_03/doc/3.png new file mode 100644 index 000000000..4efd5a0c8 Binary files /dev/null and b/trunk/ii02301/task_03/doc/3.png differ diff --git a/trunk/ii02301/task_03/doc/4.png b/trunk/ii02301/task_03/doc/4.png new file mode 100644 index 000000000..72065cfe3 Binary files /dev/null and b/trunk/ii02301/task_03/doc/4.png differ diff --git a/trunk/ii02301/task_03/doc/5.png b/trunk/ii02301/task_03/doc/5.png new file mode 100644 index 000000000..e795ed231 Binary files /dev/null and b/trunk/ii02301/task_03/doc/5.png differ diff --git a/trunk/ii02301/task_03/doc/6.png b/trunk/ii02301/task_03/doc/6.png new file mode 100644 index 000000000..81fbbf343 Binary files /dev/null and b/trunk/ii02301/task_03/doc/6.png differ diff --git a/trunk/ii02301/task_03/doc/7.png b/trunk/ii02301/task_03/doc/7.png new file mode 100644 index 000000000..4d13af4e9 Binary files /dev/null and b/trunk/ii02301/task_03/doc/7.png differ diff --git a/trunk/ii02301/task_03/doc/8.png b/trunk/ii02301/task_03/doc/8.png new file mode 100644 index 000000000..4ba789e30 Binary files /dev/null and b/trunk/ii02301/task_03/doc/8.png differ diff --git a/trunk/ii02301/task_03/doc/report.md b/trunk/ii02301/task_03/doc/report.md new file mode 100644 index 000000000..c7e9bdbda --- /dev/null +++ b/trunk/ii02301/task_03/doc/report.md @@ -0,0 +1,104 @@ +

Министерство образования Республики Беларусь

+

Учреждение образования

+

“Брестский Государственный технический университет”

+

Кафедра ИИТ

+






+

Лабораторная работа №3

+

По дисциплине “Общая теория интеллектуальных систем”

+

Тема: “Разработка редактора графов”

+




+

Выполнил:

+

Студент 2 курса

+

Группы ИИ-23

+

Бусень А.Д..

+

Проверил:

+

Иванюк Д. С.

+




+

Брест 2023

+ + +--- +# Задание: # +1. Разработать и реализовать программный продукт позволяющий +редактировать графовые конструкции различных видов и производить над +ними различные действия. Язык программирования - любой. + +2. Редактор должен позволять (задания со **[\*]** являются необязательными): + a) одновременно работать с несколькими графами (MDI); + b) **[\*]** выделение одновременно нескольких элементов графа, копирование +выделенного фрагмента в clipboard и восстановление из него; + c) задавать имена графам; + d) сохранять и восстанавливать граф во внутреннем формате программы; + e) экспортировать и импортировать граф в текстовый формат (описание +см. ниже); + f) создавать, удалять, именовать, переименовывать, перемещать узлы; + g) создавать ориентированные и неориентированные дуги, удалять дуги; + h) добавлять, удалять и редактировать содержимое узла (содержимое в +виде текста и ссылки на файл); + i) задавать цвет дуги и узла, образ узла; + j) **[\*]** создавать и отображать петли; + k) **[\*]** создавать и отображать кратные дуги. + +3. Программный продукт должен позволять выполнять следующие операции: + a) выводить информацию о графе: + + + количество вершин, дуг; + + степени для всех вершин и для выбранной вершины; + + матрицу инцидентности; + + матрицу смежности; + + является ли он деревом, полным, связанным, эйлеровым, **[\*]** планарным; + + b) поиск всех путей (маршрутов) между двумя узлами и кратчайших; + c) вычисление расстояния между двумя узлами; + d) вычисление диаметра, радиуса, центра графа; + e) **[\*]** вычисление векторного и декартово произведения двух графов; + f) **[\*]** раскраска графа; + g) нахождения эйлеровых, [*] гамильтоновых циклов; + h) **[\*]** поиск подграфа в графе, со всеми или некоторыми неизвестными + узлами; + i) **[\*]** поиск узла по содержимому; + j) **[\*]** объединение, пересечение, сочетание и дополнение графов; + k) **[\*]** приведение произвольного графа к определенному типу с + минимальными изменениями: + + + бинарное и обычное дерево; + + полный граф; + + планарный граф; + + связанный граф; + +4. Формат текстового представления графа: +<ГРАФ> ::= <ИМЯ ГРАФА> : UNORIENT | ORIENT ; <ОПИСАНИЕ УЗЛОВ> ; +<ОПИСАНИЕ СВЯЗЕЙ> . +<ИМЯ ГРАФА> ::= <ИДЕНТИФИКАТОР> +<ОПИСАНИЕ УЗЛОВ> ::= <ИМЯ УЗЛА> [ , <ИМЯ УЗЛА> …] +<ИМЯ УЗЛА> ::= <ИДЕНТИФИКАТОР> +<ОПИСАНИЕ СВЯЗЕЙ> ::= <ИМЯ УЗЛА> -> <ИМЯ УЗЛА> [ , <ИМЯ УЗЛА> …] ; +[<ОПИСАНИЕ СВЯЗЕЙ> …] + +5. Написать отчет по выполненной лабораторной работе в .md формате (readme.md). Разместить его в следующем каталоге: **trunk\ii0xxyy\task_03\doc** (где **xx** - номер группы, **yy** - номер студента, например **ii02301**). + +6. Исходный код разработанной программы разместить в каталоге: **trunk\ii0xxyy\task_03\src** +7. Данная задача реализована на языке python. +# Описание работы программы: # +## Главное окно программы +![Окно программы](1.png) + +## Создаение вершины +![Создание вершин](2.png) + +## Соединение вершины ребрами +![Соединение ребрами](3.png) +![Соединение ребрами](4.png) + +## Изменение цвета вершин, ребер и передвижение их +![Изменение цвета, передвижение](5.png) + +## Можем сохранить граф во внутреннем формате или экспортировать в текстовый файл +![Сохранение, экспорт](6.png) + +## Можем применить алгоритмы +![Алгоритмы](7.png) + +## Можем построить граф по матрице смежности +![Построение по матрице смежности](8.png) + diff --git a/trunk/ii02301/task_03/src/CMakeLists.txt b/trunk/ii02301/task_03/src/CMakeLists.txt new file mode 100644 index 000000000..59d2f9e54 --- /dev/null +++ b/trunk/ii02301/task_03/src/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.6) + +project(OTIS_03) + +set(SOURCES otis03.cpp) + +add_executable(MExecutable3 ${SOURCES}) diff --git a/trunk/ii02301/task_03/src/main.py b/trunk/ii02301/task_03/src/main.py new file mode 100644 index 000000000..caab5f414 --- /dev/null +++ b/trunk/ii02301/task_03/src/main.py @@ -0,0 +1,290 @@ +import tkinter as tk +from tkinter import messagebox, simpledialog +import tkinter.colorchooser as colorchooser + +click_number = 0 +id_of_the_edge = 0 +oval_id = None +ovals = [] +edges = [] +i = 0 +id_text = 0 +tag = 0 +x1, y1, x2, y2 = 0, 0, 0, 0 +button_1="" +text_on_vertex='text on vertex' +id_text='id text' +num_of_vertex='num of vertex' +root = tk.Tk() +canvas=tk.canvas(root) +main_label =tk.Label() +cord_edge2 = {'id_vertex1': [], 'id_vertex2': []} +cord_edge = {'id_edge_text': [], 'id_vertex1': [], 'id_vertex2': []} +cord = {'id': [], id_text: [], text_on_vertex: [], 'textID': [], num_of_vertex: [], 'coordinatesX': [], + 'coordinatesY': []} +visited = [] +matrix = [] + + +def draw_vertex(): + main_label.configure(text="Выбрано создание вершин, нажмите на пустое для создания вершины") + canvas.unbind(button_1) + canvas.bind(button_1, draw_canvas1) + + +def draw_canvas1(event): + global oval_id, i, tag, id_text + id_text += 1 + i += 1 + itext = str(i) + x, y = event.x, event.y + tag = 'oval' + str(id_text) + texttag = 'text' + str(id_text) + cord["num of vertex"].append(id_text) + cord[id_text].append(tag) + cord["coordinatesX"].append(x) + cord["coordinatesY"].append(y) + oval_id = canvas.create_oval(x - 15, y - 15, x + 15, y + 15, fill='red', tags=tag) + ovals.append(oval_id) + cord['id'].append(oval_id) + canvas.create_text(x, y, text=itext, font="Arial 13", tags=texttag) + cord['textID'].append(texttag) + cord[text_on_vertex].append(itext) + + +def draw_edge(): + main_label.configure(text="Выбрано создание ребер, нажмите на вершину для создания ребра") + canvas.unbind(button_1) + canvas.bind(button_1, draw_canvas2) + + +def draw_canvas2(event): + global click_number, x1, y1, x2, y2, id_of_the_edge + if click_number == 0: + for x in ovals: + if canvas.find_overlapping(event.x, event.y, event.x, event.y)[0] == x: + x1 = cord['coordinatesX'][cord['id'].index(x)] + y1 = cord['coordinatesY'][cord['id'].index(x)] + cord_edge['id_vertex1'].append(x) + cord_edge2['id_vertex1'].append(x) + click_number = 1 + main_label.configure(text="Выбор второй вершины для рисования ребра графа") + elif click_number == 1: + for x in ovals: + if canvas.find_overlapping(event.x, event.y, event.x, event.y)[0] == x: + x2 = cord['coordinatesX'][cord['id'].index(x)] + y2 = cord['coordinatesY'][cord['id'].index(x)] + cord_edge['id_vertex2'].append(x) + cord_edge2['id_vertex2'].append(x) + tag_edge = 'edge' + str(id_of_the_edge) + line = canvas.create_line(x1, y1, x2, y2, width=4, tags=tag_edge) + edges.append(id_of_the_edge) + cord_edge['id_edge_text'].append(tag_edge) + id_of_the_edge += 1 + canvas.tag_lower(line) + click_number = 0 + main_label.configure(text="Выберите нужную вершину для рисования ребра графа") + + +def delete_vertex(): + main_label.configure(text="Выбрано удаление вершины или ребра, нажмите на вершину или ребро для удаления") + canvas.unbind(button_1) + canvas.bind(button_1, delete_canvas) + + +def delete_canvas(event): + for x in ovals: + if canvas.find_overlapping(event.x, event.y, event.x, event.y)[0] == x: + canvas.delete(x) + canvas.delete(cord['textID'][cord['id'].index(x)]) + ovals.remove(x) + cord[num_of_vertex].remove(cord[num_of_vertex][cord['id'].index(x)]) + canvas.delete(cord[id_text][cord['id'].index(x)]) + cord['textID'].remove(cord['textID'][cord['id'].index(x)]) + cord[id_text].remove(cord[id_text][cord['id'].index(x)]) + cord["coordinatesX"].remove(cord['coordinatesX'][cord['id'].index(x)]) + cord["coordinatesY"].remove(cord['coordinatesY'][cord['id'].index(x)]) + cord[text_on_vertex].remove(cord[text_on_vertex][cord['id'].index(x)]) + cord['id'].remove(x) + break + for y in edges: + tag_edge = 'edge' + str(y) + if canvas.find_overlapping(event.x, event.y, event.x, event.y)[0] == canvas.find_withtag(tag_edge)[0]: + canvas.delete(tag_edge) + cord_edge['id_vertex1'].remove(cord_edge['id_vertex1'][edges.index(y)]) + cord_edge['id_vertex2'].remove(cord_edge['id_vertex2'][edges.index(y)]) + edges.remove(y) + break + + +def rename_vertex(): + main_label.configure(text="Выбрано переименование вершины, нажмите на вершину для переименования") + canvas.unbind(button_1) + canvas.bind(button_1, rename) + + +def rename(event): + for x in ovals: + if canvas.find_overlapping(event.x, event.y, event.x, event.y)[0] == x: + new_name = simpledialog.askstring("Rename", "Enter new name") + canvas.delete(cord['textID'][cord['id'].index(x)]) + canvas.create_text(cord['coordinatesX'][cord['id'].index(x)], cord['coordinatesY'][cord['id'].index(x)], + text=new_name, font="Arial 13", tags=(cord['textID'][cord['id'].index(x)])) + cord[text_on_vertex][cord['id'].index(x)] = new_name + break + + +def change_color(): + main_label.configure(text="Вы выбрали изменение цвета вершины, нажмите на вершину для изменения её цвета") + canvas.unbind(button_1) + canvas.bind(button_1, color) + + +def color(event): + for x in ovals: + if canvas.find_overlapping(event.x, event.y, event.x, event.y)[0] == x: + new_color = colorchooser.askcolor() + color_hex = new_color[1] + canvas.itemconfig(x, fill=color_hex) + break + + +def change_text_color(): + main_label.configure(text="Вы выбрали изменение цвета текста, нажмите на вершину для изменения цвета её текста") + canvas.unbind(button_1) + canvas.bind(button_1, text_color) + + +def text_color(event): + for x in ovals: + if canvas.find_overlapping(event.x, event.y, event.x, event.y)[0] == x: + new_color = colorchooser.askcolor() + color_hex = new_color[1] + canvas.itemconfig(cord['textID'][cord['id'].index(x)], fill=color_hex) + break + + +def change_edge_color(): + main_label.configure(text="Вы выбрали изменение цвета ребер, нажмите на ребро для изменения его цвета") + canvas.unbind(button_1) + canvas.bind(button_1, edge_color) + + +def edge_color(event): + for x in edges: + tag_edge = 'edge' + str(x) + if canvas.find_overlapping(event.x, event.y, event.x, event.y)[0] == canvas.find_withtag(tag_edge)[0]: + new_color = colorchooser.askcolor() + color_hex = new_color[1] + canvas.itemconfig(tag_edge, fill=color_hex) + break + + +def adjacency_matrix(): + k = 0 + adj_matrix = tk.Tk() + adj_matrix.title("Adjacency matrix") + adj_matrix.geometry("150x150") + matrix = [[0 for _ in range(len(ovals))] for _ in range(len(ovals))] + for index in enumerate(cord_edge['id_vertex1']): + matrix[cord['id'].index(cord_edge['id_vertex1'][index])][cord['id'].index(cord_edge['id_vertex2'][index])] = 1 + matrix[cord['id'].index(cord_edge['id_vertex2'][index])][cord['id'].index(cord_edge['id_vertex1'][index])] = 1 + + for row in matrix: + adj_matrix_label = tk.Label(adj_matrix, text=str(row)) + adj_matrix_label.grid(row=k, column=0) + k += 1 + + +def incidence_matrix(): + k = 0 + inc_matrix = tk.Tk() + inc_matrix.title("Incidence matrix") + inc_matrix.geometry("150x150") + matrix = [[0 for _ in range(len(edges))] for _ in range(len(ovals))] + for index in enumerate(cord_edge['id_vertex1']): + matrix[cord['id'].index(cord_edge['id_vertex1'][index])][edges.index(cord_edge['id_edge_text'].index( + cord_edge['id_edge_text'][index]))] = 1 + matrix[cord['id'].index(cord_edge['id_vertex2'][index])][edges.index(cord_edge['id_edge_text'].index( + cord_edge['id_edge_text'][index]))] = 1 + + for row in matrix: + inc_matrix_label = tk.Label(inc_matrix, text=str(row)) + inc_matrix_label.grid(row=k, column=0) + k += 1 + + +def dfs(): + visited = [False] * len(ovals) + + def dfs_rec(vert): + visited[vert] = True + for u in range(len(ovals)): + if matrix[vert][u] == 1 and not visited[u]: + dfs_rec(u) + + count = 0 + for v in range(len(ovals)): + if not visited[v]: + dfs_rec(v) + count += 1 + if count == 1: + messagebox.showinfo("DFS", "Graph is connected") + else: + messagebox.showinfo("DFS", "Graph is not connected") + + +def bfs(): + visited = [False] * len(ovals) + + def bfs_rec(vert): + visited[vert] = True + for u in range(len(ovals)): + if matrix[vert][u] == 1 and not visited[u]: + bfs_rec(u) + + count = 0 + for v in range(len(ovals)): + if not visited[v]: + bfs_rec(v) + count += 1 + if count == 1: + messagebox.showinfo("BFS", "Graph is connected") + else: + messagebox.showinfo("BFS", "Graph is not connected") + + +root = tk.Tk() +root.geometry("800x600") + +frame = tk.Frame(root) +frame.pack(fill=tk.BOTH, expand=True) + +canvas = tk.Canvas(frame, width=1920, height=1080) +canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + +menubar = tk.Menu(root) +root.config(menu=menubar) + + +graphmenu = tk.Menu(menubar, tearoff=0) +menubar.add_cascade(label="Граф", menu=graphmenu) +graphmenu.add_command(label="Рисование вершины", command=draw_vertex) +graphmenu.add_command(label="Рисование ребра", command=draw_edge) +graphmenu.add_command(label="Удаление вершины или ребера", command=delete_vertex) + +redmenu = tk.Menu(menubar, tearoff=0) +menubar.add_cascade(label="Редактирование графа", menu=redmenu) +redmenu.add_command(label="Переименование вершины", command=rename_vertex) +redmenu.add_command(label="Перекрашивание вершины", command=change_color) +redmenu.add_command(label="Перекрашивание текста", command=change_text_color) +redmenu.add_command(label="Перекрашивание ребра", command=change_edge_color) + +algmenu = tk.Menu(menubar, tearoff=0) +menubar.add_cascade(label="Алгоритмы графа", menu=algmenu) +algmenu.add_command(label="Вывод матрицы смежности", command=adjacency_matrix) +algmenu.add_command(label="Вывод матрицы инцидентности", command=incidence_matrix) +algmenu.add_command(label="Поиск в глубину по графу", command=dfs) +algmenu.add_command(label="Поиск в ширину по графу", command=bfs) + +root.mainloop() diff --git a/trunk/ii02301/task_03/src/otis03.cpp b/trunk/ii02301/task_03/src/otis03.cpp new file mode 100644 index 000000000..c1c6d92f4 --- /dev/null +++ b/trunk/ii02301/task_03/src/otis03.cpp @@ -0,0 +1,6 @@ +#include + +int main() { + std::system("python main.py");// c++ + return 0; +} \ No newline at end of file