实现路径生成

This commit is contained in:
Guanforever 2025-06-29 16:42:26 +08:00
parent c7f28e7f88
commit 198b6bd506
9 changed files with 936 additions and 787 deletions

6
.gitignore vendored
View File

@ -1,4 +1,4 @@
__pycache__/ __pycache__/
.venv/ .venv/
.idea/ .idea/
*.csv *.csv

View File

@ -1,142 +1,198 @@
import csv import csv
from collections import deque
class TreeNode:
def __init__(self): class TreeNode:
self.fa = None def __init__(self):
self.children = [] self.fa = None
self.pos = None self.children = []
self.val = 0 self.pos = None
self.id = 0 self.final_pos = None
self.dp = 0 self.val = 0
self.path = [] self.id = 0
self.dp_path = [] self.dp = 0
class SourceCollector: class SourceCollector:
def __init__(self, filename, maze=None): def __init__(self, filename=None, maze=None):
self.filename = filename self.filename = filename
self.maze = maze self.maze = maze
self.start_pos = None self.start_pos = None
self.end_pos = None self.end_pos = None
self.path = [] self.path = []
self.node_path = []
if self.filename: if self.filename:
self.maze = [] self.maze = []
with open(f"{self.filename}",'r') as f: with open(f"{self.filename}",'r') as f:
reader = csv.reader(f) reader = csv.reader(f)
for row in reader: for row in reader:
t = [] t = []
for i in row: for i in row:
if i.startswith('b') or i.startswith('l'): if i.startswith('b') or i.startswith('l'):
t.append('0') t.append('0')
else: else:
t.append(i) t.append(i)
self.maze.append(t) self.maze.append(t)
self.rowNums = len(self.maze) else:
self.colNums = len(self.maze[0]) self.maze = maze
self.rowNums = len(self.maze)
self.colNums = len(self.maze[0])
for i in range(self.rowNums):
for j in range(self.colNums):
if self.maze[i][j] =='s': for i in range(self.rowNums):
self.start_pos = (i,j) for j in range(self.colNums):
if self.maze[i][j] =='e': if self.maze[i][j] =='s':
self.end_pos = (i,j) self.start_pos = (i,j)
if self.maze[i][j] =='e':
def dfs_show(self,u): self.end_pos = (i,j)
if u.id != 0:
print(f"id: {u.id} , fa:{u.fa.id} , val:{u.val}") def dfs_show(self,u):
else: if u.id != 0:
print(f"id: {u.id} , val:{u.val}") print(f"id: {u.id} , fa:{u.fa.id} , val:{u.val} , pos:{u.pos}")
print(u.path) else:
for child in u.children: print(f"id: {u.id} , val:{u.val} , pos:{u.pos}")
for child in u.children:
self.dfs_show(child) self.dfs_show(child)
def build_a_tree(self):
def outofmap(self,x,y): cnt = 0
return x < 0 or y < 0 or x > self.rowNums or y > self.colNums root = TreeNode()
def build_a_tree(self): root.pos = self.start_pos
sn = TreeNode() root.id = 0
sn.pos = self.start_pos root.val = 0
id = 0 root.fa = None
sn.id = id
sn.val = 0 queue = deque([(self.start_pos[0], self.start_pos[1], root)])
sn.path = [sn.pos] st = [[False] * self.colNums for _ in range(self.rowNums)]
st[self.start_pos[0]][self.start_pos[1]] = True
st = [[False] * self.colNums for _ in range(self.rowNums)]
qsk = [] dx = [-1, 0, 1, 0]
sx, sy = self.start_pos dy = [0, -1, 0, 1]
st[sx][sy] = True
qsk.append((self.start_pos[0],self.start_pos[1], sn,[])) while queue:
dx = [-1,0,1,0] x, y, parent = queue.popleft()
dy = [0,-1,0,1] for i in range(4):
nx, ny = x + dx[i], y + dy[i]
while qsk: if self.outofmap(nx, ny) or st[nx][ny]:
x, y, u,path = qsk.pop() continue
for _x, _y in zip(dx,dy):
nx, ny = x + _x, y + _y if self.maze[nx][ny] != '1':
if self.outofmap(nx,ny): st[nx][ny] = True
continue
if self.maze[nx][ny] == '1' or st[nx][ny]: new_node = TreeNode()
continue new_node.pos = (nx, ny)
new_node.fa = parent
st[nx][ny] = True cnt+=1
to = self.maze[nx][ny] new_node.id = cnt
new_path = path + [(nx,ny)] if self.maze[nx][ny].startswith('g'):
if to.startswith('g') or to.startswith('t'): new_node.val = int(self.maze[nx][ny][1:])
new_node = TreeNode() elif self.maze[nx][ny].startswith('t'):
id+=1 new_node.val =-1 *int(self.maze[nx][ny][1:])
new_node.id = id parent.children.append(new_node)
new_node.pos = (nx, ny) queue.append((nx, ny, new_node))
new_node.fa = u return root
num_str = to[1:]
new_node.path = new_path
try:
if to.startswith('g'):
new_node.val = int(num_str) def outofmap(self,x,y):
else: return x < 0 or y < 0 or x > self.rowNums or y > self.colNums
new_node.val = -int(num_str) def getlca(self,u, v):
except ValueError: def get_path_to_root(node):
print("wa ! ") path = []
u.children.append(new_node) while node:
qsk.append((nx, ny, new_node,[])) path.append(node)
else: node = node.fa
qsk.append((nx, ny, u,new_path)) return path
path_u = get_path_to_root(u)
return sn path_v = get_path_to_root(v)
def dfs(self,sn):
sn.dp = sn.val path_u.reverse()
for child in sn.children: path_v.reverse()
# print(f"cur : {child.pos} , fa : {child.fa.pos} , childrens : {child.path}")
self.dfs(child) lca = None
if child.dp > 0: for i in range(min(len(path_u),len(path_v))):
sn.dp += child.dp if path_u[i] == path_v[i]:
sn.dp_path += child.path + child.dp_path + child.path[::-1] lca = path_u[i]
else:
break
def find_path(self):
self.path = [] if lca is None:
sn = self.build_a_tree() return []
self.dfs(sn) u_to_lca = []
return self.path node = u
while node != lca:
if __name__ == '__main__': u_to_lca.append(node.pos)
obj = SourceCollector(filename="maze.csv") node = node.fa
sn = obj.build_a_tree()
# obj.dfs_show(sn) lca_to_v = []
obj.dfs(sn) node_list = []
print(len(sn.dp_path)) node = v
print(sn.pos) while node != lca:
pre = sn.pos node_list.append(node)
for _ in sn.dp_path: node = node.fa
dx,dy = _[0] - pre[0],_[1]-pre[1] node_list.append(lca)
if dx > 0: node_list.reverse()
print("down") for node in node_list:
elif dx < 0: lca_to_v.append(node.pos)
print("up")
elif dy > 0: full_path = u_to_lca + lca_to_v
print("right") return full_path
elif dy < 0: def dfs(self,sn):
print("left")
pre = _ sn.dp = sn.val
sn.final_pos = sn.pos
sn.path= [sn.pos]
cur = None
for idx,child in enumerate(sn.children):
self.dfs(child)
if child.dp > 0:
sn.dp += child.dp
if cur != None:
sn.path.extend(self.getlca(cur,child))
sn.path.extend(child.path)
cur = child
if idx == len(sn.children)-1:
sn.final_pos = cur.final_pos
def get_path(self):
return self.path
def run(self):
sn = self.build_a_tree()
# self.dfs_show(sn)
self.dfs(sn)
self.path = sn.path
def output_list(self):
copy_maze = self.maze
for idx, (y, x) in enumerate(self.path):
if copy_maze[y][x].startswith('s') | copy_maze[y][x].startswith('e'):
continue
if copy_maze[y][x].startswith('g') | copy_maze[y][x].startswith('t'):
copy_maze[y][x] = f"{copy_maze[y][x]}p{idx}"
continue
copy_maze[y][x] = f"p{idx}"
return copy_maze
if __name__ == '__main__':
obj = SourceCollector(filename="maze.csv")
obj.run()
path = obj.get_path()
for i in path:
print(i)
# print(sn.pos)
# pre = sn.pos
# for _ in sn.dp_path:
# dx,dy = _[0] - pre[0],_[1]-pre[1]
# if dx > 0:
# print("down")
# elif dx < 0:
# print("up")
# elif dy > 0:
# print("right")
# elif dy < 0:
# print("left")
# pre = _

