maze_python/maze_generator.py
2025-06-26 20:15:59 +08:00

256 lines
9.8 KiB
Python

import random
import csv
import os
class MazeGenerator:
def __init__(self, size, filename, name="Default Maze"):
# 迷宫基础元素
self.ROUTE = '0'
self.WALL = '1'
# 特殊元素
self.BOSS = 'b'
self.START = 's'
self.END = 'e'
self.TRAP = 't'
self.MECHANISM = 'l'
self.GOLD = 'g'
self.size = size
self.maze = []
self.filename = filename
self.name = name # 迷宫名称
self.special_elements = [] # 存储特殊元素的位置和值
def initialize_maze(self):
"""初始化迷宫,四周设置为墙"""
self.maze = [[self.ROUTE for _ in range(self.size)] for _ in range(self.size)]
for i in range(self.size):
self.maze[0][i] = self.WALL
self.maze[i][0] = self.WALL
self.maze[self.size - 1][i] = self.WALL
self.maze[i][self.size - 1] = self.WALL
def create_maze(self, x1, y1, x2, y2):
"""递归分割法生成迷宫"""
if x2 - x1 < 2 or y2 - y1 < 2:
return
x = x1 + 1 + random.randint(0, (x2 - x1 - 2))
y = y1 + 1 + random.randint(0, (y2 - y1 - 2))
# 画墙
for i in range(x1, x2 + 1):
self.maze[i][y] = self.WALL
for i in range(y1, y2 + 1):
self.maze[x][i] = self.WALL
# 递归分割四个区域
self.create_maze(x1, y1, x - 1, y - 1)
self.create_maze(x + 1, y + 1, x2, y2)
self.create_maze(x + 1, y1, x2, y - 1)
self.create_maze(x1, y + 1, x - 1, y2)
# 随机打通三面墙
r = [0, 0, 0, 0]
r[random.randint(0, 3)] = 1
for i in range(4):
if r[i] == 0:
rx, ry = x, y
if i == 0: # 上方
while True:
rx = x1 + random.randint(0, (x - x1 - 1))
wall_count = sum([
(int)(self.maze[rx - 1][ry]), (int)(self.maze[rx + 1][ry]),
(int)(self.maze[rx][ry - 1]), (int)(self.maze[rx][ry + 1])
])
if wall_count <= 2 * (int)(self.WALL):
break
elif i == 1: # 右侧
while True:
ry = y + 1 + random.randint(0, (y2 - y - 1))
wall_count = sum([
(int)(self.maze[rx - 1][ry]), (int)(self.maze[rx + 1][ry]),
(int)(self.maze[rx][ry - 1]), (int)(self.maze[rx][ry + 1])
])
if wall_count <= 2 * (int)(self.WALL):
break
elif i == 2: # 下方
while True:
rx = x + 1 + random.randint(0, (x2 - x - 1))
wall_count = sum([
(int)(self.maze[rx - 1][ry]), (int)(self.maze[rx + 1][ry]),
(int)(self.maze[rx][ry - 1]), (int)(self.maze[rx][ry + 1])
])
if wall_count <= 2 * (int)(self.WALL):
break
elif i == 3: # 左侧
while True:
ry = y1 + random.randint(0, (y - y1 - 1))
wall_count = sum([
(int)(self.maze[rx - 1][ry]), (int)(self.maze[rx + 1][ry]),
(int)(self.maze[rx][ry - 1]), (int)(self.maze[rx][ry + 1])
])
if wall_count <= 2 * (int)(self.WALL):
break
self.maze[rx][ry] = self.ROUTE
def set_random_exits(self):
"""随机设置迷宫入口和出口"""
available = self.get_available_cells()
if len(available) < 2:
raise ValueError("迷宫空间不足,无法设置随机出入口")
start, end = random.sample(available, 2)
self.maze[start[0]][start[1]] = self.START
self.maze[end[0]][end[1]] = self.END
self.special_elements.extend([(start[0], start[1], self.START), (end[0], end[1], self.END)])
def get_available_cells(self):
"""获取所有可通行单元格"""
cells = []
for i in range(1, self.size - 1):
for j in range(1, self.size - 1):
if self.maze[i][j] == self.ROUTE:
cells.append((i, j))
return cells
def place_special_elements(self, boss_count=1, traps_range=(3, 8),
mechanisms_range=(2, 6), skill_traps=5,gold_range=(3,8)):
"""放置特殊元素(支持技能触发陷阱)"""
available = self.get_available_cells()
random.shuffle(available)
# 计算所需单元格数量
required = 2 + boss_count + random.randint(*traps_range) + random.randint(*mechanisms_range) + skill_traps + random.randint(*gold_range)
if len(available) < required:
raise ValueError(f"空间不足,需要{required}个单元格,实际可用{len(available)}")
# 放置出入口
start, end = available.pop(), available.pop()
self.special_elements.extend([(start[0], start[1], self.START), (end[0], end[1], self.END)])
self.maze[start[0]][start[1]] = self.START
self.maze[end[0]][end[1]] = self.END
# 放置BOSS
for _ in range(boss_count):
pos = available.pop()
val = random.randint(50, 100)
self.special_elements.append((pos[0], pos[1], f"{self.BOSS}{val}"))
self.maze[pos[0]][pos[1]] = f"{self.BOSS}{val}"
# 放置普通陷阱
traps = random.randint(*traps_range)
for _ in range(traps):
pos = available.pop()
val = random.randint(5, 20)
self.special_elements.append((pos[0], pos[1], f"{self.TRAP}{val}"))
self.maze[pos[0]][pos[1]] = f"{self.TRAP}{val}"
# 放置机关
mechanisms = random.randint(*mechanisms_range)
for _ in range(mechanisms):
pos = available.pop()
val = random.randint(10, 30)
self.special_elements.append((pos[0], pos[1], f"{self.MECHANISM}{val}"))
self.maze[pos[0]][pos[1]] = f"{self.MECHANISM}{val}"
# 放置金币
mechanisms = random.randint(*gold_range)
for _ in range(mechanisms):
pos = available.pop()
val = random.randint(10, 30)
self.special_elements.append((pos[0], pos[1], f"{self.GOLD}{val}"))
self.maze[pos[0]][pos[1]] = f"{self.GOLD}{val}"
def generate(self, seed=None, boss_count=1, traps_range=(3, 8),
mechanisms_range=(2, 6), skill_traps=5):
"""生成迷宫主方法"""
random.seed(seed or random.randint(0, 1000))
self.initialize_maze()
self.create_maze(1, 1, self.size - 2, self.size - 2)
self.place_special_elements(boss_count, traps_range, mechanisms_range, skill_traps)
print(f"成功生成迷宫: {self.name}")
def export_to_csv(self, filename):
"""导出迷宫到CSV文件"""
try:
with open(filename, 'w', newline='') as f:
writer = csv.writer(f)
for row in self.maze:
writer.writerow(row)
print(f"迷宫已导出至: {os.path.abspath(filename)}")
except Exception as e:
print(f"导出失败: {str(e)}")
def read_from_csv(self):
"""从CSV读取迷宫数据"""
try:
with open(self.filename, 'r', newline='') as f:
reader = csv.reader(f)
self.maze = [list(map(self._parse_element, row)) for row in reader]
self.size = len(self.maze)
print(f"成功从{os.path.abspath(self.filename)}读取迷宫")
return True
except Exception as e:
print(f"读取失败: {str(e)}")
return False
def _parse_element(self, elem):
"""解析CSV中的元素类型"""
if elem == 's': return self.START
if elem == 'e': return self.END
if elem.startswith('b'): return self.BOSS
if elem.startswith('t'): return self.TRAP
if elem.startswith('l'): return self.MECHANISM
if elem.startswith('g'): return self.GOLD
return int(elem)
def print_maze(self):
"""打印迷宫到控制台(带元素标识)"""
symbols = {
self.WALL: '', self.ROUTE: '·', self.START: 'S',
self.END: 'E', self.BOSS: 'B', self.TRAP: 'T',
self.GOLD: 'G','|':'|','-':'',
}
for row in self.maze:
display = []
for cell in row:
symbol = symbols.get(((str)(cell))[0], ((str)(cell))[0])
display.append(str(symbol))
print(' '.join(display))
def read_csv(self):
l = []
with open(f'{self.filename}', 'r', newline='') as f:
reader = csv.reader(f)
for row in reader:
l.append(row)
return l
def main():
# 示例1: 生成带技能陷阱的迷宫
generator = MazeGenerator(
size=20,
filename="dungeon_maze.csv",
name="龙脊峡谷迷宫"
)
generator.generate(
seed=666,
boss_count=2,
traps_range=(5, 10),
mechanisms_range=(3, 7),
skill_traps=8
)
generator.print_maze()
generator.export_to_csv()
reader = MazeGenerator(size=1, filename="dungeon_maze.csv")
if reader.read_from_csv():
print("\n读取的迷宫:")
reader.print_maze()
if __name__ == "__main__":
main()