forked from UNN/2026-rff_mp
lab_2 builder, BFS, DFS
This commit is contained in:
parent
f62aa21088
commit
3d7c072106
228
GutovVM/docs/data/lab_2_data/main.py
Normal file
228
GutovVM/docs/data/lab_2_data/main.py
Normal file
|
|
@ -0,0 +1,228 @@
|
||||||
|
import numpy as np
|
||||||
|
import abc
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
|
#Классы клетки и лабиринта
|
||||||
|
|
||||||
|
class Cell:
|
||||||
|
|
||||||
|
def __init__(self, coords, isWall = False, isStart = False,
|
||||||
|
isExit = False):
|
||||||
|
self.coords = coords
|
||||||
|
self.isWall = isWall
|
||||||
|
self.isStart = isStart
|
||||||
|
self.isExit = isExit
|
||||||
|
|
||||||
|
def isPassable(self):
|
||||||
|
if self.isWall:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
class Maze:
|
||||||
|
|
||||||
|
def __init__(self, cells, width, height, st, ex):
|
||||||
|
self.cells = cells
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
self.st = st
|
||||||
|
self.ex = ex
|
||||||
|
|
||||||
|
def getCell(self,x,y):
|
||||||
|
try:
|
||||||
|
return self.cells[x][y]
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def getNeighbors(self,cell):
|
||||||
|
x,y = cell.coords
|
||||||
|
res = []
|
||||||
|
for i,j in (x,y+1),(x,y-1),(x-1,y),(x+1,y):
|
||||||
|
cellij = self.getCell(i,j)
|
||||||
|
if i <= self.width-1 and j <= self.height-1 and 0 <= i and 0 <= j and cellij is not None:
|
||||||
|
if cellij.isPassable():
|
||||||
|
res.append(cellij)
|
||||||
|
else:
|
||||||
|
res.append(None)
|
||||||
|
else:
|
||||||
|
res.append(None)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
#Тестирование классов клетки и лабиринта
|
||||||
|
|
||||||
|
cell1 = Cell((1,2), isExit = True, isWall = True, isStart = False)
|
||||||
|
|
||||||
|
print(cell1.isPassable())
|
||||||
|
print(cell1.isStart)
|
||||||
|
print(cell1.coords)
|
||||||
|
|
||||||
|
width, height = 3,3
|
||||||
|
|
||||||
|
cells = np.full((width,height), None, dtype=object)
|
||||||
|
|
||||||
|
for x in range(width):
|
||||||
|
for y in range(height):
|
||||||
|
if x != 0 and x != width-1 and y != 0 and y != height-1:
|
||||||
|
cells[x][y] = Cell((x,y), isWall = False)
|
||||||
|
else:
|
||||||
|
cells[x][y] = Cell((x,y), isWall = True)
|
||||||
|
|
||||||
|
print(cells)
|
||||||
|
|
||||||
|
maze1 = Maze(cells, width, height, cells[0], cells[-1])
|
||||||
|
|
||||||
|
for column in cells:
|
||||||
|
for cell in column:
|
||||||
|
print(cell.coords)
|
||||||
|
print(maze1.getNeighbors(cell))
|
||||||
|
|
||||||
|
print('\n')
|
||||||
|
|
||||||
|
#Интерфейс постройки лабиринта
|
||||||
|
|
||||||
|
class MazeBuilder(abc.ABC):
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def buildFromFile(filename): pass
|
||||||
|
|
||||||
|
#Наследуем от него класс постройки из текстового файла
|
||||||
|
|
||||||
|
class TextFileMazeBuilder(MazeBuilder):
|
||||||
|
|
||||||
|
def buildFromFile(filename):
|
||||||
|
with open(filename, "r") as file:
|
||||||
|
|
||||||
|
rows = file.read().splitlines()
|
||||||
|
|
||||||
|
print(rows)
|
||||||
|
|
||||||
|
width = 0
|
||||||
|
height = 0
|
||||||
|
for row in rows:
|
||||||
|
height += 1
|
||||||
|
if len(row) > width:
|
||||||
|
width = len(row)
|
||||||
|
|
||||||
|
print(width, height)
|
||||||
|
|
||||||
|
st = (0,0)
|
||||||
|
ex = (width,height)
|
||||||
|
|
||||||
|
cells = np.full((width,height), None, dtype=object)
|
||||||
|
|
||||||
|
for y in range(height):
|
||||||
|
for x in range(width):
|
||||||
|
isWall = False
|
||||||
|
isStart = False
|
||||||
|
isExit = False
|
||||||
|
|
||||||
|
if rows[-(y+1)][x] == '#':
|
||||||
|
isWall = True
|
||||||
|
elif rows[-(y+1)][x] == 'S':
|
||||||
|
isStart = True
|
||||||
|
st = (x,y)
|
||||||
|
print('Старт в',x,y)
|
||||||
|
elif rows[-(y+1)][x] == 'E':
|
||||||
|
isExit = True
|
||||||
|
ex = (x,y)
|
||||||
|
print('Выход в',x,y)
|
||||||
|
elif rows[-(y+1)][x] != ' ':
|
||||||
|
raise ValueError("Неверный формат лабиринта! Пожалуйста, используйте только символы #,S,E и пробелы")
|
||||||
|
|
||||||
|
cells[x][y] = Cell((x,y), isWall, isStart, isExit)
|
||||||
|
|
||||||
|
return Maze(cells, width, height, cells[st[0]][st[1]], cells[ex[0]][ex[1]])
|
||||||
|
|
||||||
|
|
||||||
|
builder = TextFileMazeBuilder
|
||||||
|
|
||||||
|
maze = builder.buildFromFile('maze1.txt')
|
||||||
|
|
||||||
|
print(maze)
|
||||||
|
|
||||||
|
|
||||||
|
#Интерфейс поиска пути
|
||||||
|
|
||||||
|
class PathFindingStrategy(abc.ABC):
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def findPath(maze, st, ex): pass
|
||||||
|
|
||||||
|
#Поиск в глубину
|
||||||
|
|
||||||
|
class DFS(PathFindingStrategy):
|
||||||
|
|
||||||
|
def findPath(maze,st,ex):
|
||||||
|
|
||||||
|
stack = [st]
|
||||||
|
|
||||||
|
visited = {st.coords} #по координатам надёжнее, а то вдруг адрес изменится
|
||||||
|
|
||||||
|
pathmap = {}
|
||||||
|
|
||||||
|
while stack:
|
||||||
|
cell = stack.pop()
|
||||||
|
|
||||||
|
if cell == ex:
|
||||||
|
|
||||||
|
#маршрут выстраивается в обратном порядке и разворачивается
|
||||||
|
path = []
|
||||||
|
while cell.coords != st.coords:
|
||||||
|
path.append(cell)
|
||||||
|
cell = pathmap[cell.coords]
|
||||||
|
path.append(st)
|
||||||
|
path = path[::-1]
|
||||||
|
return path
|
||||||
|
|
||||||
|
for n in maze.getNeighbors(cell):
|
||||||
|
if n != None and n.coords not in visited:
|
||||||
|
visited.add(n.coords)
|
||||||
|
pathmap[n.coords] = cell
|
||||||
|
stack.append(n)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
path = DFS.findPath(maze,maze.st,maze.ex)
|
||||||
|
|
||||||
|
print('путь поиском в глубину:')
|
||||||
|
for cell in path:
|
||||||
|
print(cell.coords)
|
||||||
|
|
||||||
|
|
||||||
|
class BFS(PathFindingStrategy):
|
||||||
|
|
||||||
|
def findPath(maze,st,ex):
|
||||||
|
|
||||||
|
queue = deque([st])
|
||||||
|
|
||||||
|
visited = {st.coords} #по координатам надёжнее, а то вдруг адрес изменится
|
||||||
|
|
||||||
|
pathmap = {}
|
||||||
|
|
||||||
|
while queue:
|
||||||
|
cell = queue.popleft()
|
||||||
|
|
||||||
|
if cell == ex:
|
||||||
|
|
||||||
|
#маршрут выстраивается в обратном порядке и разворачивается
|
||||||
|
path = []
|
||||||
|
while cell.coords != st.coords:
|
||||||
|
path.append(cell)
|
||||||
|
cell = pathmap[cell.coords]
|
||||||
|
path.append(st)
|
||||||
|
path = path[::-1]
|
||||||
|
return path
|
||||||
|
|
||||||
|
for n in maze.getNeighbors(cell):
|
||||||
|
if n != None and n.coords not in visited:
|
||||||
|
visited.add(n.coords)
|
||||||
|
pathmap[n.coords] = cell
|
||||||
|
queue.append(n)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
path = BFS.findPath(maze,maze.st,maze.ex)
|
||||||
|
|
||||||
|
print('путь поиском в ширину:')
|
||||||
|
for cell in path:
|
||||||
|
print(cell.coords)
|
||||||
6
GutovVM/docs/data/lab_2_data/maze1.txt
Normal file
6
GutovVM/docs/data/lab_2_data/maze1.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
## ####S# ##
|
||||||
|
# ## # ##
|
||||||
|
## # # # #
|
||||||
|
# ### #
|
||||||
|
# ## ## E
|
||||||
|
# ##### ######
|
||||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user