View File

@ -1,136 +1,136 @@
# -*-coding: GBK -*- # -*-coding: GBK -*-
import heapq # 导入堆模块,用于实现优先队列 import heapq # 导入堆模块,用于实现优先队列
from typing import List, Optional, Tuple # 导入类型提示相关模块 from typing import List, Optional, Tuple # 导入类型提示相关模块
def boss_strategy(coin: int, blood: int) -> Optional[Tuple[List[str], int]]: def boss_strategy(coin: int, blood: int) -> Optional[Tuple[List[str], int]]:
# 使用分支限界法寻找最小回合数击败BOSS的技能序列 # 使用分支限界法寻找最小回合数击败BOSS的技能序列
# 参数: # 参数:
# coin: 玩家初始金币数 # coin: 玩家初始金币数
# blood: BOSS初始血量 # blood: BOSS初始血量
# 返回: # 返回:
# 最小回合数的技能序列列表如果无解则返回None # 最小回合数的技能序列列表如果无解则返回None
start_coin = coin # 记录初始金币数,用于计算消耗金币 start_coin = coin # 记录初始金币数,用于计算消耗金币
# 初始状态: (回合数, 剩余金币, BOSS血量, 充能, 连续E计数, 技能序列元组) # 初始状态: (回合数, 剩余金币, BOSS血量, 充能, 连续E计数, 技能序列元组)
start_state = (0, coin, blood, 0, 0, ()) start_state = (0, coin, blood, 0, 0, ())
# 创建优先队列: 元素为 (优先级, 状态) # 创建优先队列: 元素为 (优先级, 状态)
# 优先级元组: (回合数, 消耗金币, BOSS血量) - 值越小优先级越高 # 优先级元组: (回合数, 消耗金币, BOSS血量) - 值越小优先级越高
heap = [] heap = []
heapq.heappush(heap, ((0, 0, blood), start_state)) # 将初始状态加入优先队列 heapq.heappush(heap, ((0, 0, blood), start_state)) # 将初始状态加入优先队列
# 创建访问集合: 用于避免重复状态 # 创建访问集合: 用于避免重复状态
# 状态键: (回合数, 剩余金币, BOSS血量, 充能, min(连续E计数,3)) # 状态键: (回合数, 剩余金币, BOSS血量, 充能, min(连续E计数,3))
visited = set() visited = set()
start_ce_compressed = min(0, 3) # 压缩连续E计数状态 start_ce_compressed = min(0, 3) # 压缩连续E计数状态
visited.add((0, coin, blood, 0, start_ce_compressed)) # 将初始状态加入已访问集合 visited.add((0, coin, blood, 0, start_ce_compressed)) # 将初始状态加入已访问集合
# 设置最大回合数限制,避免无限循环 # 设置最大回合数限制,避免无限循环
max_round = blood * 2 # 每次至少造成1点伤害最多回合数为血量两倍 max_round = blood * 2 # 每次至少造成1点伤害最多回合数为血量两倍
# 主循环: 处理优先队列中的状态 # 主循环: 处理优先队列中的状态
while heap: while heap:
# 从优先队列中取出优先级最高的状态 # 从优先队列中取出优先级最高的状态
priority, state = heapq.heappop(heap) priority, state = heapq.heappop(heap)
# 解包状态元组 # 解包状态元组
round_cnt, cur_coin, cur_blood, energy, ce, seq_tuple = state round_cnt, cur_coin, cur_blood, energy, ce, seq_tuple = state
# 检查是否已击败BOSS # 检查是否已击败BOSS
if cur_blood <= 0: if cur_blood <= 0:
return (list(seq_tuple), cur_coin) # 返回技能序列和剩余金币 return (list(seq_tuple), cur_coin) # 返回技能序列和剩余金币
# 超过最大回合数则跳过当前状态 # 超过最大回合数则跳过当前状态
if round_cnt >= max_round: if round_cnt >= max_round:
continue continue
# 尝试使用技能A # 尝试使用技能A
if cur_coin >= 2: # 检查金币是否足够 if cur_coin >= 2: # 检查金币是否足够
new_coin = cur_coin - 2 # 扣除金币 new_coin = cur_coin - 2 # 扣除金币
new_blood = cur_blood - 1 # 减少BOSS血量 new_blood = cur_blood - 1 # 减少BOSS血量
new_energy = energy + 1 # 增加充能 new_energy = energy + 1 # 增加充能
new_ce = 0 # 使用非E技能重置连续E计数 new_ce = 0 # 使用非E技能重置连续E计数
new_round = round_cnt + 1 # 回合数+1 new_round = round_cnt + 1 # 回合数+1
new_seq = seq_tuple + ('A',) # 添加技能到序列 new_seq = seq_tuple + ('A',) # 添加技能到序列
# 压缩连续E计数状态>=3视为3 # 压缩连续E计数状态>=3视为3
ce_compressed = min(new_ce, 3) ce_compressed = min(new_ce, 3)
# 创建状态键用于去重 # 创建状态键用于去重
state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed)
# 检查是否为新状态 # 检查是否为新状态
if state_key not in visited: if state_key not in visited:
visited.add(state_key) # 标记为已访问 visited.add(state_key) # 标记为已访问
cost = start_coin - new_coin # 计算已消耗金币 cost = start_coin - new_coin # 计算已消耗金币
# 创建新状态 # 创建新状态
new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq) new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq)
# 将新状态加入优先队列 # 将新状态加入优先队列
heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) heapq.heappush(heap, ((new_round, cost, new_blood), new_state))
# 尝试使用技能E # 尝试使用技能E
cost_e = 3 # 默认消耗金币 cost_e = 3 # 默认消耗金币
if ce >= 2: # 检查是否为连续第三次使用E if ce >= 2: # 检查是否为连续第三次使用E
cost_e = 2 # 第三次消耗2金币 cost_e = 2 # 第三次消耗2金币
if cur_coin >= cost_e: # 检查金币是否足够 if cur_coin >= cost_e: # 检查金币是否足够
new_coin = cur_coin - cost_e # 扣除金币 new_coin = cur_coin - cost_e # 扣除金币
new_blood = cur_blood - 3 # 减少BOSS血量 new_blood = cur_blood - 3 # 减少BOSS血量
new_energy = energy + 1 # 增加充能 new_energy = energy + 1 # 增加充能
new_ce = ce + 1 # 增加连续E计数 new_ce = ce + 1 # 增加连续E计数
new_round = round_cnt + 1 # 回合数+1 new_round = round_cnt + 1 # 回合数+1
new_seq = seq_tuple + ('E',) # 添加技能到序列 new_seq = seq_tuple + ('E',) # 添加技能到序列
# 压缩连续E计数状态 # 压缩连续E计数状态
ce_compressed = min(new_ce, 3) ce_compressed = min(new_ce, 3)
# 创建状态键用于去重 # 创建状态键用于去重
state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed)
# 检查是否为新状态 # 检查是否为新状态
if state_key not in visited: if state_key not in visited:
visited.add(state_key) # 标记为已访问 visited.add(state_key) # 标记为已访问
cost = start_coin - new_coin # 计算已消耗金币 cost = start_coin - new_coin # 计算已消耗金币
# 创建新状态 # 创建新状态
new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq) new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq)
# 将新状态加入优先队列 # 将新状态加入优先队列
heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) heapq.heappush(heap, ((new_round, cost, new_blood), new_state))
# 尝试使用技能Q # 尝试使用技能Q
if energy >= 3 and cur_coin >= 3: # 检查充能和金币是否足够 if energy >= 3 and cur_coin >= 3: # 检查充能和金币是否足够
new_coin = cur_coin - 3 # 扣除金币 new_coin = cur_coin - 3 # 扣除金币
new_blood = cur_blood - 8 # 减少BOSS血量 new_blood = cur_blood - 8 # 减少BOSS血量
new_energy = energy - 3 # 消耗充能 new_energy = energy - 3 # 消耗充能
new_ce = 0 # 使用非E技能重置连续E计数 new_ce = 0 # 使用非E技能重置连续E计数
new_round = round_cnt + 1 # 回合数+1 new_round = round_cnt + 1 # 回合数+1
new_seq = seq_tuple + ('Q',) # 添加技能到序列 new_seq = seq_tuple + ('Q',) # 添加技能到序列
# 压缩连续E计数状态 # 压缩连续E计数状态
ce_compressed = min(new_ce, 3) ce_compressed = min(new_ce, 3)
# 创建状态键用于去重 # 创建状态键用于去重
state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed)
# 检查是否为新状态 # 检查是否为新状态
if state_key not in visited: if state_key not in visited:
visited.add(state_key) # 标记为已访问 visited.add(state_key) # 标记为已访问
cost = start_coin - new_coin # 计算已消耗金币 cost = start_coin - new_coin # 计算已消耗金币
# 创建新状态 # 创建新状态
new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq) new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq)
# 将新状态加入优先队列 # 将新状态加入优先队列
heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) heapq.heappush(heap, ((new_round, cost, new_blood), new_state))
return None # 队列为空,无解 return None # 队列为空,无解
# 主程序入口 # 主程序入口
if __name__ == "__main__": if __name__ == "__main__":
# 测试示例: 金币=10, BOSS血量=10 # 测试示例: 金币=10, BOSS血量=10
result = boss_strategy(20, 20) result = boss_strategy(20, 20)
if result is None: if result is None:
print("无法击败BOSS") print("无法击败BOSS")
else: else:
skill_sequence, remaining_coins = result skill_sequence, remaining_coins = result
print("最小回合数技能序列:", skill_sequence) # 预期输出: ['A', 'A', 'A', 'Q'] print("最小回合数技能序列:", skill_sequence) # 预期输出: ['A', 'A', 'A', 'Q']
print("剩余金币:", remaining_coins) # 预期输出: 1 print("剩余金币:", remaining_coins) # 预期输出: 1

