[2] task 1 and task 2 #160
3
VaravinVV/.vscode/settings.json
vendored
Normal file
3
VaravinVV/.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"python-envs.defaultEnvManager": "ms-python.python:system"
|
||||||
|
}
|
||||||
BIN
VaravinVV/docs/data/performance_plots.png
Normal file
BIN
VaravinVV/docs/data/performance_plots.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
31
VaravinVV/docs/data/res.csv
Normal file
31
VaravinVV/docs/data/res.csv
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
Structure,Mode,Repeat,Insert (sec),Search (sec),Delete (sec)
|
||||||
|
LinkedList,random,1,0.020151,0.002076,0.000330
|
||||||
|
LinkedList,random,2,0.019539,0.001570,0.000161
|
||||||
|
LinkedList,random,3,0.020193,0.001963,0.000151
|
||||||
|
LinkedList,random,4,0.020033,0.001751,0.000161
|
||||||
|
LinkedList,random,5,0.019602,0.002023,0.000175
|
||||||
|
LinkedList,sorted,1,0.020010,0.002227,0.000175
|
||||||
|
LinkedList,sorted,2,0.019032,0.001596,0.000122
|
||||||
|
LinkedList,sorted,3,0.019683,0.001889,0.000195
|
||||||
|
LinkedList,sorted,4,0.019917,0.001636,0.000215
|
||||||
|
LinkedList,sorted,5,0.019039,0.001624,0.000141
|
||||||
|
HashTable,random,1,0.003015,0.000273,0.000024
|
||||||
|
HashTable,random,2,0.002447,0.000214,0.000020
|
||||||
|
HashTable,random,3,0.002656,0.000226,0.000026
|
||||||
|
HashTable,random,4,0.002447,0.000205,0.000022
|
||||||
|
HashTable,random,5,0.002181,0.000381,0.000021
|
||||||
|
HashTable,sorted,1,0.002358,0.000309,0.000025
|
||||||
|
HashTable,sorted,2,0.002539,0.000205,0.000019
|
||||||
|
HashTable,sorted,3,0.002286,0.000234,0.000023
|
||||||
|
HashTable,sorted,4,0.002566,0.000223,0.000019
|
||||||
|
HashTable,sorted,5,0.002144,0.000230,0.000022
|
||||||
|
BST,random,1,0.001556,0.000107,0.000021
|
||||||
|
BST,random,2,0.001631,0.000116,0.000019
|
||||||
|
BST,random,3,0.001351,0.000106,0.000016
|
||||||
|
BST,random,4,0.001378,0.000148,0.000017
|
||||||
|
BST,random,5,0.001617,0.000121,0.000017
|
||||||
|
BST,sorted,1,0.066839,0.006176,0.000532
|
||||||
|
BST,sorted,2,0.064324,0.005361,0.000521
|
||||||
|
BST,sorted,3,0.065574,0.005315,0.000562
|
||||||
|
BST,sorted,4,0.063277,0.004858,0.000487
|
||||||
|
BST,sorted,5,0.058764,0.005325,0.000693
|
||||||
|
51
VaravinVV/docs/data/tables.py
Normal file
51
VaravinVV/docs/data/tables.py
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
import pandas as pd
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
df = pd.read_csv('res.csv')
|
||||||
|
|
||||||
|
grouped = df.groupby(['Structure', 'Mode']).agg({
|
||||||
|
'Insert (sec)': ['mean', 'std'],
|
||||||
|
'Search (sec)': ['mean', 'std'],
|
||||||
|
'Delete (sec)': ['mean', 'std']
|
||||||
|
}).reset_index()
|
||||||
|
|
||||||
|
grouped.columns = ['Structure', 'Mode', 'Insert_mean', 'Insert_std',
|
||||||
|
'Search_mean', 'Search_std', 'Delete_mean', 'Delete_std']
|
||||||
|
|
||||||
|
structures = grouped['Structure'].unique()
|
||||||
|
modes = grouped['Mode'].unique()
|
||||||
|
|
||||||
|
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
|
||||||
|
operations = ['Insert', 'Search', 'Delete']
|
||||||
|
colors = {'random': 'skyblue', 'sorted': 'lightcoral'}
|
||||||
|
|
||||||
|
for i, op in enumerate(operations):
|
||||||
|
ax = axes[i]
|
||||||
|
mean_col = f'{op}_mean'
|
||||||
|
std_col = f'{op}_std'
|
||||||
|
x = np.arange(len(structures))
|
||||||
|
width = 0.35
|
||||||
|
for j, mode in enumerate(modes):
|
||||||
|
data = grouped[grouped['Mode'] == mode]
|
||||||
|
means = [data[data['Structure'] == s][mean_col].values[0] for s in structures]
|
||||||
|
stds = [data[data['Structure'] == s][std_col].values[0] for s in structures]
|
||||||
|
offset = (j - 0.5) * width
|
||||||
|
bars = ax.bar(x + offset, means, width, yerr=stds, capsize=3,
|
||||||
|
label=mode.capitalize(), color=colors[mode])
|
||||||
|
|
||||||
|
ax.set_xticks(x)
|
||||||
|
ax.set_xticklabels(structures)
|
||||||
|
ax.set_ylabel('Time (seconds)')
|
||||||
|
ax.set_title(f'{op} Time')
|
||||||
|
ax.legend()
|
||||||
|
|
||||||
|
if op == 'Insert':
|
||||||
|
ax.set_yscale('log')
|
||||||
|
ax.set_ylabel('Time (seconds) [log scale]')
|
||||||
|
|
||||||
|
plt.tight_layout()
|
||||||
|
plt.savefig('performance_plots.png', dpi=150)
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
print("Графики сохранены в файл performance_plots.png")
|
||||||
282
VaravinVV/docs/data/task1_1.py
Normal file
282
VaravinVV/docs/data/task1_1.py
Normal file
|
|
@ -0,0 +1,282 @@
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
import csv
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.setrecursionlimit(20000)
|
||||||
|
|
||||||
|
def ll_insert(head, name, phone):
|
||||||
|
data = {'name': name, 'phone': phone, "next": None}
|
||||||
|
|
||||||
|
if head is None:
|
||||||
|
return data
|
||||||
|
|
||||||
|
current = head
|
||||||
|
while current:
|
||||||
|
if current['name'] == name:
|
||||||
|
current['phone'] = phone
|
||||||
|
return head
|
||||||
|
if current['next'] is None:
|
||||||
|
last = current
|
||||||
|
current = current['next']
|
||||||
|
|
||||||
|
last['next'] = data
|
||||||
|
return head
|
||||||
|
|
||||||
|
|
||||||
|
def ll_find(head, name):
|
||||||
|
current = head
|
||||||
|
while current:
|
||||||
|
if current['name'] == name:
|
||||||
|
return current['phone']
|
||||||
|
current = current['next']
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def ll_delete(head, name):
|
||||||
|
if head is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if head['name'] == name:
|
||||||
|
return head['next']
|
||||||
|
|
||||||
|
prev = head
|
||||||
|
current = head['next']
|
||||||
|
while current:
|
||||||
|
if current['name'] == name:
|
||||||
|
prev['next'] = current['next']
|
||||||
|
return head
|
||||||
|
prev = current
|
||||||
|
current = current['next']
|
||||||
|
return head
|
||||||
|
|
||||||
|
|
||||||
|
def ll_list_all(head):
|
||||||
|
data_list = []
|
||||||
|
current = head
|
||||||
|
while current:
|
||||||
|
data_list.append({'name': current['name'], 'phone': current['phone']})
|
||||||
|
current = current['next']
|
||||||
|
data_list.sort(key=lambda x: x['name'])
|
||||||
|
return data_list
|
||||||
|
|
||||||
|
|
||||||
|
def hash_function(name, size):
|
||||||
|
return hash(name) % size
|
||||||
|
|
||||||
|
|
||||||
|
def ht_insert(buckets, name, phone):
|
||||||
|
index = hash_function(name, len(buckets))
|
||||||
|
head = buckets[index]
|
||||||
|
new_head = ll_insert(head, name, phone)
|
||||||
|
buckets[index] = new_head
|
||||||
|
return buckets
|
||||||
|
|
||||||
|
|
||||||
|
def ht_find(buckets, name):
|
||||||
|
index = hash_function(name, len(buckets))
|
||||||
|
head = buckets[index]
|
||||||
|
return ll_find(head, name)
|
||||||
|
|
||||||
|
|
||||||
|
def ht_delete(buckets, name):
|
||||||
|
index = hash_function(name, len(buckets))
|
||||||
|
head = buckets[index]
|
||||||
|
new_head = ll_delete(head, name)
|
||||||
|
buckets[index] = new_head
|
||||||
|
return buckets
|
||||||
|
|
||||||
|
|
||||||
|
def ht_list_all(buckets):
|
||||||
|
all_records = []
|
||||||
|
for head in buckets:
|
||||||
|
current = head
|
||||||
|
while current is not None:
|
||||||
|
all_records.append((current['name'], current['phone']))
|
||||||
|
current = current['next']
|
||||||
|
all_records.sort(key=lambda x: x[0])
|
||||||
|
return all_records
|
||||||
|
|
||||||
|
|
||||||
|
def create_node(name, phone):
|
||||||
|
return {'name': name, 'phone': phone, 'left': None, 'right': None}
|
||||||
|
|
||||||
|
|
||||||
|
def bst_insert(root, name, phone):
|
||||||
|
if root is None:
|
||||||
|
return create_node(name, phone)
|
||||||
|
|
||||||
|
if name == root['name']:
|
||||||
|
root['phone'] = phone
|
||||||
|
elif name < root['name']:
|
||||||
|
root['left'] = bst_insert(root['left'], name, phone)
|
||||||
|
else:
|
||||||
|
root['right'] = bst_insert(root['right'], name, phone)
|
||||||
|
return root
|
||||||
|
|
||||||
|
|
||||||
|
def bst_find(root, name):
|
||||||
|
if root is None:
|
||||||
|
return None
|
||||||
|
if name == root['name']:
|
||||||
|
return root['phone']
|
||||||
|
elif name < root['name']:
|
||||||
|
return bst_find(root['left'], name)
|
||||||
|
else:
|
||||||
|
return bst_find(root['right'], name)
|
||||||
|
|
||||||
|
|
||||||
|
def find_min(node):
|
||||||
|
while node['left'] is not None:
|
||||||
|
node = node['left']
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
def bst_delete(root, name):
|
||||||
|
if root is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if name < root['name']:
|
||||||
|
root['left'] = bst_delete(root['left'], name)
|
||||||
|
elif name > root['name']:
|
||||||
|
root['right'] = bst_delete(root['right'], name)
|
||||||
|
else:
|
||||||
|
if root['left'] is None:
|
||||||
|
return root['right']
|
||||||
|
if root['right'] is None:
|
||||||
|
return root['left']
|
||||||
|
|
||||||
|
min_node = find_min(root['right'])
|
||||||
|
root['name'] = min_node['name']
|
||||||
|
root['phone'] = min_node['phone']
|
||||||
|
root['right'] = bst_delete(root['right'], min_node['name'])
|
||||||
|
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
|
||||||
|
|
||||||
|
def generate_records(n, seed=50): #почти в точности позаимствовано, просто понял что можно уже существующие в отдельный список заносить
|
||||||
|
random.seed(seed)
|
||||||
|
records = []
|
||||||
|
for i in range(1, n + 1):
|
||||||
|
name = f"User_{i:05d}"
|
||||||
|
phone = "8" + ''.join(str(random.randint(0, 9)) for _ in range(10))
|
||||||
|
records.append((name, phone))
|
||||||
|
return records
|
||||||
|
|
||||||
|
def prepare_datasets(base_records):
|
||||||
|
shuffled = base_records.copy()
|
||||||
|
random.shuffle(shuffled)
|
||||||
|
sorted_records = sorted(base_records, key=lambda x: x[0])
|
||||||
|
return shuffled, sorted_records
|
||||||
|
|
||||||
|
def run_experiment(struct_funcs, records, mode_name, repeats=5):
|
||||||
|
results = []
|
||||||
|
for rep in range(repeats):
|
||||||
|
struct = struct_funcs['create']()
|
||||||
|
|
||||||
|
start = time.perf_counter()
|
||||||
|
for name, phone in records:
|
||||||
|
struct = struct_funcs['insert'](struct, name, phone)
|
||||||
|
end = time.perf_counter()
|
||||||
|
insert_time = end - start
|
||||||
|
|
||||||
|
existing_names = [name for name, _ in records]
|
||||||
|
sample_existing = random.sample(existing_names, 100)
|
||||||
|
nonexistent = [f"None_{i}" for i in range(10)]
|
||||||
|
search_names = sample_existing + nonexistent
|
||||||
|
random.shuffle(search_names)
|
||||||
|
|
||||||
|
start = time.perf_counter()
|
||||||
|
for name in search_names:
|
||||||
|
_ = struct_funcs['find'](struct, name)
|
||||||
|
end = time.perf_counter()
|
||||||
|
find_time = end - start
|
||||||
|
|
||||||
|
to_delete = random.sample(existing_names, 10)
|
||||||
|
start = time.perf_counter()
|
||||||
|
for name in to_delete:
|
||||||
|
struct = struct_funcs['delete'](struct, name)
|
||||||
|
end = time.perf_counter()
|
||||||
|
delete_time = end - start
|
||||||
|
|
||||||
|
results.append({
|
||||||
|
'structure': struct_funcs['name'],
|
||||||
|
'mode': mode_name,
|
||||||
|
'repetition': rep + 1,
|
||||||
|
'insert_time': insert_time,
|
||||||
|
'find_time': find_time,
|
||||||
|
'delete_time': delete_time
|
||||||
|
})
|
||||||
|
return results
|
||||||
|
|
||||||
|
def main():
|
||||||
|
N = 1000
|
||||||
|
base_records = generate_records(N)
|
||||||
|
shuffled, sorted_records = prepare_datasets(base_records)
|
||||||
|
|
||||||
|
structures = {
|
||||||
|
'LinkedList': {
|
||||||
|
'name': 'LinkedList',
|
||||||
|
'create': lambda: None,
|
||||||
|
'insert': ll_insert,
|
||||||
|
'find': ll_find,
|
||||||
|
'delete': ll_delete,
|
||||||
|
'list_all': ll_list_all
|
||||||
|
},
|
||||||
|
'HashTable': {
|
||||||
|
'name': 'HashTable',
|
||||||
|
'create': lambda: [None] * 10,
|
||||||
|
'insert': ht_insert,
|
||||||
|
'find': ht_find,
|
||||||
|
'delete': ht_delete,
|
||||||
|
'list_all': ht_list_all
|
||||||
|
},
|
||||||
|
'BST': {
|
||||||
|
'name': 'BST',
|
||||||
|
'create': lambda: None,
|
||||||
|
'insert': bst_insert,
|
||||||
|
'find': bst_find,
|
||||||
|
'delete': bst_delete,
|
||||||
|
'list_all': bst_list_all
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
all_results = []
|
||||||
|
repeats = 5
|
||||||
|
|
||||||
|
for struct_name, funcs in structures.items():
|
||||||
|
print(f"Тестирование {struct_name} на случайном порядке...")
|
||||||
|
res = run_experiment(funcs, shuffled, 'random', repeats)
|
||||||
|
all_results.extend(res)
|
||||||
|
|
||||||
|
print(f"Тестирование {struct_name} на отсортированном порядке...")
|
||||||
|
res = run_experiment(funcs, sorted_records, 'sorted', repeats)
|
||||||
|
all_results.extend(res)
|
||||||
|
|
||||||
|
with open('res.csv', 'w', newline='', encoding='utf-8') as f:
|
||||||
|
writer = csv.writer(f)
|
||||||
|
writer.writerow(['Structure', 'Mode', 'Repeat', 'Insert (sec)', 'Search (sec)', 'Delete (sec)'])
|
||||||
|
for r in all_results:
|
||||||
|
writer.writerow([
|
||||||
|
r['structure'],
|
||||||
|
r['mode'],
|
||||||
|
r['repetition'],
|
||||||
|
f"{r['insert_time']:.6f}",
|
||||||
|
f"{r['find_time']:.6f}",
|
||||||
|
f"{r['delete_time']:.6f}"
|
||||||
|
])
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
10
VaravinVV/docs/data/task2/easy.txt
Normal file
10
VaravinVV/docs/data/task2/easy.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
##########
|
||||||
|
#S ### #
|
||||||
|
## ## # #
|
||||||
|
# ## # #
|
||||||
|
# #### # #
|
||||||
|
# # # #
|
||||||
|
### #
|
||||||
|
### ### ##
|
||||||
|
# ### E#
|
||||||
|
##########
|
||||||
1
VaravinVV/docs/data/task2/empty.txt
Normal file
1
VaravinVV/docs/data/task2/empty.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
S E
|
||||||
BIN
VaravinVV/docs/data/task2/graphs/results_easy.txt.png
Normal file
BIN
VaravinVV/docs/data/task2/graphs/results_easy.txt.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
BIN
VaravinVV/docs/data/task2/graphs/results_empty.txt.png
Normal file
BIN
VaravinVV/docs/data/task2/graphs/results_empty.txt.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
BIN
VaravinVV/docs/data/task2/graphs/results_hard.txt.png
Normal file
BIN
VaravinVV/docs/data/task2/graphs/results_hard.txt.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
BIN
VaravinVV/docs/data/task2/graphs/results_medium.txt.png
Normal file
BIN
VaravinVV/docs/data/task2/graphs/results_medium.txt.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
BIN
VaravinVV/docs/data/task2/graphs/results_noexit.txt.png
Normal file
BIN
VaravinVV/docs/data/task2/graphs/results_noexit.txt.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
101
VaravinVV/docs/data/task2/hard.txt
Normal file
101
VaravinVV/docs/data/task2/hard.txt
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
#####################################################################################################
|
||||||
|
#S # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # ####### ########### # # # ######### ######### ##### # ### # ####### ##### # # # # # ### ### # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
### ### # ##### ##### ### ### ####### # # # ##### # # # ####### ##### ##### ### # ##### # ####### # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # ### # ### # # ####### # # ### ##### ### ### # ####### # ### ### ##### ##### ### ##### ### ### #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# ### ##### ######### ### ####### ### # ### # ### # ######### # ######### # ### # ### # ##### #######
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
### ### ### # ### ######### # ##### ### # # ### ####### # ########### # # ### ############### #######
|
||||||
|
# # # # # # # # # # # # # # # #
|
||||||
|
# ##### # # ####### # # ##### ### # ### ######### # ##### ##### ### ### # ### # # ####### # ### #####
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
### # ### # ### # ### # ### # ### ### # # ####### ####### ##### ##### # # # # ##### ### ### ### # ###
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # ### # ### # # ####### ##### # ######### # # # # ### # ### ### ### ##### # # ### # # ### # #######
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
##### # ##### # # ### # # # # # ####### # ### # ##### ### # ##### # # # # ##### # ### # ##### # # ###
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # # # ##### # # # ### # ### # ### ### # ##### # ### # # ##### ############# ##### ### ##### ### #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# ##### # # ### # ### ################### ### ### ### # ### # ### # # ### ### ######### ### ####### #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
##### ### ##### ####### ### ### ##### # # ### ### ### ### ### # ### ### ### ### ##### # # ### # #####
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
### # ### # ### # # # # # ####### # ### ############# ####### ### ### ### # # ### ####### # ### # ###
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # ##### ### # ### # ### # ### # # # # # ### ### # ### ### # # ### ##### # ### ### # ##### ##### #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # ##### ##### # # # ############### ##### # ### ### # # ##### ####### ##### ####### ##### ### # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
##### ### ##### # # # # # # ### ##### ### ########### # ### # # # ### ### # # # ### # # ######### # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
### # ### # ### # ##### ##### ##### ########### # ### ### ##### # ##### ### ### ##### ######### # # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# ### # ####### # ### ##### # # ############# ### ####### # # ### # # ### # ####### ### # # # # #####
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
####### # # ### # ########### # ### ##### ########### # ##### ### # ### ############# # # # # ##### #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# ### ##### ### # ### # # ### ### ### ### # ##### ##### ### # # ### ### # # ##### ### ####### #######
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# ##### # # # # ##### # # # ######### ### # ####### # # ####### # ##### ### # ### ### # # ####### ###
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # ####### # # # # # ### ####### # # # ####### # ### # ### ### # ##### ##### ### # ##### ### ### # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# ##### ### # # ######### ##### ####### ##### # ##### ####### ### ### ####### ##### ### ##### # # # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # ######### # # # ####### ### # ####### # # ##### # ### # ### # ########### ############# ##### # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# ### ##### # ##### # ### # ##### # ### # ### ### # # ### ##### ##### # # # ### # ############# # ###
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
### # ### ### # # ######### ### ### ### ### # # ####### # ### ######### ### ##### # # # # ### # #####
|
||||||
|
# # # # # # # # # # # # # # # # # # # # #
|
||||||
|
### # ######### ######### # ### # # ### # ############# # # # # # # ############# ######### # #######
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # # ### ### ### ### ### # ##### # # ##### ####### # # # # ### # # # # ### ### # # # # ##### # ###
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # ### ##### ### ### # # # ### # # ######### ######### ##### ##### # ######### ### # # ### # ### ###
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
### ##### ### # # # ############### # ### ### # # ### ### # ##### # ### # ##### ### ######### # #####
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# ##### ### ### ### # ####### # ### # ### ### ######### # ### ######### # # ### # ### ########### ###
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # ### ### # # ##### ### # # ### ### ##### ### ### # ########### # ### ####### # # ######### ### ###
|
||||||
|
# # # # # # # # # # # # # # # # # # # #
|
||||||
|
##### ### # # # # # # ##### ####### # # # ####### # ####### # ##### ######### # ### # ####### # #####
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# ### # ### ### ####### # ### # ### # # ####### # ### # ### ##### ##### ### ####### # # # ##### ### #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # ### # # ############### # # ##### # ##### ########### # # # ### # ### ### ### ### # ### # ### #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
##### ######### ##### ### # ### # ### # ### ### ####### ######### ########### ##### # ### # ### # # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
### # ### ### # ##### # ##### # ##### # # ##### ####### # ####### ### ##### ### ####### ##### ### ###
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
##### ### # # ##### ####### ### # ##### ####### ### # # # ### ####### ### # ##### ####### # # ##### #
|
||||||
|
# # # # # # # # # # # # # # # # # #
|
||||||
|
# ### ####### ##### ####### ### # ### ##### ##### ### # # ### # ### ### # # # ####### # # ##### # # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# ### ### ##### ######### # ##### ##### # # # # ### ##### ### # # # # # ######### # ######### # ### #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # ####### ### ##### ######### ##### ########### # ### # ### # # # # ##### # # ### ##### ##### ###
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # ### # ### ##### ### # ########### ##### # ####### # ##### # # ### # # ##### ### # ######### ###
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # ### ### # ######### # ### # # # ##### ### # # ### ##### ##### ### ### ############# ####### # #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
##### ### # ### ### # # # ### ##### # ##### # ##### # ### ##### # ### ### # # # # # ##### # #########
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # ##### # ### # # # ##### # ### ### ##### # ### ##### # ### ####### ### # ##### ### # ##### # # ###
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# # # ### ########### ##### # ### # # ### # ######### ####### # # # # ########### ### ####### ##### #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
# ### # # ### ############# ### # ### ##### ### ### ##### # # ### ######### ### ### ### # # ### ### #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
##### ### # ### # # # # # ### # # ### # # ####### ####### # # ##### # ### # # ##### # ### # ### ### #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # #
|
||||||
|
### # ### ##### ### ### # # # ##### ### # ### ### ##### # ##### ### # # ##### # ####### # ######### #
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # E#
|
||||||
|
#####################################################################################################
|
||||||
427
VaravinVV/docs/data/task2/main.py
Normal file
427
VaravinVV/docs/data/task2/main.py
Normal file
|
|
@ -0,0 +1,427 @@
|
||||||
|
import abc
|
||||||
|
import heapq
|
||||||
|
import time
|
||||||
|
from collections import deque
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import List, Optional, Dict, Set, Tuple, Any
|
||||||
|
import csv
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class Cell:
|
||||||
|
#тут что такое клетка
|
||||||
|
def __init__(self, x: int, y: int, is_wall: bool = False,
|
||||||
|
is_exit: bool = False, is_start: bool = False):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.is_wall = is_wall
|
||||||
|
self.is_exit = is_exit
|
||||||
|
self.is_start = is_start
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return isinstance(other, Cell) and self.x == other.x and self.y == other.y
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash((self.x, self.y))
|
||||||
|
|
||||||
|
def is_passable(self) -> bool:
|
||||||
|
return not self.is_wall
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"Cell({self.x},{self.y})"
|
||||||
|
|
||||||
|
|
||||||
|
class Maze:
|
||||||
|
def __init__(self, width: int, height: int): #что содержит лабиринт, начало конец и тд
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
self.grid: List[List[Cell]] = []
|
||||||
|
self.start_cell: Optional[Cell] = None
|
||||||
|
self.exit_cell: Optional[Cell] = None
|
||||||
|
|
||||||
|
def set_cell(self, x: int, y: int, cell: Cell) -> None: #ставим клетку куда надо или не ставим если в границы не попала
|
||||||
|
if not (0 <= x < self.width and 0 <= y < self.height):
|
||||||
|
raise IndexError("координаты вне границ лабиринта")
|
||||||
|
self.grid[y][x] = cell
|
||||||
|
|
||||||
|
def get_cell(self, x: int, y: int) -> Optional[Cell]: #тут уже из коррдинат клетку вытаскиваем
|
||||||
|
if 0 <= x < self.width and 0 <= y < self.height:
|
||||||
|
return self.grid[y][x]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_neighbors(self, cell: Cell) -> List[Cell]: #если соседняя клетка проходима - добавляем
|
||||||
|
neighbors = []
|
||||||
|
for dx, dy in [(0, -1), (0, 1), (-1, 0), (1, 0)]:
|
||||||
|
nx, ny = cell.x + dx, cell.y + dy
|
||||||
|
neighbor = self.get_cell(nx, ny)
|
||||||
|
if neighbor and neighbor.is_passable():
|
||||||
|
neighbors.append(neighbor)
|
||||||
|
return neighbors
|
||||||
|
|
||||||
|
|
||||||
|
class MazeBuilder(abc.ABC):
|
||||||
|
@abc.abstractmethod
|
||||||
|
def build_from_file(self, filename: str) -> Maze:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TextFileMazeBuilder(MazeBuilder):
|
||||||
|
def build_from_file(self, filename: str) -> Maze:
|
||||||
|
lines = []
|
||||||
|
with open(filename, 'r', encoding='utf-8') as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.rstrip('\n')
|
||||||
|
if line: #игнорируем пустые строки
|
||||||
|
lines.append(line)
|
||||||
|
|
||||||
|
if not lines:
|
||||||
|
raise ValueError("Файл пуст")
|
||||||
|
|
||||||
|
height = len(lines)
|
||||||
|
width = max(len(line) for line in lines)
|
||||||
|
|
||||||
|
maze = Maze(width, height)
|
||||||
|
#инициализируем сетку пустыми клетками,по умолчанию стенами
|
||||||
|
maze.grid = [[Cell(x, y, is_wall=True) for x in range(width)] for y in range(height)]
|
||||||
|
|
||||||
|
start_cell = None
|
||||||
|
exit_cell = None
|
||||||
|
|
||||||
|
for y, line in enumerate(lines):
|
||||||
|
for x, ch in enumerate(line):
|
||||||
|
if x >= width:
|
||||||
|
continue
|
||||||
|
if ch == '#':
|
||||||
|
continue
|
||||||
|
elif ch == ' ':
|
||||||
|
cell = Cell(x, y, is_wall=False)
|
||||||
|
elif ch == 'S':
|
||||||
|
cell = Cell(x, y, is_wall=False, is_start=True)
|
||||||
|
start_cell = cell
|
||||||
|
elif ch == 'E':
|
||||||
|
cell = Cell(x, y, is_wall=False, is_exit=True)
|
||||||
|
exit_cell = cell
|
||||||
|
else:
|
||||||
|
#любой другой символ считаем проходом
|
||||||
|
cell = Cell(x, y, is_wall=False)
|
||||||
|
maze.set_cell(x, y, cell)
|
||||||
|
|
||||||
|
if start_cell is None:
|
||||||
|
raise ValueError("отсутствует стартовая клетка (S)") #invalid check
|
||||||
|
if exit_cell is None:
|
||||||
|
raise ValueError("отсутствует выход (E)")
|
||||||
|
|
||||||
|
maze.start_cell = start_cell
|
||||||
|
maze.exit_cell = exit_cell
|
||||||
|
return maze
|
||||||
|
|
||||||
|
class PathFindingStrategy(abc.ABC):
|
||||||
|
@abc.abstractmethod
|
||||||
|
def find_path(self, maze: Maze, start: Cell, exit_: Cell) -> Tuple[List[Cell], int]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
#дальше скорее математика, методы вроде ещё в том семаке разбирали
|
||||||
|
class BFSStrategy(PathFindingStrategy):
|
||||||
|
def find_path(self, maze: Maze, start: Cell, exit_: Cell) -> Tuple[List[Cell], int]:
|
||||||
|
if start is exit_:
|
||||||
|
return [start], 1
|
||||||
|
|
||||||
|
queue = deque([start]) #используйте deque 👍
|
||||||
|
visited: Set[Cell] = {start}
|
||||||
|
parent: Dict[Cell, Optional[Cell]] = {start: None}
|
||||||
|
|
||||||
|
while queue:
|
||||||
|
current = queue.popleft()
|
||||||
|
if current is exit_:
|
||||||
|
#восстановление пути
|
||||||
|
path = []
|
||||||
|
cur = current
|
||||||
|
while cur is not None:
|
||||||
|
path.append(cur)
|
||||||
|
cur = parent[cur]
|
||||||
|
path.reverse()
|
||||||
|
return path, len(visited)
|
||||||
|
|
||||||
|
for neighbor in maze.get_neighbors(current):
|
||||||
|
if neighbor not in visited:
|
||||||
|
visited.add(neighbor)
|
||||||
|
parent[neighbor] = current
|
||||||
|
queue.append(neighbor)
|
||||||
|
|
||||||
|
return [], len(visited)
|
||||||
|
|
||||||
|
|
||||||
|
class DFSStrategy(PathFindingStrategy):
|
||||||
|
def find_path(self, maze: Maze, start: Cell, exit_: Cell) -> Tuple[List[Cell], int]:
|
||||||
|
if start is exit_:
|
||||||
|
return [start], 1
|
||||||
|
|
||||||
|
stack = [start]
|
||||||
|
visited: Set[Cell] = {start}
|
||||||
|
parent: Dict[Cell, Optional[Cell]] = {start: None}
|
||||||
|
|
||||||
|
while stack:
|
||||||
|
current = stack.pop()
|
||||||
|
if current is exit_:
|
||||||
|
path = []
|
||||||
|
cur = current
|
||||||
|
while cur is not None:
|
||||||
|
path.append(cur)
|
||||||
|
cur = parent[cur]
|
||||||
|
path.reverse()
|
||||||
|
return path, len(visited)
|
||||||
|
|
||||||
|
for neighbor in maze.get_neighbors(current):
|
||||||
|
if neighbor not in visited:
|
||||||
|
visited.add(neighbor)
|
||||||
|
parent[neighbor] = current
|
||||||
|
stack.append(neighbor)
|
||||||
|
|
||||||
|
return [], len(visited)
|
||||||
|
|
||||||
|
|
||||||
|
class AStarStrategy(PathFindingStrategy):
|
||||||
|
@staticmethod
|
||||||
|
def _heuristic(cell: Cell, target: Cell) -> int:
|
||||||
|
return abs(cell.x - target.x) + abs(cell.y - target.y) #самая простая эвристика
|
||||||
|
|
||||||
|
def find_path(self, maze: Maze, start: Cell, exit_: Cell) -> Tuple[List[Cell], int]:
|
||||||
|
if start is exit_:
|
||||||
|
return [start], 1
|
||||||
|
counter = 0
|
||||||
|
open_set = [(0, counter, start)]
|
||||||
|
g_score: Dict[Cell, int] = {start: 0}
|
||||||
|
f_score: Dict[Cell, int] = {start: self._heuristic(start, exit_)}
|
||||||
|
parent: Dict[Cell, Optional[Cell]] = {start: None}
|
||||||
|
closed_set: Set[Cell] = set()
|
||||||
|
visited_count = 0
|
||||||
|
|
||||||
|
while open_set:
|
||||||
|
_, _, current = heapq.heappop(open_set)
|
||||||
|
if current in closed_set:
|
||||||
|
continue
|
||||||
|
closed_set.add(current)
|
||||||
|
visited_count = len(closed_set)
|
||||||
|
|
||||||
|
if current is exit_:
|
||||||
|
path = []
|
||||||
|
cur = current
|
||||||
|
while cur is not None:
|
||||||
|
path.append(cur)
|
||||||
|
cur = parent[cur]
|
||||||
|
path.reverse()
|
||||||
|
return path, visited_count
|
||||||
|
|
||||||
|
for neighbor in maze.get_neighbors(current):
|
||||||
|
if neighbor in closed_set:
|
||||||
|
continue
|
||||||
|
tentative_g = g_score[current] + 1
|
||||||
|
if neighbor not in g_score or tentative_g < g_score[neighbor]:
|
||||||
|
parent[neighbor] = current
|
||||||
|
g_score[neighbor] = tentative_g
|
||||||
|
f = tentative_g + self._heuristic(neighbor, exit_)
|
||||||
|
f_score[neighbor] = f
|
||||||
|
counter += 1
|
||||||
|
heapq.heappush(open_set, (f, counter, neighbor))
|
||||||
|
|
||||||
|
return [], visited_count
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SearchStats:
|
||||||
|
time_ms: float #время выполнения в мс
|
||||||
|
visited_cells: int #количество посещённых клеток
|
||||||
|
path_length: int #длина найденного пути (0 если пути нет)
|
||||||
|
path_found: bool #найден ли путь
|
||||||
|
|
||||||
|
class Observer(abc.ABC): #я забыл что я там писать хотел после наблюдателя удачи мне завтра разобрать
|
||||||
|
@abc.abstractmethod #а я (гугл + хабр) разобрал снова балбесина!!!
|
||||||
|
def update(self, event_type: str, data: Any = None) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Subject:
|
||||||
|
def __init__(self):
|
||||||
|
self._observers: List[Observer] = []
|
||||||
|
|
||||||
|
def attach(self, observer: Observer) -> None:
|
||||||
|
if observer not in self._observers:
|
||||||
|
self._observers.append(observer)
|
||||||
|
|
||||||
|
def detach(self, observer: Observer) -> None:
|
||||||
|
if observer in self._observers:
|
||||||
|
self._observers.remove(observer)
|
||||||
|
|
||||||
|
def notify(self, event_type: str, data: Any = None) -> None:
|
||||||
|
for obs in self._observers:
|
||||||
|
obs.update(event_type, data)
|
||||||
|
|
||||||
|
|
||||||
|
class MazeSolver(Subject):
|
||||||
|
def __init__(self, maze: Maze, strategy: Optional[PathFindingStrategy] = None):
|
||||||
|
super().__init__()
|
||||||
|
self.maze = maze
|
||||||
|
self._strategy = strategy
|
||||||
|
|
||||||
|
def set_strategy(self, strategy: PathFindingStrategy) -> None:
|
||||||
|
self._strategy = strategy
|
||||||
|
|
||||||
|
def solve(self) -> Optional[SearchStats]:
|
||||||
|
if self._strategy is None:
|
||||||
|
return None
|
||||||
|
start_time = time.perf_counter()
|
||||||
|
path, visited = self._strategy.find_path(self.maze, self.maze.start_cell, self.maze.exit_cell)
|
||||||
|
end_time = time.perf_counter()
|
||||||
|
time_ms = (end_time - start_time) * 1000.0
|
||||||
|
return SearchStats(time_ms, visited, len(path), len(path) > 0)
|
||||||
|
|
||||||
|
class Benchmark:
|
||||||
|
def __init__(self, maze_files: List[str], runs_per_strategy: int = 5):
|
||||||
|
self.maze_files = maze_files
|
||||||
|
self.runs = runs_per_strategy
|
||||||
|
self.strategies = {
|
||||||
|
"BFS": BFSStrategy(),
|
||||||
|
"DFS": DFSStrategy(),
|
||||||
|
"AStar": AStarStrategy()
|
||||||
|
}
|
||||||
|
self.builder = TextFileMazeBuilder()
|
||||||
|
self.results = []
|
||||||
|
|
||||||
|
def run(self, output_csv: str):
|
||||||
|
for maze_file in self.maze_files:
|
||||||
|
if not os.path.exists(maze_file):
|
||||||
|
print(f"файл {maze_file} не найден")
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
maze = self.builder.build_from_file(maze_file)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ошибка загрузки {maze_file}: {e}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"обработка лабиринта: {maze_file} (размер {maze.width}x{maze.height})")
|
||||||
|
for strat_name, strategy in self.strategies.items():
|
||||||
|
solver = MazeSolver(maze, strategy)
|
||||||
|
times = []
|
||||||
|
visited_list = []
|
||||||
|
path_lengths = []
|
||||||
|
path_found = False
|
||||||
|
for run_idx in range(self.runs):
|
||||||
|
stats = solver.solve()
|
||||||
|
if stats is None:
|
||||||
|
continue
|
||||||
|
times.append(stats.time_ms)
|
||||||
|
visited_list.append(stats.visited_cells)
|
||||||
|
path_lengths.append(stats.path_length)
|
||||||
|
path_found = stats.path_found
|
||||||
|
if times:
|
||||||
|
avg_time = sum(times) / len(times)
|
||||||
|
avg_visited = sum(visited_list) / len(visited_list)
|
||||||
|
avg_length = sum(path_lengths) / len(path_lengths)
|
||||||
|
else:
|
||||||
|
avg_time = avg_visited = avg_length = 0.0
|
||||||
|
self.results.append({
|
||||||
|
"лабиринт": os.path.basename(maze_file),
|
||||||
|
"стратегия": strat_name,
|
||||||
|
"время_мс": round(avg_time, 3),
|
||||||
|
"посещено_клеток": round(avg_visited, 1),
|
||||||
|
"длина_пути": round(avg_length, 1),
|
||||||
|
"путь_найден": path_found
|
||||||
|
})
|
||||||
|
print(f" {strat_name}: {avg_time:.3f} мс, посещено {avg_visited:.1f}, длина {avg_length:.1f}")
|
||||||
|
|
||||||
|
with open(output_csv, 'w', newline='', encoding='utf-8') as csvfile:
|
||||||
|
fieldnames = ["лабиринт", "стратегия", "время_мс", "посещено_клеток", "длина_пути", "путь_найден"]
|
||||||
|
writer = csv.DictWriter(csvfile, fieldnames=fieldnames, delimiter=',')
|
||||||
|
writer.writeheader()
|
||||||
|
for row in self.results:
|
||||||
|
writer.writerow(row)
|
||||||
|
print(f"\nрезультаты сохранены в {output_csv}")
|
||||||
|
|
||||||
|
def interactive_mode(maze_file: str):
|
||||||
|
builder = TextFileMazeBuilder()
|
||||||
|
try:
|
||||||
|
maze = builder.build_from_file(maze_file)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ошибка загрузки лабиринта: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
strategies = {
|
||||||
|
"1": ("BFS", BFSStrategy()),
|
||||||
|
"2": ("DFS", DFSStrategy()),
|
||||||
|
"3": ("A*", AStarStrategy())
|
||||||
|
}
|
||||||
|
print("\nвыберите алгоритм поиска:")
|
||||||
|
print("1. BFS")
|
||||||
|
print("2. DFS")
|
||||||
|
print("3. A*")
|
||||||
|
choice = input("введите (1/2/3): ").strip()
|
||||||
|
|
||||||
|
if choice not in strategies:
|
||||||
|
print("неверный выбор, по умолчанию используется BFS.")
|
||||||
|
strat_name, strategy = strategies["1"]
|
||||||
|
else:
|
||||||
|
strat_name, strategy = strategies[choice]
|
||||||
|
|
||||||
|
solver = MazeSolver(maze, strategy)
|
||||||
|
stats = solver.solve()
|
||||||
|
if stats is None:
|
||||||
|
print("ошибка с решением")
|
||||||
|
return
|
||||||
|
|
||||||
|
path, _ = strategy.find_path(maze, maze.start_cell, maze.exit_cell)
|
||||||
|
path_set = set(path)
|
||||||
|
for y in range(maze.height):
|
||||||
|
row = []
|
||||||
|
for x in range(maze.width):
|
||||||
|
cell = maze.get_cell(x, y)
|
||||||
|
if cell is maze.start_cell:
|
||||||
|
row.append('S')
|
||||||
|
elif cell is maze.exit_cell:
|
||||||
|
row.append('E')
|
||||||
|
elif cell in path_set:
|
||||||
|
row.append('*')
|
||||||
|
elif cell and cell.is_wall:
|
||||||
|
row.append('#')
|
||||||
|
else:
|
||||||
|
row.append(' ')
|
||||||
|
print(''.join(row))
|
||||||
|
|
||||||
|
print(f"\nстатистика ({strat_name}):")
|
||||||
|
print(f"время выполнения: {stats.time_ms:.3f} мс")
|
||||||
|
print(f"посещено клеток: {stats.visited_cells}")
|
||||||
|
print(f"длина пути: {stats.path_length}")
|
||||||
|
print(f"путь найден: {'да' if stats.path_found else 'нет'}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("использование:")
|
||||||
|
print("режим визуализации: python main.py <файл_лабиринта>")
|
||||||
|
print("режим замера: python main.py --benchmark <список_лабиринтов> --runs <кол_во_итераций> --output <название_таблицы>.csv")
|
||||||
|
return
|
||||||
|
|
||||||
|
if sys.argv[1] == "--benchmark":
|
||||||
|
args = sys.argv[2:]
|
||||||
|
maze_files = []
|
||||||
|
runs = 5
|
||||||
|
output = "benchmark_results.csv"
|
||||||
|
i = 0
|
||||||
|
while i < len(args):
|
||||||
|
if args[i] == "--runs" and i+1 < len(args):
|
||||||
|
runs = int(args[i+1])
|
||||||
|
i += 2
|
||||||
|
elif args[i] == "--output" and i+1 < len(args):
|
||||||
|
output = args[i+1]
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
maze_files.append(args[i])
|
||||||
|
i += 1
|
||||||
|
if not maze_files:
|
||||||
|
print("Ошибка: не указаны файлы лабиринтов.")
|
||||||
|
return
|
||||||
|
benchmark = Benchmark(maze_files, runs_per_strategy=runs)
|
||||||
|
benchmark.run(output)
|
||||||
|
else:
|
||||||
|
interactive_mode(sys.argv[1])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
51
VaravinVV/docs/data/task2/medium.txt
Normal file
51
VaravinVV/docs/data/task2/medium.txt
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
###################################################
|
||||||
|
#S # # # #
|
||||||
|
# # # ####### ########### # # # ######### #########
|
||||||
|
# # # # # # # # # # # # # #
|
||||||
|
### ### # ##### ##### ### ### ####### # # # ##### #
|
||||||
|
# # # # # # # # # # # # #
|
||||||
|
# # # ### # ### # # ####### # # ### ##### ### ### #
|
||||||
|
# # # # # # # # # #
|
||||||
|
# ### ##### ######### ### ####### ### # ### # ### #
|
||||||
|
# # # # # # # # # # # # # #
|
||||||
|
### ### ### # ### ######### # ##### ### # # ### ###
|
||||||
|
# # # # # # # # # # #
|
||||||
|
# ##### # # ####### # # ##### ### # ### ######### #
|
||||||
|
# # # # # # # # # # # # # #
|
||||||
|
### # ### # ### # ### # ### # ### ### ### #########
|
||||||
|
# # # # # # # # # # # # #
|
||||||
|
# # ### # ### # # ####### ##### # ######### ##### #
|
||||||
|
# # # # # # # # # # # # #
|
||||||
|
##### # ##### # # ### # # # # # ######### ##### ###
|
||||||
|
# # # # # # # # # # # # #
|
||||||
|
# # # # # ##### # # # ### # ### # ####### # #######
|
||||||
|
# # # # # # # # # # # # # # # # #
|
||||||
|
# ##### # # ### # ### ################# # ### ### #
|
||||||
|
# # # # # # # # # # # # #
|
||||||
|
##### ### ##### ####### ### ### ##### ### # # #####
|
||||||
|
# # # # # # # # # # # #
|
||||||
|
### # ### # ### # # # # # ##### # # ##### # # #####
|
||||||
|
# # # # # # # # # # # # # # # # #
|
||||||
|
# # # ##### ### # ### # ### # ### # ####### # # # #
|
||||||
|
# # # # # # # # # # # # # # #
|
||||||
|
# # # ##### ##### # # # ####### # ### ####### ### #
|
||||||
|
# # # # # # # # # # # # #
|
||||||
|
##### ### ##### # # # # # # ##### # # # # ### # # #
|
||||||
|
# # # # # # # # # # # # # # # # # # #
|
||||||
|
### # ### # ### # ##### ##### ####### ########### #
|
||||||
|
# # # # # # # # # # # #
|
||||||
|
# ### # ####### # ### ##### ##### ### ### #########
|
||||||
|
# # # # # # # # # # # #
|
||||||
|
####### # # ### # ######### # ##### # ##### # ### #
|
||||||
|
# # # # # # # # # # # # # #
|
||||||
|
# # ####### ### # ### # # ##### ######### ### #####
|
||||||
|
# # # # # # # # # # # # # #
|
||||||
|
### ### # # # # ##### ### ##### # # # ### # # # # #
|
||||||
|
# # # # # # # # # # # # # #
|
||||||
|
### ### # # # # ### # # # ##### ######### ####### #
|
||||||
|
# # # # # # # # # # # # #
|
||||||
|
##### # # ### # # ########### ### ##### # # ### # #
|
||||||
|
# # # # # # # # # # # # # #
|
||||||
|
### ### # ##### # # ### ### ##### ### # # ### ### #
|
||||||
|
# # # # # # # # # # # # #E#
|
||||||
|
###################################################
|
||||||
5
VaravinVV/docs/data/task2/noexit.txt
Normal file
5
VaravinVV/docs/data/task2/noexit.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#####
|
||||||
|
#S###
|
||||||
|
#####
|
||||||
|
###E#
|
||||||
|
#####
|
||||||
16
VaravinVV/docs/data/task2/res.csv
Normal file
16
VaravinVV/docs/data/task2/res.csv
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
лабиринт,стратегия,время_мс,посещено_клеток,длина_пути,путь_найден
|
||||||
|
easy.txt,BFS,0.046,32.0,17.0,True
|
||||||
|
easy.txt,DFS,0.026,28.0,17.0,True
|
||||||
|
easy.txt,AStar,0.037,21.0,17.0,True
|
||||||
|
medium.txt,BFS,1.141,1249.0,101.0,True
|
||||||
|
medium.txt,DFS,0.547,633.0,101.0,True
|
||||||
|
medium.txt,AStar,1.26,721.0,101.0,True
|
||||||
|
hard.txt,BFS,4.703,4997.0,209.0,True
|
||||||
|
hard.txt,DFS,3.61,4026.0,209.0,True
|
||||||
|
hard.txt,AStar,6.119,3377.0,209.0,True
|
||||||
|
noexit.txt,BFS,0.002,1.0,0.0,False
|
||||||
|
noexit.txt,DFS,0.002,1.0,0.0,False
|
||||||
|
noexit.txt,AStar,0.005,1.0,0.0,False
|
||||||
|
empty.txt,BFS,0.003,3.0,3.0,True
|
||||||
|
empty.txt,DFS,0.003,3.0,3.0,True
|
||||||
|
empty.txt,AStar,0.004,3.0,3.0,True
|
||||||
|
53
VaravinVV/docs/data/task2/tables.py
Normal file
53
VaravinVV/docs/data/task2/tables.py
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
import pandas as pd
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import seaborn as sns
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
def plot_results(csv_file: str, output_dir: str = "plots"):
|
||||||
|
if not os.path.exists(csv_file):
|
||||||
|
print(f"Файл {csv_file} не найден.")
|
||||||
|
return
|
||||||
|
df = pd.read_csv(csv_file, encoding='utf-8')
|
||||||
|
required = ["лабиринт", "стратегия", "время_мс", "посещено_клеток", "длина_пути"]
|
||||||
|
for col in required:
|
||||||
|
if col not in df.columns:
|
||||||
|
print(f"В CSV отсутствует колонка {col}")
|
||||||
|
return
|
||||||
|
|
||||||
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
|
|
||||||
|
sns.set_style("whitegrid")
|
||||||
|
|
||||||
|
for maze_name in df["лабиринт"].unique():
|
||||||
|
maze_df = df[df["лабиринт"] == maze_name]
|
||||||
|
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
|
||||||
|
fig.suptitle(f"Сравнение стратегий для лабиринта {maze_name}", fontsize=14)
|
||||||
|
|
||||||
|
ax = axes[0]
|
||||||
|
sns.barplot(data=maze_df, x="стратегия", y="время_мс", ax=ax, palette="viridis")
|
||||||
|
ax.set_title("Время выполнения (мс)")
|
||||||
|
ax.set_ylabel("мс")
|
||||||
|
|
||||||
|
ax = axes[1]
|
||||||
|
sns.barplot(data=maze_df, x="стратегия", y="посещено_клеток", ax=ax, palette="plasma")
|
||||||
|
ax.set_title("Количество посещённых клеток")
|
||||||
|
ax.set_ylabel("клетки")
|
||||||
|
|
||||||
|
ax = axes[2]
|
||||||
|
sns.barplot(data=maze_df, x="стратегия", y="длина_пути", ax=ax, palette="coolwarm")
|
||||||
|
ax.set_title("Длина найденного пути")
|
||||||
|
ax.set_ylabel("шаги")
|
||||||
|
|
||||||
|
plt.tight_layout()
|
||||||
|
plt.savefig(os.path.join(output_dir, f"results_{maze_name}.png"), dpi=150)
|
||||||
|
plt.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Использование: python tables.py <csv_файл> <папка_для_сохранения>")
|
||||||
|
print("Пример: python tables.py res.csv plots")
|
||||||
|
sys.exit(1)
|
||||||
|
csv_file = sys.argv[1]
|
||||||
|
out_dir = sys.argv[2] if len(sys.argv) > 2 else "plots"
|
||||||
|
plot_results(csv_file, out_dir)
|
||||||
BIN
VaravinVV/docs/report_task2.docx
Normal file
BIN
VaravinVV/docs/report_task2.docx
Normal file
Binary file not shown.
BIN
VaravinVV/docs/task1_report.docx
Normal file
BIN
VaravinVV/docs/task1_report.docx
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user