forked from UNN/2026-rff_mp
Merge branch 'SolovevDS-task2' into SolovevDS-task1
This commit is contained in:
commit
63e6158583
76
SolovevDS/docs/data/data_for_task2/diagrams.py
Normal file
76
SolovevDS/docs/data/data_for_task2/diagrams.py
Normal file
|
|
@ -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"
|
||||||
|
)
|
||||||
10
SolovevDS/docs/data/data_for_task2/maze10.txt
Normal file
10
SolovevDS/docs/data/data_for_task2/maze10.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
##########
|
||||||
|
#S ###
|
||||||
|
###### ###
|
||||||
|
# ###
|
||||||
|
# #### ###
|
||||||
|
# # ###
|
||||||
|
# # ######
|
||||||
|
# # #
|
||||||
|
# ######E#
|
||||||
|
##########
|
||||||
100
SolovevDS/docs/data/data_for_task2/maze100.txt
Normal file
100
SolovevDS/docs/data/data_for_task2/maze100.txt
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
####################################################################################################
|
||||||
|
#S # # # # # # # # # ##
|
||||||
|
## ############### # ## ## ###### # ### ### ### ########### ### # ## # ####### # ### # # # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ### # ##### # #### ##### ######### # ##### # ##### # ### ##### ### # # ### # ####### ##### # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ##### ### ##### ##### # # ### # ##### # ##### # ####### ######### ##### # # # # ### ### # # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # # ### # # # ### # ##### ### ### # # ##### # # # ### # # ##### ### ##### ### ########### ### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # ### ########### # # ### # ### # # ### # ### # ##### # ####### #### ## # ### ######### ####### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ####### ### # # # ### # ### ################# ############# # ### ## ### ## # ### ### # # # # ####
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
####### ### ### ##### ### # # ########### # ####### ### # ### # ##### # # ##### ### # ### ##### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ### # # ### ####### # # ##### ### # ### ### # ### # # # # ##### # # ########### # ##### # # ######
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # ##### #### # # # # # # ## ## # # ### ##### ### # ####### ### ####### # # # # ### # # ##### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # ## # # # ### ####### # # # ##### # # ## # # # ######### ### ####### # ### ### # # # ### # # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ##### ### # # ##### # ### ##### # ### ### ### ##### # # # ### ###### ##### # # # # ##### ### # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ##### # ######### # ######### ### # ## #### ### ############### # ########### ######### ## # # ##
|
||||||
|
# # # # # # # # # # # # # # # # ##
|
||||||
|
# ####### # # ##### ### # #### # ### # ### # # # ############# # # # # # # # ####### ### # # ### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
####### ### ### # # ##### # # ### # # ### ##### ########### # ### ####### ####### # # ### # # # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ### ## ##### ###### ## # ##### ### ### ##### ### ############# # ### # ##### ####### ### ##### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # ### ## ###### # # # #### ### ### # # # ####### # ##### # ### # ####### ### ### ### ### ######
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ### # # ##### # ###### #### # # ### # # # # ### # # # ######### # ### ### # # ## ## # ### # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # ### ### # ##### # ## # # # ### ##### # # # # # # # ### #### # ### # # ####### # # # ### # ####
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ### ### ### # ### # ####### # ### # # ##### # ### # ### # ##### ### ### # ##### # ### # ### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ##### ### # # ### # # # #### ## # # # ### # # ### # ### ### ### # # # # # ####### ######### # ####
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # # # # ##### # # ### # ### # # ### # ### # # # ### ### ############# # ### # ######### # ### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ### # # # # # ##### ### # # # # # # ##### # # # ##### # ##### # # ## # ### # # # ### ##### ####
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
### ##### ### ### # # # ### # ### # # ### # ### # # # # ### ### # # # ### ####### ## ## ### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # # # ## ### # ##### # # ### # # ##### # ### ### # # ### ### ##### ### # ##### ## ### ####### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ####### ### ### # ####### ####### # # ### # # ####### ### ### # # # ##### ##### ### ### # # ####
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # ####### ####### ### # ### ### # # # ##### ########## # # # ####### # # ######### # # ### # # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # # # # ##### # ### ##### ### ##### # ##### ### # # # ### # ### # ### # # #### ## ### ### # # # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # # ##### ### ####### ##### ### # ### ## ### # # # ####### # # # # # ##### ##### # ### # ##### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
##### # # ### ### # # # ##### # # # ### # # # # ##### ### # ### # # # # ##### # ### # ### # # # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # ### # # ##### # ############ # ##### # #### ## # ##### # # ######### # ####### ## # # # # # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ##### # ##### # ### ### # # ##### # ############### # # ### ######### # ### # ##### ### # ##### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # # # ### # # # # ## ### ##### # ### ## ######## ### ########## # # ### # # ####### ### ##### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ### # # # ### ##### ##### # # # ############### ######### ### # # ################ # # ### ######
|
||||||
|
# # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # # ### ### ######### # # # ####### ### #### # ### ##### ######### # # # ##### # ##### # ########
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
### # # # ##### # # # # # # # ### # # ### # ### # ## # ## # ####### ######### ##### # # # ### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ##### ##### # # ### ### ### # ##### # # # ### # ############ ## ######### ### # ### ### # # # # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # ##### # # ##### # ### # #### ### # ######### ### # # ##### # ### ### # ### ### #### ## # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ##### ### #### # # ########### ### # # # # # # # ### # # # # # # ### # ### ##### ### # ### # # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # # # # ### # ### # # ####### #### ######### ####### ### ####### # # ####### ### ### # ##### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # ##### ##### # ####### ### ################# # # ### # # ### # # ### # # ### # ######### ##### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
### # ### # # ##### # # # # ### ### # ##### ####### ### ### # # ### ####### ####### ### ##########
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ######### # ##### ### ############# # ####### ##### ### ### # # ### # ### ##### # # ### ### # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # # # # # ##### ##### # ######### # ### ### ### # ####### # # ### # ####### ##### ### # ### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ### # # # ##### # ###### #### # ##### # ### # # ### ######### ### ####### # ### ### ### ####### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # ########### ### # ##### # # # # # ### # ### ### ### ##### ### ##### # ####### # ###### # # ####
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# # # ###### # ### # # ########### ## ### ##### # # # # # # # # # ########### ### ######### ### ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
# ### ### # ### # ### # # ### # # ### # ### # ### # ##### # # # # ### # # ###### # ### # # ### # ##
|
||||||
|
# # # # # # # # # # # # # # # # # # # # # # # # # # # ##
|
||||||
|
### # # ##### ##### ### # # ####### ##### # # # ########### ######### ### # # ### ##### # # # # ##
|
||||||
|
# # # # # # # # E##
|
||||||
|
####################################################################################################
|
||||||
|
####################################################################################################
|
||||||
50
SolovevDS/docs/data/data_for_task2/maze50.txt
Normal file
50
SolovevDS/docs/data/data_for_task2/maze50.txt
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
##################################################
|
||||||
|
#S # # # # # ##
|
||||||
|
##### ##### ### ######### ### ### # ### # ### # ##
|
||||||
|
# # # # # # # # # # # # ##
|
||||||
|
### ######### ############# ### # # # ##### ### ##
|
||||||
|
# # # # # # # # # # ##
|
||||||
|
# ########### # ### # # ##### # ##### # ### # ##
|
||||||
|
# # # # # # # # # # # ##
|
||||||
|
### # # ### ### # ### # ######### # ####### ### ##
|
||||||
|
# # # # # # # # # # ##
|
||||||
|
# ##### # ### ##### # ##### ##### ########### ####
|
||||||
|
# # # # # # # # # # ##
|
||||||
|
##### # ### ##### # ########### ##### ##### ### ##
|
||||||
|
# # # # # # # # # # ##
|
||||||
|
# ####### # ####### # ####### ### # ### # ### # ##
|
||||||
|
# # # # # # # # # # # # ##
|
||||||
|
# # # # ################### # # ### # # # ### # ##
|
||||||
|
# # # # # # # # # # # # # ##
|
||||||
|
### # ### ### # # ########### ### # # # ### ### ##
|
||||||
|
# # # # # # # # # # # # # # ##
|
||||||
|
# ##### ### ######### ##### ### # ### # # ### # ##
|
||||||
|
# # # # # # # # # # # # # ##
|
||||||
|
# # # ####### ### ### # ### # # ### # # # # # ####
|
||||||
|
# # # # # # # # # # # # # # ##
|
||||||
|
# # ########### ####### # ### # # ######### ### ##
|
||||||
|
# # # # # # # # ##
|
||||||
|
# ### ####### # ##### ##### # ####### ### ### ####
|
||||||
|
# # # # # # # # # # # # ##
|
||||||
|
# ######### ####### # # # # ### # ####### # ### ##
|
||||||
|
# # # # # # # # # # # # ##
|
||||||
|
### # ### ##### ####### # # # # ### # # ####### ##
|
||||||
|
# # # # # # # # # # # # # # ##
|
||||||
|
# # # # ### # ####### # # # ##### # # ### ### # ##
|
||||||
|
# # # # # # # # # # # # # # # # ##
|
||||||
|
# # # ######### # # # ### ### ### ### # ### # # ##
|
||||||
|
# # # # # # # # # # # # # ##
|
||||||
|
# ### # ####### # ######### # ####### ### # ### ##
|
||||||
|
# # # # # # # # # # # # # ##
|
||||||
|
# ##### # # # ##### # # ####### ### # # ### # ####
|
||||||
|
# # # # # # # # # # # # # # ##
|
||||||
|
##### ### # # # ##### ########### # # # # # ### ##
|
||||||
|
# # # # # # # # # # # ##
|
||||||
|
# ############# # ### ##### ##### # ### # ##### ##
|
||||||
|
# # # # # # # # # # # ##
|
||||||
|
# # ####### ### # # ### # ### ### ### # ##### # ##
|
||||||
|
# # # # # # # # # # # # # ##
|
||||||
|
# ##### ##### ### # # ##### ### ### ##### ##### ##
|
||||||
|
# # # # # # E##
|
||||||
|
##################################################
|
||||||
|
##################################################
|
||||||
50
SolovevDS/docs/data/data_for_task2/maze_empty.txt
Normal file
50
SolovevDS/docs/data/data_for_task2/maze_empty.txt
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
S
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
E
|
||||||
10
SolovevDS/docs/data/data_for_task2/maze_no_path.txt
Normal file
10
SolovevDS/docs/data/data_for_task2/maze_no_path.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
##########
|
||||||
|
#S #
|
||||||
|
# ###### #
|
||||||
|
# # # #
|
||||||
|
# # ## # #
|
||||||
|
# # ## # #
|
||||||
|
# # # #
|
||||||
|
# ########
|
||||||
|
# #E#
|
||||||
|
##########
|
||||||
1536
SolovevDS/docs/data/data_for_task2/path_length_comparison.svg
Normal file
1536
SolovevDS/docs/data/data_for_task2/path_length_comparison.svg
Normal file
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 38 KiB |
16
SolovevDS/docs/data/data_for_task2/results.csv
Normal file
16
SolovevDS/docs/data/data_for_task2/results.csv
Normal file
|
|
@ -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
|
||||||
|
934
SolovevDS/docs/data/data_for_task2/task2.cpp
Normal file
934
SolovevDS/docs/data/data_for_task2/task2.cpp
Normal file
|
|
@ -0,0 +1,934 @@
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <stdexcept> /*для ошибок*/
|
||||||
|
#include <cmath>
|
||||||
|
#include <chrono> /*мерит время*/
|
||||||
|
#include <cstdlib> /*волшебная отрисовка*/
|
||||||
|
#include <iomanip>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <clocale>
|
||||||
|
|
||||||
|
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<double, std::milli> 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;
|
||||||
|
}
|
||||||
1582
SolovevDS/docs/data/data_for_task2/time_comparison.svg
Normal file
1582
SolovevDS/docs/data/data_for_task2/time_comparison.svg
Normal file
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 41 KiB |
1530
SolovevDS/docs/data/data_for_task2/visited_cells_comparison.svg
Normal file
1530
SolovevDS/docs/data/data_for_task2/visited_cells_comparison.svg
Normal file
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 39 KiB |
BIN
SolovevDS/docs/laba_2_report.pdf
Normal file
BIN
SolovevDS/docs/laba_2_report.pdf
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user