diff --git a/SolovevDS/docs/data/data_for_task1/data_structures.py b/SolovevDS/docs/data/data_for_task1/data_structures.py
new file mode 100644
index 0000000..0f5879a
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task1/data_structures.py
@@ -0,0 +1,203 @@
+#--------------------------------------Связный список--------------------------
+def ll_insert(head, name, phone):
+ # 1. если список пуст → новый элемент становится head
+ if head is None:
+ return {'name': name, 'phone': phone,'next': None}
+
+ current = head
+ # 2. сначала проверим — может имя уже есть → тогда просто обновим
+ while current is not None:
+ if current['name'] == name:
+ current['phone'] = phone
+ return head
+ current = current['next']
+ # 3. идём до конца списка
+ current = head
+ while current['next'] is not None:
+ current = current['next']
+ # 4. добавляем новый узел в конец
+ current['next'] = {'name': name,'phone': phone,'next': None}
+
+ return head
+
+
+def ll_find(head, name):
+ current = head
+
+ while current is not None:
+ if current['name'] == name:
+ return current['phone']
+
+ current = current['next']
+
+ return None
+
+def ll_delete(head, name):
+ current = head
+ previous = None
+
+ while current is not None:
+ if current['name'] == name:
+
+ # 1. удаляем голову списка
+ if previous is None:
+ return current['next']
+
+ # 2. удаляем середину или конец
+ previous['next'] = current['next']
+ return head
+
+ previous = current
+ current = current['next']
+
+ return head # если не нашли
+
+def ll_list_all(head):
+ result = []
+ current = head
+ # 1. проходим по списку
+ while current is not None:
+ result.append((current['name'], current['phone']))
+ current = current['next']
+ # 2. сортируем по имени
+ result.sort(key=lambda x: x[0])
+
+ return result
+
+
+#----------------------------------HASH-таблица--------------------------------
+def my_hash(s, M):
+ B = 31
+ n = len(s)
+ h = 0
+ for i in range(n):
+ h += ord(s[i]) * (B ** (n - 1 - i))
+ return h % M
+
+def ht_insert(buckets, name, phone):
+ index = my_hash(name, len(buckets))
+ buckets[index] = ll_insert(buckets[index], name, phone)
+ return buckets
+
+
+def ht_find(buckets, name):
+ index = my_hash(name, len(buckets))
+ return ll_find(buckets[index], name)
+
+def ht_delete(buckets, name):
+ index = my_hash(name, len(buckets))
+ buckets[index] = ll_delete(buckets[index], name)
+ return buckets
+
+def ht_list_all(buckets):
+ result = []
+ for i in range(len(buckets)):
+ result += ll_list_all(buckets[i])
+ result.sort(key=lambda x: x[0])
+ return result
+
+#---------------------------Двоичное дерево поиска-----------------------------
+def bst_insert(root, name, phone):
+ if root is None:
+ return {'name': name, 'phone': phone,'left': None, 'right': None}
+
+ current = root
+ while True:
+ # если такое имя уже есть — меняем телефон
+ if name == current['name']:
+ current['phone'] = phone
+ return root
+
+ # если новое имя меньше — идём влево
+ if name < current['name']:
+ if current['left'] is None:
+ current['left'] = {'name': name, 'phone': phone,'left': None, 'right': None}
+ return root
+ current = current['left']
+
+ # если новое имя больше — идём вправо
+ else:
+ if current['right'] is None:
+ current['right'] = {'name': name, 'phone': phone,'left': None, 'right': None}
+ return root
+ current = current['right']
+
+def bst_find(root, name):
+ current = root
+
+ while current is not None:
+ if name == current['name']:
+ return current['phone']
+
+ if name < current['name']:
+ current = current['left']
+ else:
+ current = current['right']
+
+ return None
+
+def bst_delete(root, name):
+ current = root
+ previous = None
+
+ while current is not None and current['name'] != name:
+ previous = current
+
+ if name < current['name']:
+ current = current['left']
+ else:
+ current = current['right']
+
+ # если не нашли
+ if current is None:
+ return root
+
+ # 2. Если у узла два потомка
+ if current['left'] is not None and current['right'] is not None:
+ successor_parent = current
+ successor = current['right']
+
+ # ищем минимальный узел в правом поддереве
+ while successor['left'] is not None:
+ successor_parent = successor
+ successor = successor['left']
+
+ # копируем данные successor в current
+ current['name'] = successor['name']
+ current['phone'] = successor['phone']
+
+ # теперь удаляем successor
+ current = successor
+ previous = successor_parent
+ #3
+ if current['left'] is not None:
+ child = current['left']
+ else:
+ child = current['right']
+
+ # 4. Если удаляем корень
+ if previous is None:
+ return child
+
+ # 5. Переподключаем родителя
+ if previous['left'] is current:
+ previous['left'] = child
+ else:
+ previous['right'] = child
+
+ return root
+
+def bst_list_all(root):
+ result = []
+
+ def inorder(node):
+ if node is None:
+ return
+
+ inorder(node['left'])
+ result.append((node['name'], node['phone']))
+ inorder(node['right'])
+
+ inorder(root)
+ return result
+
diff --git a/SolovevDS/docs/data/data_for_task1/delete_chart.svg b/SolovevDS/docs/data/data_for_task1/delete_chart.svg
new file mode 100644
index 0000000..a76383b
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task1/delete_chart.svg
@@ -0,0 +1,1298 @@
+
+
+
diff --git a/SolovevDS/docs/data/data_for_task1/diagramm.py b/SolovevDS/docs/data/data_for_task1/diagramm.py
new file mode 100644
index 0000000..222ff2d
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task1/diagramm.py
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri May 1 11:42:31 2026
+
+@author: ddima
+"""
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+data = {
+ ("LinkedList", "shuffled", "insert"): 3.46348492,
+ ("HashTable", "shuffled", "insert"): 0.01967166,
+ ("BST", "shuffled", "insert"): 0.01715242,
+
+ ("LinkedList", "shuffled", "find"): 0.0301834,
+ ("HashTable", "shuffled", "find"): 0.0002298400002,
+ ("BST", "shuffled", "find"): 0.0002346200003,
+
+ ("LinkedList", "shuffled", "delete"): 0.01254974,
+ ("HashTable", "shuffled", "delete"): 0.0001220800004,
+ ("BST", "shuffled", "delete"): 0.0001421199995,
+
+ ("LinkedList", "sorted", "insert"): 3.2739972,
+ ("HashTable", "sorted", "insert"): 0.01923022,
+ ("BST", "sorted", "insert"): 4.01406982,
+
+ ("LinkedList", "sorted", "find"): 0.0252881,
+ ("HashTable", "sorted", "find"): 0.0002579799999,
+ ("BST", "sorted", "find"): 0.0369953,
+
+ ("LinkedList", "sorted", "delete"): 0.01326564,
+ ("HashTable", "sorted", "delete"): 0.0001182399996,
+ ("BST", "sorted", "delete"): 0.02074794,
+}
+
+structures = ["BST", "LinkedList", "HashTable"]
+structure_labels = ["Бинарное дерево", "Связный список", "Хэш-таблица"]
+
+operations = [("insert", "Вставка"), ("find", "Поиск"), ("delete", "Удаление"),]
+
+for op_key, op_title in operations:
+ shuffled_values = [data[(s, "shuffled", op_key)] for s in structures]
+ sorted_values = [data[(s, "sorted", op_key)] for s in structures]
+
+ x = np.arange(len(structures))
+ width = 0.35
+
+ plt.figure(figsize=(8, 5))
+
+ plt.bar(x - width / 2, shuffled_values, width, label="Случайный")
+ plt.bar(x + width / 2, sorted_values, width, label="Отсортированный")
+
+ plt.title(op_title)
+ plt.ylabel("Время (сек)")
+ plt.xticks(x, structure_labels)
+ plt.legend()
+ plt.grid(axis="y", alpha=0.3)
+ plt.tight_layout()
+
+ plt.savefig(f"{op_key}_chart.svg", format="svg")
+ plt.show()
\ No newline at end of file
diff --git a/SolovevDS/docs/data/data_for_task1/experements_with_structures.py b/SolovevDS/docs/data/data_for_task1/experements_with_structures.py
new file mode 100644
index 0000000..3aaf000
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task1/experements_with_structures.py
@@ -0,0 +1,240 @@
+import data_structures as st
+import time
+import random
+import csv
+
+
+def generate_records(N):
+ records = []
+
+ for i in range(N):
+ name = f"User_{i:05d}"
+ phone = f"+7{random.randint(10**9, 10**10 - 1)}"
+ records.append((name, phone))
+
+ records_shuffled = records[:]
+ random.shuffle(records_shuffled)
+
+ records_sorted = sorted(records, key=lambda x: x[0])
+
+ return records_shuffled, records_sorted
+
+def linked_list_build_structure(records):
+ head = None
+
+ for name, phone in records:
+ head = st.ll_insert(head, name, phone)
+
+ return head
+
+def hash_table_build_structure(records):
+ buckets = [None] * 10007
+
+ for name, phone in records:
+ buckets = st.ht_insert(buckets, name, phone)
+
+ return buckets
+
+def bst_build_structure(records):
+ root = None
+
+ for name, phone in records:
+ root = st.bst_insert(root, name, phone)
+
+ return root
+
+def measure_time(func, *args):
+ start = time.perf_counter()
+ result = func(*args)
+ end = time.perf_counter()
+
+ return result, end - start
+
+def prepare_find_names(records):
+ existing_names = [name for name, phone in records]
+
+ find_existing = random.sample(existing_names, 100)
+
+ find_missing = []
+ for i in range(10):
+ find_missing.append(f"None_{i}")
+ find_names = find_existing + find_missing
+ return find_names
+
+
+def linked_list_find(head, find_names):
+ results = []
+ for name in find_names:
+ phone = st.ll_find(head, name)
+ results.append(phone)
+ return results
+
+def hash_table_find(buckets, find_names):
+ results = []
+ for name in find_names:
+ phone = st.ht_find(buckets, name)
+ results.append(phone)
+ return results
+
+def bst_find(root, find_names):
+ results = []
+ for name in find_names:
+ phone = st.bst_find(root, name)
+ results.append(phone)
+ return results
+
+def prepare_delete_names(records):
+ existing_names = [name for name, phone in records]
+ delete_names = random.sample(existing_names, 50)
+ return delete_names
+
+
+def linked_list_delete(head, delete_names):
+ for name in delete_names:
+ head = st.ll_delete(head, name)
+ return head
+
+def hash_table_delete(buckets, delete_names):
+ for name in delete_names:
+ buckets = st.ht_delete(buckets, name)
+ return buckets
+
+def bst_delete(root, delete_names):
+ for name in delete_names:
+ root = st.bst_delete(root, name)
+ return root
+
+
+def run_one_experiment(records_shuffled, records_sorted, find_names, delete_names):
+ one_run_results = []
+ #------------------------ создание структур + замер времени заполнения -------------------------
+ # ------------------- shuffled -------------------
+ head_shuffled, ll_insert_time_shuffled = measure_time(linked_list_build_structure,records_shuffled)
+
+ buckets_shuffled, ht_insert_time_shuffled = measure_time(hash_table_build_structure,records_shuffled)
+
+ root_shuffled, bst_insert_time_shuffled = measure_time(bst_build_structure,records_shuffled)
+
+
+ # ------------------- sorted -------------------
+
+ head_sorted, ll_insert_time_sorted = measure_time(linked_list_build_structure,records_sorted)
+
+ buckets_sorted, ht_insert_time_sorted = measure_time(hash_table_build_structure,records_sorted)
+
+ root_sorted, bst_insert_time_sorted = measure_time(bst_build_structure,records_sorted)
+
+
+
+ # ------------------- поиск в shuffled -------------------
+
+ ll_find_results_shuffled, ll_find_time_shuffled = measure_time(linked_list_find,head_shuffled,find_names)
+
+ ht_find_results_shuffled, ht_find_time_shuffled = measure_time(hash_table_find,buckets_shuffled,find_names)
+
+ bst_find_results_shuffled, bst_find_time_shuffled = measure_time(bst_find,root_shuffled,find_names)
+
+
+ # ------------------- поиск в sorted -------------------
+
+ ll_find_results_sorted, ll_find_time_sorted = measure_time(linked_list_find,head_sorted,find_names)
+
+ ht_find_results_sorted, ht_find_time_sorted = measure_time(hash_table_find,buckets_sorted,find_names)
+
+ bst_find_results_sorted, bst_find_time_sorted = measure_time(bst_find,root_sorted,find_names)
+
+
+
+ # ------------------- удаление в shuffled -------------------
+
+ head_shuffled, ll_delete_time_shuffled = measure_time(linked_list_delete,head_shuffled,delete_names)
+
+ buckets_shuffled, ht_delete_time_shuffled = measure_time(hash_table_delete,buckets_shuffled,delete_names)
+
+ root_shuffled, bst_delete_time_shuffled = measure_time(bst_delete,root_shuffled,delete_names)
+
+ # ------------------- удаление в sorted -------------------
+
+ head_sorted, ll_delete_time_sorted = measure_time(linked_list_delete,head_sorted,delete_names)
+
+ buckets_sorted, ht_delete_time_sorted = measure_time(hash_table_delete,buckets_sorted,delete_names)
+
+ root_sorted, bst_delete_time_sorted = measure_time(bst_delete,root_sorted,delete_names)
+
+ one_run_results.append(["LinkedList", "shuffled", "insert", ll_insert_time_shuffled])
+ one_run_results.append(["HashTable", "shuffled", "insert", ht_insert_time_shuffled])
+ one_run_results.append(["BST", "shuffled", "insert", bst_insert_time_shuffled])
+
+ one_run_results.append(["LinkedList", "shuffled", "find", ll_find_time_shuffled])
+ one_run_results.append(["HashTable", "shuffled", "find", ht_find_time_shuffled])
+ one_run_results.append(["BST", "shuffled", "find", bst_find_time_shuffled])
+
+ one_run_results.append(["LinkedList", "shuffled", "delete", ll_delete_time_shuffled])
+ one_run_results.append(["HashTable", "shuffled", "delete", ht_delete_time_shuffled])
+ one_run_results.append(["BST", "shuffled", "delete", bst_delete_time_shuffled])
+
+ one_run_results.append(["LinkedList", "sorted", "insert", ll_insert_time_sorted])
+ one_run_results.append(["HashTable", "sorted", "insert", ht_insert_time_sorted])
+ one_run_results.append(["BST", "sorted", "insert", bst_insert_time_sorted])
+
+ one_run_results.append(["LinkedList", "sorted", "find", ll_find_time_sorted])
+ one_run_results.append(["HashTable", "sorted", "find", ht_find_time_sorted])
+ one_run_results.append(["BST", "sorted", "find", bst_find_time_sorted])
+
+ one_run_results.append(["LinkedList", "sorted", "delete", ll_delete_time_sorted])
+ one_run_results.append(["HashTable", "sorted", "delete", ht_delete_time_sorted])
+ one_run_results.append(["BST", "sorted", "delete", bst_delete_time_sorted])
+
+ return one_run_results
+
+
+N = 10000
+REPEATS = 5
+records_shuffled, records_sorted = generate_records(N)
+find_names = prepare_find_names(records_sorted)
+delete_names = prepare_delete_names(records_sorted)
+
+results = [["Запуск", "Структура", "Режим", "Операция", "Время (сек)"]]
+
+for run in range(1, REPEATS + 1):
+ print("Запуск эксперимента:", run)
+
+ one_run_results = run_one_experiment(records_shuffled,records_sorted,find_names,delete_names)
+
+ for row in one_run_results:
+ structure = row[0]
+ mode = row[1]
+ operation = row[2]
+ elapsed = row[3]
+
+ results.append([run, structure, mode, operation, elapsed])
+
+groups = {}
+
+for row in results[1:]:
+ structure = row[1]
+ mode = row[2]
+ operation = row[3]
+ elapsed = row[4]
+
+ key = (structure, mode, operation)
+
+ if key not in groups:
+ groups[key] = []
+
+ groups[key].append(elapsed)
+
+
+for key, times in groups.items():
+ structure, mode, operation = key
+ avg_time = sum(times) / len(times)
+
+ results.append(["average", structure, mode, operation, avg_time])
+
+
+with open("results.csv", "w", newline="", encoding="utf-8") as f:
+ writer = csv.writer(f)
+ writer.writerows(results)
+
+print("Результаты сохранены в results.csv")
+
diff --git a/SolovevDS/docs/data/data_for_task1/find_chart.svg b/SolovevDS/docs/data/data_for_task1/find_chart.svg
new file mode 100644
index 0000000..24d75bf
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task1/find_chart.svg
@@ -0,0 +1,1282 @@
+
+
+
diff --git a/SolovevDS/docs/data/data_for_task1/insert_chart.svg b/SolovevDS/docs/data/data_for_task1/insert_chart.svg
new file mode 100644
index 0000000..dc6bc2b
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task1/insert_chart.svg
@@ -0,0 +1,1296 @@
+
+
+
diff --git a/SolovevDS/docs/data/data_for_task1/results.csv b/SolovevDS/docs/data/data_for_task1/results.csv
new file mode 100644
index 0000000..9e8a000
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task1/results.csv
@@ -0,0 +1,109 @@
+Запуск,Структура,Режим,Операция,Время (сек)
+1,LinkedList,shuffled,insert,3.4127272000005178
+1,HashTable,shuffled,insert,0.019356400000106078
+1,BST,shuffled,insert,0.01772239999991143
+1,LinkedList,shuffled,find,0.029260500003147172
+1,HashTable,shuffled,find,0.00023599999985890463
+1,BST,shuffled,find,0.00022670000180369243
+1,LinkedList,shuffled,delete,0.011755700001231162
+1,HashTable,shuffled,delete,0.00011840000297524966
+1,BST,shuffled,delete,0.00014689999807160348
+1,LinkedList,sorted,insert,3.2256927999987965
+1,HashTable,sorted,insert,0.019139899999572663
+1,BST,sorted,insert,4.1095220999995945
+1,LinkedList,sorted,find,0.024785800000245217
+1,HashTable,sorted,find,0.00022289999833446927
+1,BST,sorted,find,0.03631210000094143
+1,LinkedList,sorted,delete,0.012450800000806339
+1,HashTable,sorted,delete,0.00011539999832166359
+1,BST,sorted,delete,0.0211152999982005
+2,LinkedList,shuffled,insert,3.3890004999993835
+2,HashTable,shuffled,insert,0.019052899999223882
+2,BST,shuffled,insert,0.01668930000232649
+2,LinkedList,shuffled,find,0.028735200001392514
+2,HashTable,shuffled,find,0.00022629999875789508
+2,BST,shuffled,find,0.00024219999977503903
+2,LinkedList,shuffled,delete,0.01258820000293781
+2,HashTable,shuffled,delete,0.00011489999815239571
+2,BST,shuffled,delete,0.00014340000052470714
+2,LinkedList,sorted,insert,3.256336700000247
+2,HashTable,sorted,insert,0.018892399999458576
+2,BST,sorted,insert,3.978548999999475
+2,LinkedList,sorted,find,0.02532219999920926
+2,HashTable,sorted,find,0.00022780000290367752
+2,BST,sorted,find,0.036961199999495875
+2,LinkedList,sorted,delete,0.013499500000762055
+2,HashTable,sorted,delete,0.00011860000086016953
+2,BST,sorted,delete,0.02029960000072606
+3,LinkedList,shuffled,insert,3.4580803999997443
+3,HashTable,shuffled,insert,0.019483100000798004
+3,BST,shuffled,insert,0.017162699998152675
+3,LinkedList,shuffled,find,0.029887100001360523
+3,HashTable,shuffled,find,0.00023090000104275532
+3,BST,shuffled,find,0.00023660000078962184
+3,LinkedList,shuffled,delete,0.01279649999924004
+3,HashTable,shuffled,delete,0.00014880000162520446
+3,BST,shuffled,delete,0.0001424999973096419
+3,LinkedList,sorted,insert,3.3060915999994904
+3,HashTable,sorted,insert,0.020634799999243114
+3,BST,sorted,insert,3.999759400001494
+3,LinkedList,sorted,find,0.025299299999460345
+3,HashTable,sorted,find,0.00022419999731937423
+3,BST,sorted,find,0.03626530000110506
+3,LinkedList,sorted,delete,0.012905700001283549
+3,HashTable,sorted,delete,0.00012069999866071157
+3,BST,sorted,delete,0.020299800002248958
+4,LinkedList,shuffled,insert,3.490586699997948
+4,HashTable,shuffled,insert,0.020179600000119535
+4,BST,shuffled,insert,0.017119400003139162
+4,LinkedList,shuffled,find,0.030576699999073753
+4,HashTable,shuffled,find,0.00022309999985736795
+4,BST,shuffled,find,0.00023399999918183312
+4,LinkedList,shuffled,delete,0.012583200001245132
+4,HashTable,shuffled,delete,0.00011319999975967221
+4,BST,shuffled,delete,0.00013839999883202836
+4,LinkedList,sorted,insert,3.2922638000018196
+4,HashTable,sorted,insert,0.018590499999845633
+4,BST,sorted,insert,4.008463900001516
+4,LinkedList,sorted,find,0.025681600000098115
+4,HashTable,sorted,find,0.0002204000011261087
+4,BST,sorted,find,0.0370997999998508
+4,LinkedList,sorted,delete,0.013347899999644142
+4,HashTable,sorted,delete,0.00011789999916800298
+4,BST,sorted,delete,0.021108500000991626
+5,LinkedList,shuffled,insert,3.567029800000455
+5,HashTable,shuffled,insert,0.020286300001316704
+5,BST,shuffled,insert,0.017068300003302284
+5,LinkedList,shuffled,find,0.0324575000013283
+5,HashTable,shuffled,find,0.00023290000171982683
+5,BST,shuffled,find,0.00023359999977401458
+5,LinkedList,shuffled,delete,0.013025099997321377
+5,HashTable,shuffled,delete,0.00011509999967529438
+5,BST,shuffled,delete,0.00013940000280854292
+5,LinkedList,sorted,insert,3.289601099997526
+5,HashTable,sorted,insert,0.01889350000055856
+5,BST,sorted,insert,3.9740547000001243
+5,LinkedList,sorted,find,0.02535160000115866
+5,HashTable,sorted,find,0.00039459999970858917
+5,BST,sorted,find,0.038338099999236874
+5,LinkedList,sorted,delete,0.014124299999821233
+5,HashTable,sorted,delete,0.00011860000086016953
+5,BST,sorted,delete,0.0209164999978384
+average,LinkedList,shuffled,insert,3.4634849199996096
+average,HashTable,shuffled,insert,0.01967166000031284
+average,BST,shuffled,insert,0.01715242000136641
+average,LinkedList,shuffled,find,0.030183400001260453
+average,HashTable,shuffled,find,0.00022984000024734997
+average,BST,shuffled,find,0.0002346200002648402
+average,LinkedList,shuffled,delete,0.012549740000395104
+average,HashTable,shuffled,delete,0.00012208000043756329
+average,BST,shuffled,delete,0.00014211999950930476
+average,LinkedList,sorted,insert,3.273997199999576
+average,HashTable,sorted,insert,0.01923021999973571
+average,BST,sorted,insert,4.014069820000441
+average,LinkedList,sorted,find,0.02528810000003432
+average,HashTable,sorted,find,0.0002579799998784438
+average,BST,sorted,find,0.036995300000126005
+average,LinkedList,sorted,delete,0.013265640000463463
+average,HashTable,sorted,delete,0.00011823999957414344
+average,BST,sorted,delete,0.02074794000000111
diff --git a/SolovevDS/docs/data/data_for_task2/diagrams.py b/SolovevDS/docs/data/data_for_task2/diagrams.py
new file mode 100644
index 0000000..7ff2bde
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task2/diagrams.py
@@ -0,0 +1,76 @@
+import pandas as pd
+import matplotlib.pyplot as plt
+import numpy as np
+
+df = pd.read_csv("results.csv")
+
+maze_order = ["small_10", "medium_50", "large_100", "empty", "no_path"]
+strategy_order = ["BFS", "DFS", "AStar"]
+
+maze_labels = {
+ "small_10": "10×10",
+ "medium_50": "50×50",
+ "large_100": "100×100",
+ "empty": "Пустой",
+ "no_path": "Без выхода"
+}
+
+df["maze"] = pd.Categorical(df["maze"], categories=maze_order, ordered=True)
+df["strategy"] = pd.Categorical(df["strategy"], categories=strategy_order, ordered=True)
+df = df.sort_values(["maze", "strategy"])
+
+
+def plot_grouped_bar(df, value_col, ylabel, title, filename):
+ mazes = maze_order
+ strategies = strategy_order
+
+ x = np.arange(len(mazes))
+ width = 0.25
+
+ plt.figure(figsize=(11, 6))
+
+ for i, strategy in enumerate(strategies):
+ values = []
+
+ for maze in mazes:
+ row = df[(df["maze"] == maze) & (df["strategy"] == strategy)]
+ values.append(row[value_col].values[0])
+
+ plt.bar(x + (i - 1) * width, values, width, label=strategy)
+
+ plt.xlabel("Лабиринт")
+ plt.ylabel(ylabel)
+ plt.title(title)
+
+ plt.xticks(x, [maze_labels[m] for m in mazes], rotation=20)
+ plt.legend(title="Стратегия")
+ plt.grid(axis="y", alpha=0.3)
+
+ plt.tight_layout()
+ plt.savefig(filename, format="svg")
+ plt.show()
+
+
+plot_grouped_bar(
+ df,
+ value_col="time_ms",
+ ylabel="Время, мс",
+ title="Сравнение времени выполнения BFS, DFS и A*",
+ filename="time_comparison.svg"
+)
+
+plot_grouped_bar(
+ df,
+ value_col="cells_visited",
+ ylabel="Количество посещённых клеток",
+ title="Сравнение количества посещённых клеток",
+ filename="visited_cells_comparison.svg"
+)
+
+plot_grouped_bar(
+ df,
+ value_col="way_len",
+ ylabel="Длина пути, клеток",
+ title="Сравнение длины найденного пути",
+ filename="path_length_comparison.svg"
+)
\ No newline at end of file
diff --git a/SolovevDS/docs/data/data_for_task2/maze10.txt b/SolovevDS/docs/data/data_for_task2/maze10.txt
new file mode 100644
index 0000000..8ffe41a
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task2/maze10.txt
@@ -0,0 +1,10 @@
+##########
+#S ###
+###### ###
+# ###
+# #### ###
+# # ###
+# # ######
+# # #
+# ######E#
+##########
diff --git a/SolovevDS/docs/data/data_for_task2/maze100.txt b/SolovevDS/docs/data/data_for_task2/maze100.txt
new file mode 100644
index 0000000..2bd6ce0
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task2/maze100.txt
@@ -0,0 +1,100 @@
+####################################################################################################
+#S # # # # # # # # # ##
+## ############### # ## ## ###### # ### ### ### ########### ### # ## # ####### # ### # # # ##
+# # # # # # # # # # # # # # # # # # # ##
+# ### # ##### # #### ##### ######### # ##### # ##### # ### ##### ### # # ### # ####### ##### # ##
+# # # # # # # # # # # # # # # # # # # # # # # # # ##
+# ##### ### ##### ##### # # ### # ##### # ##### # ####### ######### ##### # # # # ### ### # # ##
+# # # # # # # # # # # # # # # # # # # # # # # # # ##
+# # # ### # # # ### # ##### ### ### # # ##### # # # ### # # ##### ### ##### ### ########### ### ##
+# # # # # # # # # # # # # # # # # # # # # # # # # ##
+# # ### ########### # # ### # ### # # ### # ### # ##### # ####### #### ## # ### ######### ####### ##
+# # # # # # # # # # # # # # # # # # ##
+# ####### ### # # # ### # ### ################# ############# # ### ## ### ## # ### ### # # # # ####
+# # # # # # # # # # # # # # # # # # # # # # ##
+####### ### ### ##### ### # # ########### # ####### ### # ### # ##### # # ##### ### # ### ##### ##
+# # # # # # # # # # # # # # # # # # # # # # # # # ##
+# ### # # ### ####### # # ##### ### # ### ### # ### # # # # ##### # # ########### # ##### # # ######
+# # # # # # # # # # # # # # # # # # # # # # # # # # ##
+# # ##### #### # # # # # # ## ## # # ### ##### ### # ####### ### ####### # # # # ### # # ##### ##
+# # # # # # # # # # # # # # # # # # # # # # # # # ##
+# # ## # # # ### ####### # # # ##### # # ## # # # ######### ### ####### # ### ### # # # ### # # ##
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
+# ##### ### # # ##### # ### ##### # ### ### ### ##### # # # ### ###### ##### # # # # ##### ### # ##
+# # # # # # # # # # # # # # # # # # # # # ##
+# ##### # ######### # ######### ### # ## #### ### ############### # ########### ######### ## # # ##
+# # # # # # # # # # # # # # # # ##
+# ####### # # ##### ### # #### # ### # ### # # # ############# # # # # # # # ####### ### # # ### ##
+# # # # # # # # # # # # # # # # # # # # # # # # # ##
+####### ### ### # # ##### # # ### # # ### ##### ########### # ### ####### ####### # # ### # # # ##
+# # # # # # # # # # # # # # # # # # # # # ##
+# ### ## ##### ###### ## # ##### ### ### ##### ### ############# # ### # ##### ####### ### ##### ##
+# # # # # # # # # # # # # # # # # # # # # ##
+# # ### ## ###### # # # #### ### ### # # # ####### # ##### # ### # ####### ### ### ### ### ######
+# # # # # # # # # # # # # # # # # # # # # # # # # ##
+# ### # # ##### # ###### #### # # ### # # # # ### # # # ######### # ### ### # # ## ## # ### # ##
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
+# # ### ### # ##### # ## # # # ### ##### # # # # # # # ### #### # ### # # ####### # # # ### # ####
+# # # # # # # # # # # # # # # # # # # # # # # # # # # ##
+# ### ### ### # ### # ####### # ### # # ##### # ### # ### # ##### ### ### # ##### # ### # ### ##
+# # # # # # # # # # # # # # # # # # # # # # # # # # ##
+# ##### ### # # ### # # # #### ## # # # ### # # ### # ### ### ### # # # # # ####### ######### # ####
+# # # # # # # # # # # # # # # # # # # # # # # # # # ##
+# # # # # ##### # # ### # ### # # ### # ### # # # ### ### ############# # ### # ######### # ### ##
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
+# ### # # # # # ##### ### # # # # # # ##### # # # ##### # ##### # # ## # ### # # # ### ##### ####
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
+### ##### ### ### # # # ### # ### # # ### # ### # # # # ### ### # # # ### ####### ## ## ### ##
+# # # # # # # # # # # # # # # # # # # # # # # # # # # ##
+# # # # ## ### # ##### # # ### # # ##### # ### ### # # ### ### ##### ### # ##### ## ### ####### ##
+# # # # # # # # # # # # # # # # # # # # # # # # # ##
+# ####### ### ### # ####### ####### # # ### # # ####### ### ### # # # ##### ##### ### ### # # ####
+# # # # # # # # # # # # # # # # # # # # # ##
+# # ####### ####### ### # ### ### # # # ##### ########## # # # ####### # # ######### # # ### # # ##
+# # # # # # # # # # # # # # # # # # # # # # # # # # ##
+# # # # # ##### # ### ##### ### ##### # ##### ### # # # ### # ### # ### # # #### ## ### ### # # # ##
+# # # # # # # # # # # # # # # # # # # # # # # # # # # ##
+# # # ##### ### ####### ##### ### # ### ## ### # # # ####### # # # # # ##### ##### # ### # ##### ##
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
+##### # # ### ### # # # ##### # # # ### # # # # ##### ### # ### # # # # ##### # ### # ### # # # ##
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
+# # ### # # ##### # ############ # ##### # #### ## # ##### # # ######### # ####### ## # # # # # ##
+# # # # # # # # # # # # # # # # # # # ##
+# ##### # ##### # ### ### # # ##### # ############### # # ### ######### # ### # ##### ### # ##### ##
+# # # # # # # # # # # # # # # # # # # # # # # # # ##
+# # # # ### # # # # ## ### ##### # ### ## ######## ### ########## # # ### # # ####### ### ##### ##
+# # # # # # # # # # # # # # # # # # # ##
+# ### # # # ### ##### ##### # # # ############### ######### ### # # ################ # # ### ######
+# # # # # # # # # # # # # # # # # # # ##
+# # # ### ### ######### # # # ####### ### #### # ### ##### ######### # # # ##### # ##### # ########
+# # # # # # # # # # # # # # # # # # # # # # # # # # ##
+### # # # ##### # # # # # # # ### # # ### # ### # ## # ## # ####### ######### ##### # # # ### ##
+# # # # # # # # # # # # # # # # # # # # # # # ##
+# ##### ##### # # ### ### ### # ##### # # # ### # ############ ## ######### ### # ### ### # # # # ##
+# # # # # # # # # # # # # # # # # # # # # # # # ##
+# # ##### # # ##### # ### # #### ### # ######### ### # # ##### # ### ### # ### ### #### ## # ##
+# # # # # # # # # # # # # # # # # # # # # # # # ##
+# ##### ### #### # # ########### ### # # # # # # # ### # # # # # # ### # ### ##### ### # ### # # ##
+# # # # # # # # # # # # # # # # # # # # # # # # # ##
+# # # # # ### # ### # # ####### #### ######### ####### ### ####### # # ####### ### ### # ##### ##
+# # # # # # # # # # # # # # # # # # # # # # # ##
+# # ##### ##### # ####### ### ################# # # ### # # ### # # ### # # ### # ######### ##### ##
+# # # # # # # # # # # # # # # # # # # # # # # # ##
+### # ### # # ##### # # # # ### ### # ##### ####### ### ### # # ### ####### ####### ### ##########
+# # # # # # # # # # # # # # # # # # # # # ##
+# ######### # ##### ### ############# # ####### ##### ### ### # # ### # ### ##### # # ### ### # ##
+# # # # # # # # # # # # # # # # # # # # # ##
+# # # # # # ##### ##### # ######### # ### ### ### # ####### # # ### # ####### ##### ### # ### ##
+# # # # # # # # # # # # # # # # # # # # ##
+# ### # # # ##### # ###### #### # ##### # ### # # ### ######### ### ####### # ### ### ### ####### ##
+# # # # # # # # # # # # # # # # # # # # # # # ##
+# # ########### ### # ##### # # # # # ### # ### ### ### ##### ### ##### # ####### # ###### # # ####
+# # # # # # # # # # # # # # # # # # # # # # # ##
+# # # ###### # ### # # ########### ## ### ##### # # # # # # # # # ########### ### ######### ### ##
+# # # # # # # # # # # # # # # # # # # # # # # # # # # ##
+# ### ### # ### # ### # # ### # # ### # ### # ### # ##### # # # # ### # # ###### # ### # # ### # ##
+# # # # # # # # # # # # # # # # # # # # # # # # # # # ##
+### # # ##### ##### ### # # ####### ##### # # # ########### ######### ### # # ### ##### # # # # ##
+# # # # # # # # E##
+####################################################################################################
+####################################################################################################
diff --git a/SolovevDS/docs/data/data_for_task2/maze50.txt b/SolovevDS/docs/data/data_for_task2/maze50.txt
new file mode 100644
index 0000000..b574296
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task2/maze50.txt
@@ -0,0 +1,50 @@
+##################################################
+#S # # # # # ##
+##### ##### ### ######### ### ### # ### # ### # ##
+# # # # # # # # # # # # ##
+### ######### ############# ### # # # ##### ### ##
+# # # # # # # # # # ##
+# ########### # ### # # ##### # ##### # ### # ##
+# # # # # # # # # # # ##
+### # # ### ### # ### # ######### # ####### ### ##
+# # # # # # # # # # ##
+# ##### # ### ##### # ##### ##### ########### ####
+# # # # # # # # # # ##
+##### # ### ##### # ########### ##### ##### ### ##
+# # # # # # # # # # ##
+# ####### # ####### # ####### ### # ### # ### # ##
+# # # # # # # # # # # # ##
+# # # # ################### # # ### # # # ### # ##
+# # # # # # # # # # # # # ##
+### # ### ### # # ########### ### # # # ### ### ##
+# # # # # # # # # # # # # # ##
+# ##### ### ######### ##### ### # ### # # ### # ##
+# # # # # # # # # # # # # ##
+# # # ####### ### ### # ### # # ### # # # # # ####
+# # # # # # # # # # # # # # ##
+# # ########### ####### # ### # # ######### ### ##
+# # # # # # # # ##
+# ### ####### # ##### ##### # ####### ### ### ####
+# # # # # # # # # # # # ##
+# ######### ####### # # # # ### # ####### # ### ##
+# # # # # # # # # # # # ##
+### # ### ##### ####### # # # # ### # # ####### ##
+# # # # # # # # # # # # # # ##
+# # # # ### # ####### # # # ##### # # ### ### # ##
+# # # # # # # # # # # # # # # # ##
+# # # ######### # # # ### ### ### ### # ### # # ##
+# # # # # # # # # # # # # ##
+# ### # ####### # ######### # ####### ### # ### ##
+# # # # # # # # # # # # # ##
+# ##### # # # ##### # # ####### ### # # ### # ####
+# # # # # # # # # # # # # # ##
+##### ### # # # ##### ########### # # # # # ### ##
+# # # # # # # # # # # ##
+# ############# # ### ##### ##### # ### # ##### ##
+# # # # # # # # # # # ##
+# # ####### ### # # ### # ### ### ### # ##### # ##
+# # # # # # # # # # # # # ##
+# ##### ##### ### # # ##### ### ### ##### ##### ##
+# # # # # # E##
+##################################################
+##################################################
diff --git a/SolovevDS/docs/data/data_for_task2/maze_empty.txt b/SolovevDS/docs/data/data_for_task2/maze_empty.txt
new file mode 100644
index 0000000..a92cf1d
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task2/maze_empty.txt
@@ -0,0 +1,50 @@
+S
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ E
diff --git a/SolovevDS/docs/data/data_for_task2/maze_no_path.txt b/SolovevDS/docs/data/data_for_task2/maze_no_path.txt
new file mode 100644
index 0000000..03906b4
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task2/maze_no_path.txt
@@ -0,0 +1,10 @@
+##########
+#S #
+# ###### #
+# # # #
+# # ## # #
+# # ## # #
+# # # #
+# ########
+# #E#
+##########
diff --git a/SolovevDS/docs/data/data_for_task2/path_length_comparison.svg b/SolovevDS/docs/data/data_for_task2/path_length_comparison.svg
new file mode 100644
index 0000000..f3af08a
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task2/path_length_comparison.svg
@@ -0,0 +1,1536 @@
+
+
+
diff --git a/SolovevDS/docs/data/data_for_task2/results.csv b/SolovevDS/docs/data/data_for_task2/results.csv
new file mode 100644
index 0000000..8bc14f3
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task2/results.csv
@@ -0,0 +1,16 @@
+maze,strategy,time_ms,cells_visited,way_len
+small_10,BFS,0.00724,31.00000,21.00000
+small_10,DFS,0.00360,31.00000,21.00000
+small_10,AStar,0.00519,24.00000,21.00000
+medium_50,BFS,0.04465,505.00000,145.00000
+medium_50,DFS,0.03666,385.00000,361.00000
+medium_50,AStar,0.05370,319.00000,145.00000
+large_100,BFS,0.44010,4534.00000,245.00000
+large_100,DFS,0.09760,816.00000,703.00000
+large_100,AStar,0.37331,1298.00000,245.00000
+empty,BFS,0.15303,2500.00000,99.00000
+empty,DFS,0.09335,1275.00000,1275.00000
+empty,AStar,0.17047,341.00000,99.00000
+no_path,BFS,0.00259,25.00000,0.00000
+no_path,DFS,0.00244,25.00000,0.00000
+no_path,AStar,0.00494,25.00000,0.00000
diff --git a/SolovevDS/docs/data/data_for_task2/task2.cpp b/SolovevDS/docs/data/data_for_task2/task2.cpp
new file mode 100644
index 0000000..07f957c
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task2/task2.cpp
@@ -0,0 +1,934 @@
+#include
+#include
+#include
+#include /*для ошибок*/
+#include
+#include /*мерит время*/
+#include /*волшебная отрисовка*/
+#include
+#include
+#include
+
+class cell{
+ private:
+ int x, y;
+ bool isWall;
+ bool isExit;
+ bool isStart;
+
+ public:
+ cell() {x=0; y=0; isWall=false; isExit=false; isStart = false;}
+ cell(int x, int y, bool isWall, bool isExit, bool isStart)
+ {
+ this->x = x;
+ this->y = y;
+ this->isWall = isWall;
+ this->isExit = isExit;
+ this->isStart = isStart;
+ }
+
+ bool isPassable() {return !isWall;}
+
+ void setStart(bool value) {isStart = value;}
+ void setExit(bool value) {isExit = value;}
+ void setX(int x) {this->x = x;}
+ void setY(int y) {this->y = y;}
+ void setIsWall(bool isWall) {this->isWall = isWall;}
+
+
+ int getX() {return x;}
+ int getY() {return y;}
+ bool getIsWall() {return isWall;}
+ bool getIsExit() {return isExit;}
+ bool getIsStart() {return isStart;}
+
+};
+
+class maze{
+ private:
+ int width;
+ int height;
+ cell** matrix;
+
+ cell* start;
+ cell* exit;
+
+ public:
+ maze(int width, int height)
+ {
+ this->width = width;
+ this->height = height;
+ this->start = nullptr;
+ this->exit = nullptr;
+
+ matrix = new cell*[width];
+
+ for (int x = 0; x < width; ++x) {
+ matrix[x] = new cell[height];
+ for (int y = 0; y < height; ++y)
+ matrix[x][y] = cell(x, y, false, false, false);
+ }
+ }
+ maze(int width, int height, int startX, int startY, int exitX, int exitY)
+ {
+ this->width = width;
+ this->height = height;
+ this->start = nullptr;
+ this->exit = nullptr;
+
+ matrix = new cell*[width];
+ for (int x = 0; x < width; ++x) {
+ matrix[x] = new cell[height];
+ for (int y = 0; y < height; ++y) {
+ matrix[x][y] = cell(x, y, false, false, false);
+ }
+ }
+
+
+ matrix[startX][startY].setStart(true);
+ matrix[exitX][exitY].setExit(true);
+
+ start = &matrix[startX][startY];
+ exit = &matrix[exitX][exitY];
+ }
+
+ ~maze()
+ {
+ for (int i = 0; i < width; ++i)
+ delete[] matrix[i];
+ delete[] matrix;
+ }
+
+ cell* getCell(int x, int y) {
+ if (x < 0 || x >= width || y < 0 || y >= height)
+ return nullptr;
+
+ return &matrix[x][y];
+ }
+ void setCell(int x, int y, cell newCell) {
+ if (x < 0 || x >= width || y < 0 || y >= height)
+ return;
+
+ matrix[x][y] = newCell;
+
+ if (matrix[x][y].getIsStart())
+ start = &matrix[x][y];
+
+ if (matrix[x][y].getIsExit())
+ exit = &matrix[x][y];
+ }
+
+ cell** getNeighbors(cell* current) { /*ДЕЛАТЬ delete[] neighbors; !!!!!!!!!!!!!!!*/
+ cell** neighbors = new cell*[5];
+ int count = 0;
+
+ int x = current->getX();
+ int y = current->getY();
+
+ cell* up = getCell(x, y - 1);
+ cell* down = getCell(x, y + 1);
+ cell* left = getCell(x - 1, y);
+ cell* right = getCell(x + 1, y);
+
+ if (up != nullptr && up->isPassable()) {
+ neighbors[count] = up;
+ count++;}
+
+ if (down != nullptr && down->isPassable()) {
+ neighbors[count] = down;
+ count++;}
+
+ if (left != nullptr && left->isPassable()) {
+ neighbors[count] = left;
+ count++;}
+
+ if (right != nullptr && right->isPassable()) {
+ neighbors[count] = right;
+ count++;}
+
+ neighbors[count] = nullptr;
+
+ return neighbors;
+ }
+
+ cell* getStart() {return start;}
+ cell* getExit() {return exit;}
+ int getWidth() {return width;}
+ int getHeight() {return height;}
+};
+
+class MazeBuilder {
+ public:
+ virtual maze* buildFromFile(const std::string& filename) = 0;
+ virtual ~MazeBuilder() {}
+};
+
+class TextFileMazeBuilder : public MazeBuilder {
+ public:
+ maze* buildFromFile(const std::string& filename) override
+ {
+
+ std::ifstream file(filename);
+ if (!file.is_open())
+ throw std::runtime_error("Ошибка: Не удалось открыть файл!");
+
+ std::string line;
+ int width = 0;
+ int height = 0;
+
+ while (std::getline(file, line)) {
+ if (height == 0) {
+ width = line.length();
+ }
+ else {
+ if (line.length() != width)
+ throw std::runtime_error("Ошибка: строки лабиринта разной длины!");
+ }
+ height++;
+ }
+
+ if (width == 0 || height == 0) {
+ throw std::runtime_error("Ошибка: файл пустой!");
+ }
+
+ file.clear();
+ file.seekg(0);
+
+ maze* labirint = new maze(width, height);
+ bool hasStart = false;
+ bool hasExit = false;
+ int y = 0;
+
+
+ while (std::getline(file, line)) {
+
+ for (int x = 0; x < width; x++) {
+ char ch = line[x];
+
+ bool isWall = false;
+ bool isStart = false;
+ bool isExit = false;
+
+ switch(ch){
+ case '#':
+ isWall = true;
+ break;
+ case ' ':
+ isWall = false;
+ break;
+ case 'S':
+ isStart = true;
+
+ if (hasStart)
+ throw std::runtime_error("Ошибка: в лабиринте больше одного старта!");
+
+ hasStart = true;
+ break;
+ case 'E':
+ isExit = true;
+
+ if (hasExit)
+ throw std::runtime_error("Ошибка: в лабиринте больше одного выхода!");
+ hasExit = true;
+ break;
+ default:
+ throw std::runtime_error("Ошибка: неизвестный символ в файле!");
+ break;
+ }
+
+ cell current(x, y, isWall, isExit, isStart);
+ labirint->setCell(x, y, current);
+ }
+
+ y++;
+ }
+ file.close();
+ if (!hasStart)
+ throw std::runtime_error("Ошибка: в лабиринте нет старта!");
+ if (!hasExit)
+ throw std::runtime_error("Ошибка: в лабиринте нет выхода!");
+ return labirint;
+ }
+};
+
+
+class PathFindingStrategy {
+ public:
+ virtual cell** findPath(maze* m, cell* start, cell* exit) = 0;
+ virtual int getVisitedCells() = 0; /*для посещенных клеток*/
+ virtual ~PathFindingStrategy() {}
+};
+
+class PathBuilder {
+ public:
+ static cell** buildPath(cell* start, cell* exit, cell*** parent) {
+ int length = 0;
+ cell* current = exit;
+
+ while (current != nullptr) {
+ length++;
+ if (current == start)
+ break;
+ current = parent[current->getX()][current->getY()];
+ }
+
+ cell** path = new cell*[length + 1];
+ current = exit;
+
+ for (int i = length - 1; i >= 0; i--) {
+ path[i] = current;
+ if (current == start)
+ break;
+ current = parent[current->getX()][current->getY()];
+ }
+ path[length] = nullptr;
+ return path;
+ }
+};
+
+class BFSStrategy : public PathFindingStrategy {
+ private:
+ int visitedCells;
+ public:
+
+ BFSStrategy() {visitedCells = 0;}
+
+ int getVisitedCells() override {return visitedCells;}
+
+ cell** findPath(maze* m, cell* start, cell* exit) override {
+ visitedCells = 0;
+ int width = m->getWidth();
+ int height = m->getHeight();
+ bool** visited = new bool*[width];
+ cell*** parent = new cell**[width];
+
+ for (int x = 0; x < width; x++) {
+ visited[x] = new bool[height];
+ parent[x] = new cell*[height];
+
+ for (int y = 0; y < height; y++) {
+ visited[x][y] = false;
+ parent[x][y] = nullptr;
+ }
+ }
+
+ cell** deque = new cell*[width * height];
+ int head = 0;
+ int tail = 0;
+
+ deque[tail] = start;
+ tail++;
+ visited[start->getX()][start->getY()] = true;
+ bool found = false;
+
+ while (head < tail) {
+ cell* current = deque[head];
+ head++;
+ visitedCells++;
+
+ if (current == exit) { //сравниваются указатели
+ found = true;
+ break;
+ }
+
+ cell** neighbors = m->getNeighbors(current);
+
+ for (int i = 0; neighbors[i] != nullptr; i++) {
+ cell* next = neighbors[i];
+
+ int nx = next->getX();
+ int ny = next->getY();
+
+ if (!visited[nx][ny]) {
+ visited[nx][ny] = true;
+ parent[nx][ny] = current;
+
+ deque[tail] = next;
+ tail++;
+ }
+ }
+ delete[] neighbors;
+ }
+
+ cell** path;
+
+ if (found) {
+ path = PathBuilder::buildPath(start, exit, parent);
+ }
+ else {
+ path = new cell*[1];
+ path[0] = nullptr;
+ }
+
+ delete[] deque;
+
+ for (int x = 0; x < width; x++) {
+ delete[] visited[x];
+ delete[] parent[x];
+ }
+ delete[] visited;
+ delete[] parent;
+ return path;
+ }
+};
+
+class DFSStrategy : public PathFindingStrategy {
+ private:
+ int visitedCells;
+ public:
+ DFSStrategy() {visitedCells = 0;}
+
+ int getVisitedCells() override {return visitedCells;}
+
+ cell** findPath(maze* m, cell* start, cell* exit) override {
+ visitedCells = 0;
+ int width = m->getWidth();
+ int height = m->getHeight();
+ bool** visited = new bool*[width];
+ cell*** parent = new cell**[width];
+
+ for (int x = 0; x < width; x++) {
+ visited[x] = new bool[height];
+ parent[x] = new cell*[height];
+
+ for (int y = 0; y < height; y++) {
+ visited[x][y] = false;
+ parent[x][y] = nullptr;
+ }
+ }
+
+ cell** stack = new cell*[width * height];
+ int top = 0;
+ stack[top] = start;
+ top++;
+ visited[start->getX()][start->getY()] = true;
+ bool found = false;
+
+ while (top > 0) {
+ top--;
+ cell* current = stack[top];
+ visitedCells++;
+
+ if (current == exit) { //сравниваются указатели
+ found = true;
+ break;
+ }
+
+ cell** neighbors = m->getNeighbors(current);
+
+ for (int i = 0; neighbors[i] != nullptr; i++) {
+ cell* next = neighbors[i];
+
+ int nx = next->getX();
+ int ny = next->getY();
+
+ if (!visited[nx][ny]) {
+ visited[nx][ny] = true;
+ parent[nx][ny] = current;
+
+ stack[top] = next;
+ top++;
+ }
+ }
+ delete[] neighbors;
+ }
+
+ cell** path;
+
+ if (found) {
+ path = PathBuilder::buildPath(start, exit, parent);
+ }
+ else {
+ path = new cell*[1];
+ path[0] = nullptr;
+ }
+
+ delete[] stack;
+
+ for (int x = 0; x < width; x++) {
+ delete[] visited[x];
+ delete[] parent[x];
+ }
+ delete[] visited;
+ delete[] parent;
+ return path;
+ }
+};
+
+class AStarStrategy : public PathFindingStrategy {
+ private:
+ int heuristic(cell* current, cell* exit) {return std::abs(current->getX() - exit->getX()) + std::abs(current->getY() - exit->getY());}
+ int visitedCells;
+
+ public:
+ AStarStrategy() {visitedCells = 0;}
+
+ int getVisitedCells() override {return visitedCells;}
+
+ cell** findPath(maze* m, cell* start, cell* exit) override {
+ visitedCells = 0;
+ int width = m->getWidth();
+ int height = m->getHeight();
+
+ bool** closed = new bool*[width]; /*клетка [x][y] посещена (да/нет)*/
+ bool** inOpen = new bool*[width]; /*клетка [x][y] имеет потенциал к посещению (да/нет)*/
+ int** gScore = new int*[width]; /* до клетка [x][y] от старта gSchore[x][y] шагов*/
+ int** fScore = new int*[width]; /*f = h + g, где h - эвристика клетки[x][y]*/
+
+ cell*** parent = new cell**[width];
+
+
+ for (int x = 0; x < width; x++) {
+ closed[x] = new bool[height];
+ inOpen[x] = new bool[height];
+ gScore[x] = new int[height];
+ fScore[x] = new int[height];
+
+ parent[x] = new cell*[height];
+
+ for (int y = 0; y < height; y++) {
+ closed[x][y] = false;
+ inOpen[x][y] = false;
+
+ gScore[x][y] = width * height + 100000; /*тупо большое число чтоб было больше чем клеток в лаберинте*/
+ fScore[x][y] = width * height + 100000;
+
+ parent[x][y] = nullptr;
+ }
+ }
+
+ cell** open = new cell*[width * height]; /*клетки с потенциалом на посещение*/
+ int openCount = 0; /*это количество потенц клеток, а также индекс следующего незанятого места*/
+
+ int sx = start->getX();
+ int sy = start->getY();
+
+ gScore[sx][sy] = 0;
+ fScore[sx][sy] = heuristic(start, exit);
+
+ open[openCount] = start;
+ openCount++;
+
+ inOpen[sx][sy] = true;
+ bool found = false;
+
+ while (openCount > 0) {
+ int bestIndex = 0;
+
+ for (int i = 1; i < openCount; i++) {
+ int ix = open[i]->getX();
+ int iy = open[i]->getY();
+
+ int bx = open[bestIndex]->getX();
+ int by = open[bestIndex]->getY();
+
+ if (fScore[ix][iy] < fScore[bx][by]) {
+ bestIndex = i; /*(fSchore наименьший в [bestIndex])*/
+ }
+ }
+
+ cell* current = open[bestIndex];
+
+ if (current == exit) {
+ found = true;
+ visitedCells++; /*чтоб выход засчитывался*/
+ break;
+ }
+
+ int cx = current->getX();
+ int cy = current->getY();
+
+ open[bestIndex] = open[openCount - 1];
+ openCount--;
+
+ inOpen[cx][cy] = false;
+ closed[cx][cy] = true;
+ visitedCells++;
+
+ cell** neighbors = m->getNeighbors(current);
+
+ for (int i = 0; neighbors[i] != nullptr; i++) {
+ cell* next = neighbors[i];
+
+ int nx = next->getX();
+ int ny = next->getY();
+
+ if (closed[nx][ny]) {
+ continue;
+ }
+
+ int tentativeG = gScore[cx][cy] + 1;
+
+ if (tentativeG < gScore[nx][ny]) {
+ parent[nx][ny] = current;
+
+ gScore[nx][ny] = tentativeG;
+ fScore[nx][ny] = gScore[nx][ny] + heuristic(next, exit);
+
+ if (!inOpen[nx][ny]) {
+ open[openCount] = next;
+ openCount++;
+
+ inOpen[nx][ny] = true;
+ }
+ }
+ }
+ delete[] neighbors;
+ }
+
+ cell** path;
+ if (found) {
+ path = PathBuilder::buildPath(start, exit, parent);
+ }
+ else {
+ path = new cell*[1];
+ path[0] = nullptr;
+ }
+
+ delete[] open;
+
+ for (int x = 0; x < width; x++) {
+ delete[] closed[x];
+ delete[] inOpen[x];
+ delete[] gScore[x];
+ delete[] fScore[x];
+ delete[] parent[x];
+ }
+ delete[] closed;
+ delete[] inOpen;
+ delete[] gScore;
+ delete[] fScore;
+ delete[] parent;
+
+ return path;
+ }
+};
+
+class SearchStats {
+public:
+ double timeMs;
+ int visitedCells;
+ int pathLength;
+
+ SearchStats(double timeMs, int visitedCells, int pathLength) {
+ this->timeMs = timeMs;
+ this->visitedCells = visitedCells;
+ this->pathLength = pathLength;
+ }
+};
+
+class MazeSolver{
+ private:
+ maze* labirint;
+ PathFindingStrategy* strategy;
+ public:
+ MazeSolver(maze* labirint) {this->labirint = labirint; this->strategy = nullptr;}
+
+ void setStrategy(PathFindingStrategy* strategy){
+ this->strategy = strategy;
+ }
+
+ SearchStats solve(){
+ auto start = std::chrono::high_resolution_clock::now();
+ cell** path = strategy->findPath(labirint,labirint->getStart(),labirint->getExit());
+ auto end = std::chrono::high_resolution_clock::now();
+ std::chrono::duration duration = end - start;
+
+ int pathLength = 0;
+
+ if (path[0] != nullptr)
+ while (path[pathLength] != nullptr) {pathLength++;}
+
+ int visitedCells = 0;
+ visitedCells = strategy->getVisitedCells();
+ delete[] path;
+
+ SearchStats stats(duration.count(), visitedCells, pathLength);
+ return stats;
+ }
+};
+
+class Player{
+ private:
+ cell* current;
+ public:
+ Player(cell* current) {this->current = current;}
+
+ cell* getCurrent() {return current;}
+ void moveTo(cell* cell) {this->current = cell;}
+};
+
+class Direction{
+ private:
+ int dx;
+ int dy;
+
+ public:
+ Direction(int dx, int dy) {
+ this->dx = dx;
+ this->dy = dy;
+ }
+
+ int getDx() {return dx;}
+ int getDy() {return dy;}
+};
+
+class Command {
+ public:
+ virtual void execute() = 0;
+ virtual void undo() = 0;
+ virtual ~Command() {}
+};
+
+class MoveCommand : public Command{
+ private:
+ Player* player;
+ Direction dir;
+ cell* previousCell;
+ maze* labirint;
+ public:
+ MoveCommand(Player* player, maze* labirint, Direction dir) : dir(dir) {
+ this->player = player;
+ this->labirint = labirint;
+ this->previousCell = nullptr;
+ }
+
+ void execute() override {
+ cell* currentCell = player->getCurrent();
+
+ int newX = currentCell->getX() + dir.getDx();
+ int newY = currentCell->getY() + dir.getDy();
+
+ cell* nextCell = labirint->getCell(newX, newY);
+
+ if (nextCell != nullptr && nextCell->isPassable()) {
+ previousCell = currentCell;
+ player->moveTo(nextCell);
+ }
+ else {
+ std::cout << "Нельзя сделать ход!" << std::endl;
+ }
+ }
+
+ void undo() override {
+ if (previousCell != nullptr) {
+ player->moveTo(previousCell);
+ previousCell = nullptr;
+ }
+ }
+
+};
+
+class ConsolController{
+ private:
+ maze* labirint;
+ Player* player;
+ Command* lastCommand; /*указатель на последнюю команду(на объект класса command)*/
+ bool running;
+ public:
+ ConsolController(maze* labirint, Player* player) {
+ this->labirint = labirint;
+ this->player = player;
+ this->lastCommand = nullptr;
+ this->running = false;
+ }
+
+ ~ConsolController() {
+ if (lastCommand != nullptr) {
+ delete lastCommand;
+ }
+ }
+
+ void run() {
+ running = true;
+
+ while (running) {
+ clearConsole();
+ drawMaze();
+
+ std::cout << "W/A/S/D - ход, Z - отмена, Q - выход" << std::endl;
+ char ch;
+ std::cin >> ch;
+
+ handleInput(ch);
+ }
+ }
+
+ void handleInput(char ch) {
+ switch(ch){
+ case 'q':
+ case 'Q':
+ running = false;
+ break;
+ case 'z':
+ case 'Z':
+ undoLastMove();
+ break;
+ default:
+ handleMove(ch);
+ break;
+ }
+ }
+
+ void handleMove(char ch) {
+ Direction dir(0, 0);
+
+ switch (ch) {
+ case 'w':
+ case 'W':
+ dir = Direction(0, -1);
+ break;
+ case 's':
+ case 'S':
+ dir = Direction(0, 1);
+ break;
+ case 'a':
+ case 'A':
+ dir = Direction(-1, 0);
+ break;
+ case 'd':
+ case 'D':
+ dir = Direction(1, 0);
+ break;
+ default:
+ return;
+ }
+
+ if (lastCommand != nullptr) {
+ delete lastCommand;
+ lastCommand = nullptr;
+ }
+
+ lastCommand = new MoveCommand(player, labirint, dir);
+ lastCommand->execute();
+ }
+
+ void undoLastMove() {
+ if (lastCommand != nullptr) {
+ lastCommand->undo();
+ delete lastCommand;
+ lastCommand = nullptr; /*можно отменить только одну команду назад, указатель делаем 0, чтобы не долбится в отмену уже отмененной команды*/
+ }
+ }
+
+ void clearConsole() {
+ #ifdef _WIN32
+ system("cls");
+ #else
+ system("clear");
+ #endif
+ }
+
+ void drawMaze() {
+ for (int y = 0; y < labirint->getHeight(); y++) {
+ for (int x = 0; x < labirint->getWidth(); x++) {
+ cell* currentCell = labirint->getCell(x, y);
+
+ if (currentCell == player->getCurrent())
+ std::cout << "P";
+ else if (currentCell->getIsWall())
+ std::cout << "#";
+ else if (currentCell->getIsStart())
+ std::cout << "S";
+ else if (currentCell->getIsExit())
+ std::cout << "E";
+ else
+ std::cout << " ";
+ }
+ std::cout << std::endl;
+ }
+ }
+};
+
+class Benchmark {
+ private:
+ int RUNS = 10;
+ public:
+ Benchmark(int runs) {this->RUNS = runs;}
+ void benchmark(){
+ std::string mazeFiles[] = {
+ "SolovevDS/docs/data/data_for_task2/maze10.txt",
+ "SolovevDS/docs/data/data_for_task2/maze50.txt",
+ "SolovevDS/docs/data/data_for_task2/maze100.txt",
+ "SolovevDS/docs/data/data_for_task2/maze_empty.txt",
+ "SolovevDS/docs/data/data_for_task2/maze_no_path.txt"
+ };
+
+ std::string mazeNames[] = {
+ "small_10",
+ "medium_50",
+ "large_100",
+ "empty",
+ "no_path"
+ };
+
+ std::ofstream csv("SolovevDS/docs/data/data_for_task2/results.csv");
+
+ if (!csv.is_open())
+ throw std::runtime_error("Ошибка: не удалось создать results.csv!");
+
+ csv << "maze,strategy,time_ms,cells_visited,way_len\n";
+
+ TextFileMazeBuilder builder;
+
+ for (int i = 0; i < 5; i++) {
+ maze* labirint = builder.buildFromFile(mazeFiles[i]);
+
+ MazeSolver solver(labirint);
+
+ BFSStrategy bfs;
+ DFSStrategy dfs;
+ AStarStrategy astar;
+
+ PathFindingStrategy* strategies[] = {&bfs, &dfs, &astar};
+ std::string strategyNames[] = {"BFS", "DFS", "AStar"};
+
+ for (int s = 0; s < 3; s++) {
+ double sumTime = 0;
+ double sumVisited = 0;
+ double sumPathLength = 0;
+
+ for (int run = 0; run < RUNS; run++) {
+ solver.setStrategy(strategies[s]);
+
+ SearchStats stats = solver.solve();
+
+ sumTime += stats.timeMs;
+ sumVisited += stats.visitedCells;
+ sumPathLength += stats.pathLength;
+ }
+
+ double avgTime = sumTime / RUNS;
+ double avgVisited = sumVisited / RUNS;
+ double avgPathLength = sumPathLength / RUNS;
+
+ csv << mazeNames[i] << ","
+ << strategyNames[s] << ","
+ << std::fixed << std::setprecision(5) << avgTime << ","
+ << avgVisited << ","
+ << avgPathLength << "\n";
+ }
+ delete labirint;
+ }
+
+ csv.close();
+ }
+};
+
+
+int main(){
+ SetConsoleCP(CP_UTF8);
+ SetConsoleOutputCP(CP_UTF8);
+ setlocale(LC_ALL, ".UTF-8");
+ Benchmark ben(10);
+ ben.benchmark();
+
+ TextFileMazeBuilder builder;
+ maze* labirint = builder.buildFromFile("SolovevDS/docs/data/data_for_task2/maze10.txt");
+ Player player(labirint->getStart());
+ ConsolController controller(labirint, &player);
+ controller.run();
+ delete labirint;
+
+ return 0;
+}
diff --git a/SolovevDS/docs/data/data_for_task2/time_comparison.svg b/SolovevDS/docs/data/data_for_task2/time_comparison.svg
new file mode 100644
index 0000000..d50a3e3
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task2/time_comparison.svg
@@ -0,0 +1,1582 @@
+
+
+
diff --git a/SolovevDS/docs/data/data_for_task2/visited_cells_comparison.svg b/SolovevDS/docs/data/data_for_task2/visited_cells_comparison.svg
new file mode 100644
index 0000000..05def5c
--- /dev/null
+++ b/SolovevDS/docs/data/data_for_task2/visited_cells_comparison.svg
@@ -0,0 +1,1530 @@
+
+
+
diff --git a/SolovevDS/docs/laba_1_report.pdf b/SolovevDS/docs/laba_1_report.pdf
new file mode 100644
index 0000000..f0f277d
Binary files /dev/null and b/SolovevDS/docs/laba_1_report.pdf differ
diff --git a/SolovevDS/docs/laba_2_report.pdf b/SolovevDS/docs/laba_2_report.pdf
new file mode 100644
index 0000000..005e523
Binary files /dev/null and b/SolovevDS/docs/laba_2_report.pdf differ