View File

@ -7,10 +7,10 @@ from draw import Button, Toast
import sys import sys
import os import os
UI_HEIGHT = 800 UI_HEIGHT = 1000
UI_WIDTH = 1100 UI_WIDTH = 1500
MAZE_SIZE = 800 MAZE_SIZE = 150
WALL_SIZE = 50 WALL_SIZE = 50
FPS = 120 FPS = 120

View File

@ -1,16 +1,16 @@
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1,0,1,0,0,0,1,e,0,0,1,t11,1,0,0,1 1,0,0,1,0,0,0,0,0,l25,0,t10,0,1,0,1
1,0,1,1,1,t17,1,0,1,0,1,0,0,0,t6,1 1,1,0,1,1,1,1,1,1,1,1,1,l15,1,t7,1
1,0,1,0,1,0,0,0,1,0,1,0,1,0,g25,1 1,0,0,g26,0,e,t20,s,0,0,0,0,0,0,l25,1
1,0,1,0,0,0,1,0,1,0,1,0,1,1,1,1 1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1
1,0,1,b89,1,0,1,0,1,0,1,0,1,g30,0,1 1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1
1,0,0,0,1,0,1,0,1,0,1,0,1,l11,0,1 1,0,1,1,1,1,0,1,1,1,1,1,g24,1,0,1
1,g30,1,0,1,0,1,0,1,0,1,0,0,g21,0,1 1,0,0,1,0,t16,0,0,1,0,0,0,0,1,l16,1
1,0,1,0,1,s,1,t11,1,1,1,0,1,0,0,1 1,1,1,1,1,1,1,1,1,1,1,0,1,1,g15,1
1,0,1,0,1,t14,1,0,0,0,1,0,1,0,0,1 1,0,t8,1,0,1,0,0,g12,0,1,0,0,1,0,1
1,1,1,1,1,1,1,0,1,1,1,0,1,0,0,1 1,0,0,1,0,1,1,0,1,0,1,0,1,1,0,1
1,0,0,g21,0,0,0,0,0,0,1,0,1,0,0,1 1,0,0,0,0,0,0,0,1,0,1,0,t15,1,l16,1
1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1 1,0,0,1,0,1,0,t16,1,0,1,0,0,1,0,1
1,0,l23,0,0,0,g17,0,0,g22,1,0,0,l26,0,1 1,1,0,1,1,1,1,1,1,0,1,0,0,1,0,1
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 1,0,0,0,0,0,0,0,1,0,t5,b89,0,1,0,1
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 1 0 1 0 0 1 0 0 1 0 e 0 0 0 l25 1 0 t11 t10 1 0 0 1 0 1
3 1 0 1 1 0 1 1 t17 1 1 0 1 1 0 1 1 0 1 0 l15 0 1 t6 t7 1
4 1 0 1 0 0 g26 1 0 0 e 0 t20 0 s 1 0 0 1 0 0 1 0 0 g25 l25 1
5 1 0 1 1 0 1 0 1 0 1 1 0 0 1 1 0 1 1 0 1 1 1 1 0 1
6 1 0 1 0 b89 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 g30 1 0 1
7 1 0 0 1 0 1 1 0 1 1 0 0 1 1 0 1 1 0 1 1 g24 l11 1 0 1
8 1 g30 0 1 0 0 1 1 0 0 t16 1 0 0 1 0 1 0 0 0 g21 1 0 l16 1
9 1 0 1 1 0 1 1 s 1 1 t11 1 1 1 1 0 1 0 1 0 g15 1
10 1 0 1 t8 0 1 1 0 t14 1 1 0 0 0 g12 0 1 0 1 0 0 1 0 1
11 1 1 0 1 0 1 1 0 1 1 0 1 1 0 1 0 1 0 1 0 1
12 1 0 0 g21 0 0 0 0 0 0 1 0 1 0 1 t15 0 1 0 l16 1
13 1 1 0 1 0 1 0 1 1 0 1 t16 1 1 0 1 1 0 1 0 0 1 1 0 1
14 1 0 1 l23 0 0 1 0 1 0 1 g17 1 0 1 0 1 g22 0 1 0 0 l26 1 0 1
15 1 0 0 0 0 0 0 0 0 1 0 0 t5 0 b89 0 0 1 0 1
16 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

