generate mazes
This commit is contained in:
parent
2f980aaa77
commit
313fe75c36
146
SobolevNS/docs/data/task2_maze/generate_mazes.py
Normal file
146
SobolevNS/docs/data/task2_maze/generate_mazes.py
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
"""
|
||||
generate_mazes.py - генерирует тестовые лабиринты в mazes/.
|
||||
|
||||
Состав:
|
||||
small_10x10.txt - маленький с простым путём
|
||||
medium_50x50.txt - средний с тупиками (DFS-генератор)
|
||||
large_100x100.txt - большой запутанный (DFS-генератор)
|
||||
empty_30x30.txt - без стен внутри (только периметр)
|
||||
nopath_15x15.txt - без пути от S до E (выход замурован)
|
||||
weighted_30x30.txt - со взвешенными клетками (асфальт/песок/болото)
|
||||
"""
|
||||
|
||||
import os
|
||||
import random
|
||||
|
||||
random.seed(2024)
|
||||
|
||||
MAZES_DIR = "mazes"
|
||||
os.makedirs(MAZES_DIR, exist_ok=True)
|
||||
|
||||
|
||||
def write(name, lines):
|
||||
path = os.path.join(MAZES_DIR, name)
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(lines) + "\n")
|
||||
print("written:", path, f"({len(lines)} строк, ширина {len(lines[0])})")
|
||||
|
||||
|
||||
def make_small():
|
||||
"""Маленький лабиринт 10x10, ручной."""
|
||||
raw = [
|
||||
"##########",
|
||||
"#S #",
|
||||
"# ###### #",
|
||||
"# # #",
|
||||
"###### # #",
|
||||
"# # # #",
|
||||
"# ## # # #",
|
||||
"# # # #",
|
||||
"# ##### E",
|
||||
"##########",
|
||||
]
|
||||
write("small_10x10.txt", raw)
|
||||
|
||||
|
||||
def _carve_perfect_maze(w, h, rng):
|
||||
"""Генератор «идеального» лабиринта DFS (recursive backtracker),
|
||||
итеративный - чтобы не упасть в RecursionError на больших размерах."""
|
||||
grid = [['#'] * w for _ in range(h)]
|
||||
grid[1][1] = ' '
|
||||
stack = [(1, 1)]
|
||||
while stack:
|
||||
x, y = stack[-1]
|
||||
dirs = [(0, -2), (0, 2), (-2, 0), (2, 0)]
|
||||
rng.shuffle(dirs)
|
||||
carved = False
|
||||
for dx, dy in dirs:
|
||||
nx, ny = x + dx, y + dy
|
||||
if 0 < nx < w - 1 and 0 < ny < h - 1 and grid[ny][nx] == '#':
|
||||
grid[y + dy // 2][x + dx // 2] = ' '
|
||||
grid[ny][nx] = ' '
|
||||
stack.append((nx, ny))
|
||||
carved = True
|
||||
break
|
||||
if not carved:
|
||||
stack.pop()
|
||||
return grid
|
||||
|
||||
|
||||
def make_with_generator(name, w, h):
|
||||
"""Создаёт перфектный лабиринт и расставляет S/E в противоположных углах."""
|
||||
rng = random.Random(hash(name) & 0xFFFF)
|
||||
grid = _carve_perfect_maze(w, h, rng)
|
||||
grid[1][1] = 'S'
|
||||
grid[h - 2][w - 2] = 'E'
|
||||
lines = ["".join(row) for row in grid]
|
||||
write(name, lines)
|
||||
|
||||
|
||||
def make_empty(name, w, h):
|
||||
"""Пустая комната - только периметр."""
|
||||
lines = []
|
||||
for y in range(h):
|
||||
if y == 0 or y == h - 1:
|
||||
lines.append('#' * w)
|
||||
else:
|
||||
lines.append('#' + ' ' * (w - 2) + '#')
|
||||
# старт в левом верхнем углу, выход в правом нижнем
|
||||
row = list(lines[1]); row[1] = 'S'; lines[1] = "".join(row)
|
||||
row = list(lines[h - 2]); row[w - 2] = 'E'; lines[h - 2] = "".join(row)
|
||||
write(name, lines)
|
||||
|
||||
|
||||
def make_nopath(name, w=15, h=15):
|
||||
"""Лабиринт, в котором выход замурован - пути нет."""
|
||||
lines = ['#' * w]
|
||||
for y in range(1, h - 1):
|
||||
lines.append('#' + ' ' * (w - 2) + '#')
|
||||
lines.append('#' * w)
|
||||
# S слева сверху
|
||||
row = list(lines[1]); row[1] = 'S'; lines[1] = "".join(row)
|
||||
# E в правой нижней клетке, но обнесён стенами с двух сторон
|
||||
# делаем «коробочку» 3x3 вокруг E с одним зазором, который мы тут же закроем
|
||||
ex, ey = w - 2, h - 2
|
||||
# сначала откроем коробочку из стен 1 клетка по периметру вокруг E
|
||||
# построим коробочку: на (ex-1, ey-1)..(ex+1, ey+1) поставим '#' кроме E
|
||||
for yy in range(ey - 1, ey + 2):
|
||||
for xx in range(ex - 1, ex + 2):
|
||||
if 0 <= xx < w and 0 <= yy < h and not (xx == ex and yy == ey):
|
||||
row = list(lines[yy]); row[xx] = '#'; lines[yy] = "".join(row)
|
||||
row = list(lines[ey]); row[ex] = 'E'; lines[ey] = "".join(row)
|
||||
write(name, lines)
|
||||
|
||||
|
||||
def make_weighted(name, w=30, h=30):
|
||||
"""Перфектный лабиринт + случайные взвешенные клетки на проходимых местах."""
|
||||
rng = random.Random(7)
|
||||
grid = _carve_perfect_maze(w | 1, h | 1, rng)
|
||||
# Перекрасим часть проходов в '.', ',' и '~'
|
||||
for y, row in enumerate(grid):
|
||||
for x, ch in enumerate(row):
|
||||
if ch == ' ':
|
||||
r = rng.random()
|
||||
if r < 0.65:
|
||||
grid[y][x] = ' ' # асфальт (1)
|
||||
elif r < 0.90:
|
||||
grid[y][x] = ',' # песок (2)
|
||||
else:
|
||||
grid[y][x] = '~' # болото (3)
|
||||
grid[1][1] = 'S'
|
||||
grid[len(grid) - 2][len(grid[0]) - 2] = 'E'
|
||||
lines = ["".join(row) for row in grid]
|
||||
write(name, lines)
|
||||
|
||||
|
||||
def main():
|
||||
make_small()
|
||||
make_with_generator("medium_51x51.txt", 51, 51)
|
||||
make_with_generator("large_101x101.txt", 101, 101)
|
||||
make_empty("empty_30x30.txt", 30, 30)
|
||||
make_nopath("nopath_15x15.txt", 15, 15)
|
||||
make_weighted("weighted_31x31.txt", 31, 31)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
19
SobolevNS/docs/data/task2_maze/generate_weighted_choice.py
Normal file
19
SobolevNS/docs/data/task2_maze/generate_weighted_choice.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
"""generate_weighted_choice.py - создаёт лабиринт, где Dijkstra/A* реально
|
||||
обходят 'болото' и находят более дешёвый путь, чем BFS."""
|
||||
W, H = 21, 13
|
||||
grid = [[' '] * W for _ in range(H)]
|
||||
# периметр
|
||||
for x in range(W):
|
||||
grid[0][x] = '#'; grid[H-1][x] = '#'
|
||||
for y in range(H):
|
||||
grid[y][0] = '#'; grid[y][W-1] = '#'
|
||||
# центральное болото 5х5 (вес 3)
|
||||
for y in range(4, 9):
|
||||
for x in range(8, 13):
|
||||
grid[y][x] = '~'
|
||||
# старт слева в центре, выход справа в центре
|
||||
grid[H//2][1] = 'S'
|
||||
grid[H//2][W-2] = 'E'
|
||||
with open('mazes/weighted_choice.txt','w') as f:
|
||||
f.write('\n'.join(''.join(row) for row in grid) + '\n')
|
||||
print(open('mazes/weighted_choice.txt').read())
|
||||
Loading…
Reference in New Issue
Block a user