Генерация лабиринта. Python / Отчет по курсовой за 3 семестр
.docxМИНОБРНАУКИ РОССИИ
САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ
ЭЛЕКТРОТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
«ЛЭТИ» ИМ. В.И. УЛЬЯНОВА (ЛЕНИНА)
Кафедра автоматики и процессов управления
ОТЧЕТ
по курсовой работе
по дисциплине «Программирование»
Тема: Генерация лабиринтов
Студентка гр. 5371 |
|
Локкина О.С. |
Преподаватель |
|
Жеронкин К.М. |
Санкт-Петербург
2016
Оглавление
1.Задание курсовой работы 2
2.Описание алгоритма генерации 3
3.Сущность данных 3
4.Интерфейс программы 4
5.Исходный код программы 5
6.Дальнейшее развитие 7
-
Задание курсовой работы
Задание курсовой работы состоит в создании работающего алгоритма генерации лабиринтов.
-
Описание алгоритма генерации
Изначально лабиринт задается в виде решетки, т.е. сначала все ячейки имеют стенки.
Ячейки задаются как массив, в котором на первых двух позициях стоят координаты клетки, а последнее значение определяет является ли ячейка посещенной (1) или нет (0 – по умолчанию).
Стены описываются одним целым числом: 1 означает, что стена существует; 0 – нет.
Так как ячейки и стены задаются отдельными объектами, то при условии, что желаемая размерность лабиринта составляет w0 единиц по ширине и h0 – по высоте, исходный размер используемой матрицы будет составлять 2w0+1 на 2h0+1 кв. единиц.
Также необходимо создать стэк, в котором будет хранится цепь из посещенных клеток.
В самом начале случайно выбирается ячейка, находящаяся в первом столбце лабиринта, и помещается в стек. От нее пойдет генерироваться лабиринт. Слева от этой ячейки убирается стена для обозначения входа.
Далее с помощью функции getNeighbours, описанной ниже, и функции randint, находящейся в библиотеке random, из непосещённых соседей клетки случайно берется один сосед, который добавляется в стэк и становится исходной клеткой. Между ячейкой и ее выбранным соседом убирается стенка с помощью функции removeWall.
В случае, когда у клетки нет непосещенных соседей, из стэка выкидывается одна ячейка, а для следующей идущей в стэке также происходит проверка на соседей и так далее до тех пор, пока количество непосещенных клеток не станет равным нулю.
В самом конце программы из крайнего правого столбца лабиринта случайно определяется ячейка, справа от которой убирается стенка для обозначения выхода.
Использование стэка гарантирует единственность пути.
-
Сущность данных
Код был написан на языке Python из-за простоты использования в нем динамической памяти.
Для работы генератора случайных чисел была импортирована библиотека random. Использован модуль turtle (черепашка) для отрисовки получившегося лабиринта.
В программе используется 4 функции:
-
getNeighbours для получения списка непосещенных соседей исходной ячейки.
-
removeWall для удаления стены между двумя ячейками лабиринта
-
drawturtle для отрисовки лабиринта с помощью черепашки
-
drawconsole для вывода лабиринта в консоль
Ниже приведены коды этих функций:
def getNeighbours(mh,mw,cell,m):
res=[]
x=cell[0]
y=cell[1]
if (y+2)<mw and m[x][y+2][-1]!=1: #right
res.append(m[x][y+2])
if (x+2)<mh and m[x+2][y][-1]!=1: #down
res.append(m[x+2][y])
if (y-2)>0 and m[x][y-2][-1]!=1: #left
res.append(m[x][y-2])
if (x-2)>0 and m[x-2][y][-1]!=1: #up
res.append(m[x-2][y])
return res
def removeWall(cf,cs,m):
x=(cf[0]-cs[0])//2
y=(cf[1]-cs[1])//2
m[cs[0]+x][cs[1]+y]=0
def drawturtle(m,mh,mw,d,a):
hideturtle()
pensize(5)
speed(0)
for i in range(mh):
if(not i%2):
penup()
setposition(0-a,-d*i+a)
seth(0)
pendown()
for k in range(len(m[i][:-1])):
if(m[i][k] and m[i][k+1]):
forward(d)
else:
penup()
forward(d)
pendown()
else:
for t in range(0,mw,2):
if(m[i][t]):
penup()
setposition(d*t-a,-d*(i-1)+a)
pendown()
seth(270)
forward(2*d)
def drawconsole(m,mh):
for i in range(mh):
if(i%2==0):
t=['■■' if x else ' ' for x in m[i]]
print(''.join(x for x in t))
else:
t=['■■ ' if x else ' ' for x in m[i][::2]]
print(''.join(x for x in t))
-
Интерфейс программы
Приведены два варианта вывода лабиринта:
Консоль
Черепашка
-
Исходный код программы
from turtle import *
import random
def getNeighbours(mh,mw,cell,m):
res=[]
x=cell[0]
y=cell[1]
if (y+2)<mw and m[x][y+2][-1]!=1: #right
res.append(m[x][y+2])
if (x+2)<mh and m[x+2][y][-1]!=1: #down
res.append(m[x+2][y])
if (y-2)>0 and m[x][y-2][-1]!=1: #left
res.append(m[x][y-2])
if (x-2)>0 and m[x-2][y][-1]!=1: #up
res.append(m[x-2][y])
return res
def removeWall(cf,cs,m):
x=(cf[0]-cs[0])//2
y=(cf[1]-cs[1])//2
m[cs[0]+x][cs[1]+y]=0
def drawturtle(m,mh,mw,d,a):
hideturtle()
pensize(5)
speed(0)
for i in range(mh):
if(not i%2):
penup()
setposition(0-a,-d*i+a)
seth(0)
pendown()
for k in range(len(m[i][:-1])):
if(m[i][k] and m[i][k+1]):
forward(d)
else:
penup()
forward(d)
pendown()
else:
for t in range(0,mw,2):
if(m[i][t]):
penup()
setposition(d*t-a,-d*(i-1)+a)
pendown()
seth(270)
forward(2*d)
def drawconsole(m,mh):
for i in range(mh):
if(i%2==0):
t=['■■' if x else ' ' for x in m[i]]
print(''.join(x for x in t))
else:
t=['■■ ' if x else ' ' for x in m[i][::2]]
print(''.join(x for x in t))
w0,h0=map(int, input("Vvedite razmernost labirinta: w,h\n>>>").strip().split(" "))
flag=int(input("\nVivesti cherez:\n1.Console;\n2.Turtle.\n>>>"))
w=2*w0+1
h=2*h0+1
maze=[]
stackcurr=[] #Цепочка посещенных клеток
unvisitedcells=w0*h0 #Количество непосещенных клеток
for i in range(h):
maze.append([])
if (i%2==0):
maze[i].extend([int(x) for x in '1'*w])
else:
for j in range(w):
if(j%2==0):
maze[i].append(1) #Стена
else:
maze[i].append([i,j,0]) #Непосещенная клетка
startcell=random.randrange(1,h,2)
currentcell=maze[startcell][1]
maze[startcell][0]=0
currentcell[-1]=1
unvisitedcells-=1
stackcurr.append(currentcell)
while (unvisitedcells):
neigh=getNeighbours(h,w,currentcell,maze)
if (neigh):
randnum=random.randint(0,len(neigh)-1)
neighbourcell=neigh[randnum]
neighbourcell[-1]=1
unvisitedcells-=1
removeWall(neighbourcell,currentcell,maze)
currentcell=neighbourcell
stackcurr.append(neighbourcell)
else:
stackcurr.pop()
currentcell=stackcurr[-1]
endcell=random.randrange(1,h,2)
maze[endcell][-1]=0
if (flag==1):
drawconsole(maze,h)
elif(flag==2):
drawturtle(maze,h,w,15,400)
-
Дальнейшее развитие
В планах модифицировать программу для решения таких задач, как:
-
Проверка данных, веденных пользователем;
-
Поиск выхода в лабиринте;
-
Использование более быстрых и менее емких алгоритмов (алгоритм Эллера и др.);
-
Вывод лабиринта в более интерактивную форму.