48
maze.py
View File

@ -1,5 +1,6 @@
import pygame import pygame
from maze_generator import MazeGenerator from maze_generator import MazeGenerator
from SourceCollector import SourceCollector
from tanxin import * from tanxin import *
import time import time
@ -18,9 +19,10 @@ class Maze:
def generate(self): def generate(self):
seed = int(time.time() * 1000) % (2**32) seed = int(time.time() * 1000) % (2**32)
self.generater.generate(seed=seed) self.generater.generate(seed=seed)
# player = GreedyPlayer(generater.maze) obj = SourceCollector(maze=self.generater.maze)
# player.find_path() obj.run()
self.grid = self.generater.maze self.grid = obj.output_list()
print(self.grid)
def export_to_csv(self, filename): def export_to_csv(self, filename):
self.generater.export_to_csv(filename=filename) self.generater.export_to_csv(filename=filename)
@ -39,8 +41,38 @@ class Maze:
screen.blit(wall_texture, (x * tile_size, y * tile_size)) screen.blit(wall_texture, (x * tile_size, y * tile_size))
if self.grid[y][x].startswith('g'): if self.grid[y][x].startswith('g'):
screen.blit(coin_texture, (x * tile_size, y * tile_size)) screen.blit(coin_texture, (x * tile_size, y * tile_size))
font = pygame.font.SysFont(None, tile_size // 2)
path = self.grid[y][x].rfind('p')
if path == -1:
continue
path = self.grid[y][x][path+1:]
center = (x * tile_size + tile_size // 2, y * tile_size + tile_size // 2)
radius = tile_size // 3
text = font.render(path, True, (255, 255, 255))
text_rect = text.get_rect(center=center)
screen.blit(text, text_rect)
if self.grid[y][x].startswith('t'): if self.grid[y][x].startswith('t'):
screen.blit(trap_texture, (x * tile_size, y * tile_size)) screen.blit(trap_texture, (x * tile_size, y * tile_size))
font = pygame.font.SysFont(None, tile_size // 2)
path = self.grid[y][x].rfind('p')
if path == -1:
continue
path = self.grid[y][x][path+1:]
center = (x * tile_size + tile_size // 2, y * tile_size + tile_size // 2)
radius = tile_size // 3
text = font.render(path, True, (255, 255, 255))
text_rect = text.get_rect(center=center)
screen.blit(text, text_rect)
if self.grid[y][x].startswith('|') or self.grid[y][x].startswith('-'): if self.grid[y][x].startswith('|') or self.grid[y][x].startswith('-'):
font = pygame.font.SysFont(None, tile_size // 2) font = pygame.font.SysFont(None, tile_size // 2)
num = 12 num = 12
@ -73,6 +105,16 @@ class Maze:
text = font.render(text, True, (0, 0, 0)) text = font.render(text, True, (0, 0, 0))
text_rect = text.get_rect(center=center) text_rect = text.get_rect(center=center)
screen.blit(text, text_rect) screen.blit(text, text_rect)
if self.grid[y][x].startswith('p'):
font = pygame.font.SysFont(None, tile_size // 2)
text = self.grid[y][x][1:]
center = (x * tile_size + tile_size // 2, y * tile_size + tile_size // 2)
radius = tile_size // 3
pygame.draw.circle(screen, (255, 215, 0), center, radius)
if text:
text = font.render(text, True, (0, 0, 0))
text_rect = text.get_rect(center=center)
screen.blit(text, text_rect)
pygame.draw.line(screen, (0, 0, 0), (self.maze_size, 0), (self.maze_size, self.maze_size), 5) pygame.draw.line(screen, (0, 0, 0), (self.maze_size, 0), (self.maze_size, self.maze_size), 5)

View File

@ -22,82 +22,82 @@ class MazeGenerator:
self.name = name # 迷宫名称 self.name = name # 迷宫名称
self.special_elements = [] # 存储特殊元素的位置和值 self.special_elements = [] # 存储特殊元素的位置和值
self.history_mazes = [] self.history_mazes = []
def initialize_maze(self): def initialize_maze(self):
"""初始化迷宫,四周设置为墙""" """初始化迷宫,全部填充为墙"""
self.maze = [[self.ROUTE for _ in range(self.size)] for _ in range(self.size)] self.maze = [[self.WALL 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): def create_maze(self, x1, y1, x2, y2):
"""递归分割法生成迷宫""" """递归分割法生成迷宫,墙壁始终在偶数坐标"""
if x2 - x1 < 2 or y2 - y1 < 2: def getWallIndex(start, length):
return assert length >= 3
wall_index = random.randint(start + 1, start + length - 2)
if wall_index % 2 == 1:
wall_index -= 1
return wall_index
x = x1 + 1 + random.randint(0, (x2 - x1 - 2)) def isValid(x, y):
y = y1 + 1 + random.randint(0, (y2 - y1 - 2)) return 0 <= x < self.size and 0 <= y < self.size
# 画墙 def isMovable(x, y):
for i in range(x1, x2 + 1): return self.maze[y][x] != self.WALL
self.maze[i][y] = self.WALL
for i in range(y1, y2 + 1):
self.maze[x][i] = self.WALL
# 递归分割四个区域 def generateHoles(x, y, width, height, wall_x, wall_y):
self.create_maze(x1, y1, x - 1, y - 1) holes = []
self.create_maze(x + 1, y + 1, x2, y2) hole_entrys = [
self.create_maze(x + 1, y1, x2, y - 1) (random.randint(x, wall_x - 1), wall_y),
self.create_maze(x1, y + 1, x - 1, y2) (random.randint(wall_x + 1, x + width - 1), wall_y),
(wall_x, random.randint(y, wall_y - 1)),
(wall_x, random.randint(wall_y + 1, y + height - 1))
]
margin_entrys = [
(x, wall_y), (x + width - 1, wall_y),
(wall_x, y), (wall_x, y + height - 1)
]
adjacent_entrys = [
(x - 1, wall_y), (x + width, wall_y),
(wall_x, y - 1), (wall_x, y + height)
]
for i in range(4):
adj_x, adj_y = adjacent_entrys[i]
if isValid(adj_x, adj_y) and isMovable(adj_x, adj_y):
mx, my = margin_entrys[i]
self.maze[my][mx] = self.ROUTE
else:
holes.append(hole_entrys[i])
ignore_hole = random.randint(0, len(holes) - 1)
for i in range(len(holes)):
if i != ignore_hole:
hx, hy = holes[i]
self.maze[hy][hx] = self.ROUTE
# 随机打通三面墙 def recursiveDivision(x, y, width, height):
r = [0, 0, 0, 0] if width < 3 or height < 3:
r[random.randint(0, 3)] = 1 return
for i in range(4): wall_x = getWallIndex(x, width)
if r[i] == 0: wall_y = getWallIndex(y, height)
rx, ry = x, y for i in range(x, x + width):
if i == 0: # 上方 self.maze[wall_y][i] = self.WALL
while True: for i in range(y, y + height):
rx = x1 + random.randint(0, (x - x1 - 1)) self.maze[i][wall_x] = self.WALL
wall_count = sum([ generateHoles(x, y, width, height, wall_x, wall_y)
(int)(self.maze[rx - 1][ry]), (int)(self.maze[rx + 1][ry]), recursiveDivision(x, y, wall_x - x, wall_y - y)
(int)(self.maze[rx][ry - 1]), (int)(self.maze[rx][ry + 1]) recursiveDivision(x, wall_y + 1, wall_x - x, y + height - wall_y - 1)
]) recursiveDivision(wall_x + 1, y, x + width - wall_x - 1, wall_y - y)
if wall_count <= 2 * (int)(self.WALL): recursiveDivision(wall_x + 1, wall_y + 1, x + width - wall_x - 1, y + height - wall_y - 1)
break # 先全部通路
elif i == 1: # 右侧 self.maze = [[self.ROUTE for _ in range(self.size)] for _ in range(self.size)]
while True: # 四周加墙
ry = y + 1 + random.randint(0, (y2 - y - 1)) for x in range(self.size):
wall_count = sum([ self.maze[0][x] = self.WALL
(int)(self.maze[rx - 1][ry]), (int)(self.maze[rx + 1][ry]), self.maze[self.size - 1][x] = self.WALL
(int)(self.maze[rx][ry - 1]), (int)(self.maze[rx][ry + 1]) for y in range(self.size):
]) self.maze[y][0] = self.WALL
if wall_count <= 2 * (int)(self.WALL): self.maze[y][self.size - 1] = self.WALL
break # 递归分割
elif i == 2: # 下方 try:
while True: recursiveDivision(1, 1, self.size - 2, self.size - 2)
rx = x + 1 + random.randint(0, (x2 - x - 1)) except:
wall_count = sum([ self.create_maze(x1, y1, x2, y2) # 如果递归失败,重新尝试
(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
self.history_mazes.append(self.maze)
# self.history_mazes.append(self.maze)
def set_random_exits(self): def set_random_exits(self):
"""随机设置迷宫入口和出口""" """随机设置迷宫入口和出口"""
available = self.get_available_cells() available = self.get_available_cells()
@ -171,6 +171,7 @@ class MazeGenerator:
random.seed(seed or random.randint(0, 1000)) random.seed(seed or random.randint(0, 1000))
self.initialize_maze() self.initialize_maze()
self.create_maze(1, 1, self.size - 2, self.size - 2) self.create_maze(1, 1, self.size - 2, self.size - 2)
self.patch_maze_edges() # 自动修正边界
self.place_special_elements(boss_count, traps_range, mechanisms_range, skill_traps) self.place_special_elements(boss_count, traps_range, mechanisms_range, skill_traps)
print(f"成功生成迷宫: {self.name}") print(f"成功生成迷宫: {self.name}")
@ -229,27 +230,77 @@ class MazeGenerator:
for row in reader: for row in reader:
l.append(row) l.append(row)
return l return l
def patch_maze_edges(self):
"""只在不破坏联通性的前提下,修正右侧和下侧边界的多余通路(加墙)"""
n = self.size
if n %2==1:
return
candidates = []
# 倒数第二列(右侧)
x = n - 2
for y in range(1, n-1):
if self.maze[y][x] == self.ROUTE:
right = self.maze[y][x+1] if x+1 < n else self.WALL
down = self.maze[y+1][x] if y+1 < n else self.WALL
if right == self.ROUTE or down == self.ROUTE:
candidates.append((y, x))
# 倒数第
# 二行(下侧)
y = n - 2
for x in range(1, n-1):
if self.maze[y][x] == self.ROUTE:
right = self.maze[y][x+1] if x+1 < n else self.WALL
down = self.maze[y+1][x] if y+1 < n else self.WALL
if right == self.ROUTE or down == self.ROUTE:
candidates.append((y, x))
# 逐个尝试加墙,确保联通
for y, x in candidates:
old = self.maze[y][x]
self.maze[y][x] = self.WALL
if not self.is_maze_connected():
self.maze[y][x] = old # 恢复
def is_maze_connected(self):
"""检查迷宫是否连通(深度优先搜索)"""
visited = [[False] * self.size for _ in range(self.size)]
def dfs(x, y):
if x < 0 or x >= self.size or y < 0 or y >= self.size:
return
if visited[y][x] or self.maze[y][x] == self.WALL:
return
visited[y][x] = True
dfs(x + 1, y)
dfs(x - 1, y)
dfs(x, y + 1)
dfs(x, y - 1)
# 从左上角开始搜索
dfs(1, 1)
# 检查是否所有通路都被访问
for y in range(1, self.size - 1):
for x in range(1, self.size - 1):
if self.maze[y][x] == self.ROUTE and not visited[y][x]:
return False
return True
def main(): def main():
# 示例1: 生成带技能陷阱的迷宫 # 示例1: 生成带技能陷阱的迷宫
generator = MazeGenerator( generator = MazeGenerator(
size=20, size=20,
filename="dungeon_maze.csv", filename="dungeon_maze.csv"
name="龙脊峡谷迷宫"
) )
generator.generate( generator.generate(
seed=666, seed=666
boss_count=2,
traps_range=(5, 10),
mechanisms_range=(3, 7),
skill_traps=8
) )
generator.print_maze() generator.print_maze()
generator.export_to_csv() generator.export_to_csv("d.csv")
for i in generator.history_mazes:
print(i[3:])
reader = MazeGenerator(size=1, filename="d.csv")
reader = MazeGenerator(size=1, filename="dungeon_maze.csv")
if reader.read_from_csv(): if reader.read_from_csv():
print("\n读取的迷宫:") print("\n读取的迷宫:")
reader.print_maze() reader.print_maze()

614
mylock.py
View File

@ -1,308 +1,308 @@
import os import os
import json import json
from Lock import PasswordLock from Lock import PasswordLock
def is_prime(n): def is_prime(n):
"""判断一个数字是否是素数""" """判断一个数字是否是素数"""
if n < 2: if n < 2:
return False return False
for i in range(2, int(n ** 0.5) + 1): for i in range(2, int(n ** 0.5) + 1):
if n % i == 0: if n % i == 0:
return False return False
return True return True
def satisfies_prime_unique_condition(digits): def satisfies_prime_unique_condition(digits):
"""检查是否满足[-1, -1]条件:每位密码为素数且不重复""" """检查是否满足[-1, -1]条件:每位密码为素数且不重复"""
return all(is_prime(d) for d in digits) and len(set(digits)) == 3 return all(is_prime(d) for d in digits) and len(set(digits)) == 3
def crack_method1(conditions): def crack_method1(conditions):
"""从高位到低位回溯(第一位→第二位→第三位)""" """从高位到低位回溯(第一位→第二位→第三位)"""
possible_passwords = [] possible_passwords = []
tries = 0 tries = 0
def backtrack(index, current_digits): def backtrack(index, current_digits):
nonlocal tries nonlocal tries
tries += 1 tries += 1
if index == 3: if index == 3:
for condition in conditions: for condition in conditions:
if condition == [-1, -1]: if condition == [-1, -1]:
if not satisfies_prime_unique_condition(current_digits): if not satisfies_prime_unique_condition(current_digits):
return return
elif len(condition) == 2: elif len(condition) == 2:
a, t = condition a, t = condition
a = abs(a) a = abs(a)
if 1 <= a <= 3: if 1 <= a <= 3:
if t == 0 and current_digits[a - 1] % 2 != 0: if t == 0 and current_digits[a - 1] % 2 != 0:
return return
elif t == 1 and current_digits[a - 1] % 2 != 1: elif t == 1 and current_digits[a - 1] % 2 != 1:
return return
else: else:
return return
elif len(condition) == 3: elif len(condition) == 3:
b1, b2, b3 = condition b1, b2, b3 = condition
if b1 != -1 and current_digits[0] != b1: if b1 != -1 and current_digits[0] != b1:
return return
if b2 != -1 and current_digits[1] != b2: if b2 != -1 and current_digits[1] != b2:
return return
if b3 != -1 and current_digits[2] != b3: if b3 != -1 and current_digits[2] != b3:
return return
possible_passwords.append("".join(map(str, current_digits))) possible_passwords.append("".join(map(str, current_digits)))
return return
for digit in range(10): for digit in range(10):
if index == 0: if index == 0:
has_fixed_value = any(len(cond) == 3 and cond[0] != -1 for cond in conditions) has_fixed_value = any(len(cond) == 3 and cond[0] != -1 for cond in conditions)
if has_fixed_value: if has_fixed_value:
fixed_values = [cond[0] for cond in conditions if len(cond) == 3 and cond[0] != -1] fixed_values = [cond[0] for cond in conditions if len(cond) == 3 and cond[0] != -1]
if digit not in fixed_values: if digit not in fixed_values:
continue continue
elif index == 1: elif index == 1:
has_fixed_value = any(len(cond) == 3 and cond[1] != -1 for cond in conditions) has_fixed_value = any(len(cond) == 3 and cond[1] != -1 for cond in conditions)
if has_fixed_value: if has_fixed_value:
fixed_values = [cond[1] for cond in conditions if len(cond) == 3 and cond[1] != -1] fixed_values = [cond[1] for cond in conditions if len(cond) == 3 and cond[1] != -1]
if digit not in fixed_values: if digit not in fixed_values:
continue continue
elif index == 2: elif index == 2:
has_fixed_value = any(len(cond) == 3 and cond[2] != -1 for cond in conditions) has_fixed_value = any(len(cond) == 3 and cond[2] != -1 for cond in conditions)
if has_fixed_value: if has_fixed_value:
fixed_values = [cond[2] for cond in conditions if len(cond) == 3 and cond[2] != -1] fixed_values = [cond[2] for cond in conditions if len(cond) == 3 and cond[2] != -1]
if digit not in fixed_values: if digit not in fixed_values:
continue continue
current_digits.append(digit) current_digits.append(digit)
backtrack(index + 1, current_digits) backtrack(index + 1, current_digits)
current_digits.pop() current_digits.pop()
backtrack(0, []) backtrack(0, [])
return possible_passwords, tries return possible_passwords, tries
def crack_method2(conditions): def crack_method2(conditions):
"""从第二位开始回溯(第二位→第三位→第一位)""" """从第二位开始回溯(第二位→第三位→第一位)"""
possible_passwords = [] possible_passwords = []
tries = 0 tries = 0
def backtrack(index, current_digits): def backtrack(index, current_digits):
nonlocal tries nonlocal tries
tries += 1 tries += 1
if index == 3: if index == 3:
reordered = [current_digits[2], current_digits[0], current_digits[1]] reordered = [current_digits[2], current_digits[0], current_digits[1]]
for condition in conditions: for condition in conditions:
if condition == [-1, -1]: if condition == [-1, -1]:
if not satisfies_prime_unique_condition(reordered): if not satisfies_prime_unique_condition(reordered):
return return
elif len(condition) == 2: elif len(condition) == 2:
a, t = condition a, t = condition
a = abs(a) a = abs(a)
if 1 <= a <= 3: if 1 <= a <= 3:
if t == 0 and reordered[a - 1] % 2 != 0: if t == 0 and reordered[a - 1] % 2 != 0:
return return
elif t == 1 and reordered[a - 1] % 2 != 1: elif t == 1 and reordered[a - 1] % 2 != 1:
return return
else: else:
return return
elif len(condition) == 3: elif len(condition) == 3:
b1, b2, b3 = condition b1, b2, b3 = condition
if b1 != -1 and reordered[0] != b1: if b1 != -1 and reordered[0] != b1:
return return
if b2 != -1 and reordered[1] != b2: if b2 != -1 and reordered[1] != b2:
return return
if b3 != -1 and reordered[2] != b3: if b3 != -1 and reordered[2] != b3:
return return
possible_passwords.append("".join(map(str, reordered))) possible_passwords.append("".join(map(str, reordered)))
return return
for digit in range(10): for digit in range(10):
if index == 0: # 第二位 if index == 0: # 第二位
has_fixed_value = any(len(cond) == 3 and cond[1] != -1 for cond in conditions) has_fixed_value = any(len(cond) == 3 and cond[1] != -1 for cond in conditions)
if has_fixed_value: if has_fixed_value:
fixed_values = [cond[1] for cond in conditions if len(cond) == 3 and cond[1] != -1] fixed_values = [cond[1] for cond in conditions if len(cond) == 3 and cond[1] != -1]
if digit not in fixed_values: if digit not in fixed_values:
continue continue
elif index == 1: # 第三位 elif index == 1: # 第三位
has_fixed_value = any(len(cond) == 3 and cond[2] != -1 for cond in conditions) has_fixed_value = any(len(cond) == 3 and cond[2] != -1 for cond in conditions)
if has_fixed_value: if has_fixed_value:
fixed_values = [cond[2] for cond in conditions if len(cond) == 3 and cond[2] != -1] fixed_values = [cond[2] for cond in conditions if len(cond) == 3 and cond[2] != -1]
if digit not in fixed_values: if digit not in fixed_values:
continue continue
elif index == 2: # 第一位 elif index == 2: # 第一位
has_fixed_value = any(len(cond) == 3 and cond[0] != -1 for cond in conditions) has_fixed_value = any(len(cond) == 3 and cond[0] != -1 for cond in conditions)
if has_fixed_value: if has_fixed_value:
fixed_values = [cond[0] for cond in conditions if len(cond) == 3 and cond[0] != -1] fixed_values = [cond[0] for cond in conditions if len(cond) == 3 and cond[0] != -1]
if digit not in fixed_values: if digit not in fixed_values:
continue continue
current_digits.append(digit) current_digits.append(digit)
backtrack(index + 1, current_digits) backtrack(index + 1, current_digits)
current_digits.pop() current_digits.pop()
backtrack(0, []) backtrack(0, [])
return possible_passwords, tries return possible_passwords, tries
def crack_method3(conditions): def crack_method3(conditions):
"""从第三位开始回溯(第三位→第一位→第二位)""" """从第三位开始回溯(第三位→第一位→第二位)"""
possible_passwords = [] possible_passwords = []
tries = 0 tries = 0
def backtrack(index, current_digits): def backtrack(index, current_digits):
nonlocal tries nonlocal tries
tries += 1 tries += 1
if index == 3: if index == 3:
reordered = [current_digits[1], current_digits[2], current_digits[0]] reordered = [current_digits[1], current_digits[2], current_digits[0]]
for condition in conditions: for condition in conditions:
if condition == [-1, -1]: if condition == [-1, -1]:
if not satisfies_prime_unique_condition(reordered): if not satisfies_prime_unique_condition(reordered):
return return
elif len(condition) == 2: elif len(condition) == 2:
a, t = condition a, t = condition
a = abs(a) a = abs(a)
if 1 <= a <= 3: if 1 <= a <= 3:
if t == 0 and reordered[a - 1] % 2 != 0: if t == 0 and reordered[a - 1] % 2 != 0:
return return
elif t == 1 and reordered[a - 1] % 2 != 1: elif t == 1 and reordered[a - 1] % 2 != 1:
return return
else: else:
return return
elif len(condition) == 3: elif len(condition) == 3:
b1, b2, b3 = condition b1, b2, b3 = condition
if b1 != -1 and reordered[0] != b1: if b1 != -1 and reordered[0] != b1:
return return
if b2 != -1 and reordered[1] != b2: if b2 != -1 and reordered[1] != b2:
return return
if b3 != -1 and reordered[2] != b3: if b3 != -1 and reordered[2] != b3:
return return
possible_passwords.append("".join(map(str, reordered))) possible_passwords.append("".join(map(str, reordered)))
return return
for digit in range(10): for digit in range(10):
if index == 0: # 第三位 if index == 0: # 第三位
has_fixed_value = any(len(cond) == 3 and cond[2] != -1 for cond in conditions) has_fixed_value = any(len(cond) == 3 and cond[2] != -1 for cond in conditions)
if has_fixed_value: if has_fixed_value:
fixed_values = [cond[2] for cond in conditions if len(cond) == 3 and cond[2] != -1] fixed_values = [cond[2] for cond in conditions if len(cond) == 3 and cond[2] != -1]
if digit not in fixed_values: if digit not in fixed_values:
continue continue
elif index == 1: # 第一位 elif index == 1: # 第一位
has_fixed_value = any(len(cond) == 3 and cond[0] != -1 for cond in conditions) has_fixed_value = any(len(cond) == 3 and cond[0] != -1 for cond in conditions)
if has_fixed_value: if has_fixed_value:
fixed_values = [cond[0] for cond in conditions if len(cond) == 3 and cond[0] != -1] fixed_values = [cond[0] for cond in conditions if len(cond) == 3 and cond[0] != -1]
if digit not in fixed_values: if digit not in fixed_values:
continue continue
elif index == 2: # 第二位 elif index == 2: # 第二位
has_fixed_value = any(len(cond) == 3 and cond[1] != -1 for cond in conditions) has_fixed_value = any(len(cond) == 3 and cond[1] != -1 for cond in conditions)
if has_fixed_value: if has_fixed_value:
fixed_values = [cond[1] for cond in conditions if len(cond) == 3 and cond[1] != -1] fixed_values = [cond[1] for cond in conditions if len(cond) == 3 and cond[1] != -1]
if digit not in fixed_values: if digit not in fixed_values:
continue continue
current_digits.append(digit) current_digits.append(digit)
backtrack(index + 1, current_digits) backtrack(index + 1, current_digits)
current_digits.pop() current_digits.pop()
backtrack(0, []) backtrack(0, [])
return possible_passwords, tries return possible_passwords, tries
def format_json(data): def format_json(data):
"""自定义 JSON 格式化函数""" """自定义 JSON 格式化函数"""
lines = ['{'] lines = ['{']
# 格式化 C 线索部分 # 格式化 C 线索部分
if "C" in data: if "C" in data:
lines.append(' "C": [') lines.append(' "C": [')
for i, item in enumerate(data["C"]): for i, item in enumerate(data["C"]):
lines.append(f" {json.dumps(item, ensure_ascii=False)}{',' if i < len(data['C']) - 1 else ''}") lines.append(f" {json.dumps(item, ensure_ascii=False)}{',' if i < len(data['C']) - 1 else ''}")
lines.append(' ],') lines.append(' ],')
# 格式化 L 哈希值 # 格式化 L 哈希值
if "L" in data: if "L" in data:
lines.append(f' "L": {json.dumps(data["L"], ensure_ascii=False)},') lines.append(f' "L": {json.dumps(data["L"], ensure_ascii=False)},')
# 格式化 password # 格式化 password
if "password" in data: if "password" in data:
lines.append(f' "password": {json.dumps(data["password"], ensure_ascii=False)},') lines.append(f' "password": {json.dumps(data["password"], ensure_ascii=False)},')
# 格式化 results # 格式化 results
if "results" in data: if "results" in data:
lines.append(' "results": {') lines.append(' "results": {')
result_items = data["results"] result_items = data["results"]
method_names = list(result_items.keys()) method_names = list(result_items.keys())
for i, method in enumerate(method_names): for i, method in enumerate(method_names):
line = f' "{method}": {json.dumps(result_items[method], ensure_ascii=False)}' line = f' "{method}": {json.dumps(result_items[method], ensure_ascii=False)}'
if i < len(result_items) - 1: if i < len(result_items) - 1:
line += "," line += ","
lines.append(line) lines.append(line)
lines.append(' }') lines.append(' }')
lines.append('}') lines.append('}')
return "\n".join(lines) return "\n".join(lines)
def main(): def main():
# 输入和输出路径 # 输入和输出路径
input_dir = r"" # path input_dir = r"" # path
output_dir = r"" # path output_dir = r"" # path
# 如果输出目录不存在,则创建 # 如果输出目录不存在,则创建
os.makedirs(output_dir, exist_ok=True) os.makedirs(output_dir, exist_ok=True)
# 遍历输入目录下所有 .json 文件 # 遍历输入目录下所有 .json 文件
for filename in os.listdir(input_dir): for filename in os.listdir(input_dir):
if filename.endswith(".json"): if filename.endswith(".json"):
input_file_path = os.path.join(input_dir, filename) input_file_path = os.path.join(input_dir, filename)
output_file_path = os.path.join(output_dir, filename) output_file_path = os.path.join(output_dir, filename)
with open(input_file_path, 'r', encoding='utf-8') as f: with open(input_file_path, 'r', encoding='utf-8') as f:
try: try:
# 读取原始 JSON 文本内容(保留结构) # 读取原始 JSON 文本内容(保留结构)
original_content = f.read() original_content = f.read()
# 解析为字典用于处理 # 解析为字典用于处理
sample_data = json.loads(original_content) sample_data = json.loads(original_content)
except json.JSONDecodeError: except json.JSONDecodeError:
print(f"跳过无效的 JSON 文件: {filename}") print(f"跳过无效的 JSON 文件: {filename}")
continue continue
conditions = sample_data["C"] conditions = sample_data["C"]
stored_hash = sample_data["L"] stored_hash = sample_data["L"]
print(f"\n正在处理文件: {filename}") print(f"\n正在处理文件: {filename}")
pwd1, tries1 = crack_method1(conditions) pwd1, tries1 = crack_method1(conditions)
pwd2, tries2 = crack_method2(conditions) pwd2, tries2 = crack_method2(conditions)
pwd3, tries3 = crack_method3(conditions) pwd3, tries3 = crack_method3(conditions)
lock = PasswordLock() lock = PasswordLock()
matched_passwords = [] matched_passwords = []
for pwd in pwd1 + pwd2 + pwd3: for pwd in pwd1 + pwd2 + pwd3:
if pwd not in matched_passwords and lock.verify_password(pwd, stored_hash): if pwd not in matched_passwords and lock.verify_password(pwd, stored_hash):
matched_passwords.append(pwd) matched_passwords.append(pwd)
first_match = matched_passwords[0] if matched_passwords else "" first_match = matched_passwords[0] if matched_passwords else ""
# 更新 JSON 内容中的结果部分 # 更新 JSON 内容中的结果部分
result_update = { result_update = {
"password": first_match, "password": first_match,
"results": { "results": {
"method1": {"tries": tries1, "password": list(map(int, first_match)) if first_match else []}, "method1": {"tries": tries1, "password": list(map(int, first_match)) if first_match else []},
"method2": {"tries": tries2, "password": list(map(int, first_match)) if first_match else []}, "method2": {"tries": tries2, "password": list(map(int, first_match)) if first_match else []},
"method3": {"tries": tries3, "password": list(map(int, first_match)) if first_match else []} "method3": {"tries": tries3, "password": list(map(int, first_match)) if first_match else []}
} }
} }
# 加载原始内容为 dict 并更新关键字段 # 加载原始内容为 dict 并更新关键字段
data = json.loads(original_content) data = json.loads(original_content)
data.update(result_update) data.update(result_update)
# 使用自定义格式化函数生成 JSON 字符串 # 使用自定义格式化函数生成 JSON 字符串
formatted_json = format_json(data) formatted_json = format_json(data)
# 写入文件 # 写入文件
with open(output_file_path, 'w', encoding='utf-8') as f: with open(output_file_path, 'w', encoding='utf-8') as f:
f.write(formatted_json) f.write(formatted_json)
print(f"结果已保存至: {output_file_path}") print(f"结果已保存至: {output_file_path}")
if __name__ == "__main__": if __name__ == "__main__":
main() main()

200
readme.md
View File

@ -1,100 +1,100 @@
# 算法驱动的迷宫探险游戏开发 # 算法驱动的迷宫探险游戏开发
## 设计目标 ## 设计目标
***\*地图:\**** ***\*地图:\****
一个二维矩阵,采⽤分治法⽣成,⽆孤⽴区域,存在唯⼀通路。 一个二维矩阵,采⽤分治法⽣成,⽆孤⽴区域,存在唯⼀通路。
输⼊:迷宫尺⼨ 。 输⼊:迷宫尺⼨ 。
输出迷宫矩阵可存储为JSON或CSV包括起点StartS、 终点ExitE、墙壁#、通路空格、资源例如⾦币G、 陷阱TrapT、机关LockerL、BOSSB 输出迷宫矩阵可存储为JSON或CSV包括起点StartS、 终点ExitE、墙壁#、通路空格、资源例如⾦币G、 陷阱TrapT、机关LockerL、BOSSB
墙壁不可通过无value的节点 墙壁不可通过无value的节点
通路可通过无value的节点 通路可通过无value的节点
金币可通过有value 的节点。BOSS战时的行动需要消耗金币 金币可通过有value 的节点。BOSS战时的行动需要消耗金币
陷阱:可通过,但经过时会扣除玩家的金币 陷阱:可通过,但经过时会扣除玩家的金币
机关:三位密码锁。一般分布在某条路的尽头,必须开启所有机关后,终点大门才会打开 机关:三位密码锁。一般分布在某条路的尽头,必须开启所有机关后,终点大门才会打开
BOSS在必经之路上有value(血量) , 必须打败才能继续前进 BOSS在必经之路上有value(血量) , 必须打败才能继续前进
***\*玩家:\**** ***\*玩家:\****
有三种攻击方式初始充能为0 有三种攻击方式初始充能为0
A消耗2枚金币造成1点伤害并获得1点充能 A消耗2枚金币造成1点伤害并获得1点充能
E消耗3枚金币造成3点伤害并获得1点充能连续第三次使用E技能时少消耗1枚金币 E消耗3枚金币造成3点伤害并获得1点充能连续第三次使用E技能时少消耗1枚金币
Q消耗3枚金币和3点充能造成8点伤害 Q消耗3枚金币和3点充能造成8点伤害
## 任务分解 ## 任务分解
### 1. 分治法生成迷宫 ### 1. 分治法生成迷宫
**需求 : ** **需求 : **
输入 : 正整数 n( 100>=n>=7 ) , 生成类型选择(json或者csv) 输入 : 正整数 n( 100>=n>=7 ) , 生成类型选择(json或者csv)
输出 : json文件 , csv文件 , 表示地图 , 无孤立区 , 存在唯一通路 输出 : json文件 , csv文件 , 表示地图 , 无孤立区 , 存在唯一通路
S : 起点 S : 起点
E : 终点 E : 终点
\# :墙壁 \# :墙壁
blank : 通路 blank : 通路
G : 资源 G : 资源
T : 陷阱 T : 陷阱
L : 机关 L : 机关
B : Boss B : Boss
**递归分割法生成迷宫** **递归分割法生成迷宫**
### 2. 动态规划进行资源收集路径规划 ### 2. 动态规划进行资源收集路径规划
### 3. 贪心算法设计实时资源拾取策略 ### 3. 贪心算法设计实时资源拾取策略
### 4. 回溯法解迷关卡 ### 4. 回溯法解迷关卡
### 5. 分支限界设计boss战 ### 5. 分支限界设计boss战