From 198b6bd506c5f8754c30394aa1ed87cabc104c52 Mon Sep 17 00:00:00 2001 From: Guanforever <2307786059@qq.com> Date: Sun, 29 Jun 2025 16:42:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E8=B7=AF=E5=BE=84=E7=94=9F?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 6 +- SourceCollector.py | 340 ++++++++++++++----------- boss_fight.py | 272 ++++++++++---------- main.py | 6 +- maze.csv | 28 +-- maze.py | 48 +++- maze_generator.py | 209 +++++++++------ mylock.py | 614 ++++++++++++++++++++++----------------------- readme.md | 200 +++++++-------- 9 files changed, 936 insertions(+), 787 deletions(-) diff --git a/.gitignore b/.gitignore index 5e67e26..9a345ec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -__pycache__/ -.venv/ -.idea/ +__pycache__/ +.venv/ +.idea/ *.csv \ No newline at end of file diff --git a/SourceCollector.py b/SourceCollector.py index 9e5b361..bafb8dc 100644 --- a/SourceCollector.py +++ b/SourceCollector.py @@ -1,142 +1,198 @@ -import csv - -class TreeNode: - def __init__(self): - self.fa = None - self.children = [] - self.pos = None - self.val = 0 - self.id = 0 - self.dp = 0 - self.path = [] - self.dp_path = [] - -class SourceCollector: - def __init__(self, filename, maze=None): - self.filename = filename - self.maze = maze - self.start_pos = None - self.end_pos = None - self.path = [] - - if self.filename: - self.maze = [] - with open(f"{self.filename}",'r') as f: - reader = csv.reader(f) - for row in reader: - t = [] - for i in row: - if i.startswith('b') or i.startswith('l'): - t.append('0') - else: - t.append(i) - self.maze.append(t) - 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': - self.start_pos = (i,j) - if self.maze[i][j] =='e': - self.end_pos = (i,j) - - def dfs_show(self,u): - if u.id != 0: - print(f"id: {u.id} , fa:{u.fa.id} , val:{u.val}") - else: - print(f"id: {u.id} , val:{u.val}") - print(u.path) - for child in u.children: - - self.dfs_show(child) - - def outofmap(self,x,y): - return x < 0 or y < 0 or x > self.rowNums or y > self.colNums - def build_a_tree(self): - sn = TreeNode() - sn.pos = self.start_pos - id = 0 - sn.id = id - sn.val = 0 - sn.path = [sn.pos] - - st = [[False] * self.colNums for _ in range(self.rowNums)] - qsk = [] - sx, sy = self.start_pos - st[sx][sy] = True - qsk.append((self.start_pos[0],self.start_pos[1], sn,[])) - dx = [-1,0,1,0] - dy = [0,-1,0,1] - - while qsk: - x, y, u,path = qsk.pop() - for _x, _y in zip(dx,dy): - nx, ny = x + _x, y + _y - if self.outofmap(nx,ny): - continue - if self.maze[nx][ny] == '1' or st[nx][ny]: - continue - - st[nx][ny] = True - to = self.maze[nx][ny] - new_path = path + [(nx,ny)] - if to.startswith('g') or to.startswith('t'): - new_node = TreeNode() - id+=1 - new_node.id = id - new_node.pos = (nx, ny) - new_node.fa = u - num_str = to[1:] - new_node.path = new_path - try: - if to.startswith('g'): - new_node.val = int(num_str) - else: - new_node.val = -int(num_str) - except ValueError: - print("wa ! ") - u.children.append(new_node) - qsk.append((nx, ny, new_node,[])) - else: - qsk.append((nx, ny, u,new_path)) - - return sn - def dfs(self,sn): - sn.dp = sn.val - for child in sn.children: - # print(f"cur : {child.pos} , fa : {child.fa.pos} , childrens : {child.path}") - self.dfs(child) - if child.dp > 0: - sn.dp += child.dp - sn.dp_path += child.path + child.dp_path + child.path[::-1] - - - def find_path(self): - self.path = [] - sn = self.build_a_tree() - self.dfs(sn) - return self.path - -if __name__ == '__main__': - obj = SourceCollector(filename="maze.csv") - sn = obj.build_a_tree() - # obj.dfs_show(sn) - obj.dfs(sn) - print(len(sn.dp_path)) - 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 = _ - - +import csv +from collections import deque + +class TreeNode: + def __init__(self): + self.fa = None + self.children = [] + self.pos = None + self.final_pos = None + self.val = 0 + self.id = 0 + self.dp = 0 + +class SourceCollector: + def __init__(self, filename=None, maze=None): + self.filename = filename + self.maze = maze + self.start_pos = None + self.end_pos = None + self.path = [] + self.node_path = [] + if self.filename: + self.maze = [] + with open(f"{self.filename}",'r') as f: + reader = csv.reader(f) + for row in reader: + t = [] + for i in row: + if i.startswith('b') or i.startswith('l'): + t.append('0') + else: + t.append(i) + self.maze.append(t) + else: + 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': + self.start_pos = (i,j) + if self.maze[i][j] =='e': + self.end_pos = (i,j) + + def dfs_show(self,u): + if u.id != 0: + print(f"id: {u.id} , fa:{u.fa.id} , val:{u.val} , pos:{u.pos}") + else: + print(f"id: {u.id} , val:{u.val} , pos:{u.pos}") + for child in u.children: + self.dfs_show(child) + def build_a_tree(self): + cnt = 0 + root = TreeNode() + root.pos = self.start_pos + root.id = 0 + root.val = 0 + root.fa = None + + queue = deque([(self.start_pos[0], self.start_pos[1], root)]) + st = [[False] * self.colNums for _ in range(self.rowNums)] + st[self.start_pos[0]][self.start_pos[1]] = True + + dx = [-1, 0, 1, 0] + dy = [0, -1, 0, 1] + + while queue: + x, y, parent = queue.popleft() + for i in range(4): + nx, ny = x + dx[i], y + dy[i] + if self.outofmap(nx, ny) or st[nx][ny]: + continue + + if self.maze[nx][ny] != '1': + st[nx][ny] = True + + new_node = TreeNode() + new_node.pos = (nx, ny) + new_node.fa = parent + cnt+=1 + new_node.id = cnt + if self.maze[nx][ny].startswith('g'): + new_node.val = int(self.maze[nx][ny][1:]) + elif self.maze[nx][ny].startswith('t'): + new_node.val =-1 *int(self.maze[nx][ny][1:]) + parent.children.append(new_node) + queue.append((nx, ny, new_node)) + return root + + + + + def outofmap(self,x,y): + return x < 0 or y < 0 or x > self.rowNums or y > self.colNums + def getlca(self,u, v): + def get_path_to_root(node): + path = [] + while node: + path.append(node) + node = node.fa + return path + path_u = get_path_to_root(u) + path_v = get_path_to_root(v) + + path_u.reverse() + path_v.reverse() + + lca = None + for i in range(min(len(path_u),len(path_v))): + if path_u[i] == path_v[i]: + lca = path_u[i] + else: + break + + if lca is None: + return [] + u_to_lca = [] + node = u + while node != lca: + u_to_lca.append(node.pos) + node = node.fa + + lca_to_v = [] + node_list = [] + node = v + while node != lca: + node_list.append(node) + node = node.fa + node_list.append(lca) + node_list.reverse() + for node in node_list: + lca_to_v.append(node.pos) + + full_path = u_to_lca + lca_to_v + return full_path + def dfs(self,sn): + + 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 = _ \ No newline at end of file diff --git a/boss_fight.py b/boss_fight.py index b1cdc4f..20f2f76 100644 --- a/boss_fight.py +++ b/boss_fight.py @@ -1,136 +1,136 @@ -# -*-coding: GBK -*- -import heapq # 导入堆模块,用于实现优先队列 -from typing import List, Optional, Tuple # 导入类型提示相关模块 - - -def boss_strategy(coin: int, blood: int) -> Optional[Tuple[List[str], int]]: - # 使用分支限界法寻找最小回合数击败BOSS的技能序列 - - # 参数: - # coin: 玩家初始金币数 - # blood: BOSS初始血量 - - # 返回: - # 最小回合数的技能序列列表,如果无解则返回None - - start_coin = coin # 记录初始金币数,用于计算消耗金币 - - # 初始状态: (回合数, 剩余金币, BOSS血量, 充能, 连续E计数, 技能序列元组) - start_state = (0, coin, blood, 0, 0, ()) - - # 创建优先队列: 元素为 (优先级, 状态) - # 优先级元组: (回合数, 消耗金币, BOSS血量) - 值越小优先级越高 - heap = [] - heapq.heappush(heap, ((0, 0, blood), start_state)) # 将初始状态加入优先队列 - - # 创建访问集合: 用于避免重复状态 - # 状态键: (回合数, 剩余金币, BOSS血量, 充能, min(连续E计数,3)) - visited = set() - start_ce_compressed = min(0, 3) # 压缩连续E计数状态 - visited.add((0, coin, blood, 0, start_ce_compressed)) # 将初始状态加入已访问集合 - - # 设置最大回合数限制,避免无限循环 - max_round = blood * 2 # 每次至少造成1点伤害,最多回合数为血量两倍 - - # 主循环: 处理优先队列中的状态 - while heap: - # 从优先队列中取出优先级最高的状态 - priority, state = heapq.heappop(heap) - # 解包状态元组 - round_cnt, cur_coin, cur_blood, energy, ce, seq_tuple = state - - # 检查是否已击败BOSS - if cur_blood <= 0: - return (list(seq_tuple), cur_coin) # 返回技能序列和剩余金币 - - # 超过最大回合数则跳过当前状态 - if round_cnt >= max_round: - continue - - # 尝试使用技能A - if cur_coin >= 2: # 检查金币是否足够 - new_coin = cur_coin - 2 # 扣除金币 - new_blood = cur_blood - 1 # 减少BOSS血量 - new_energy = energy + 1 # 增加充能 - new_ce = 0 # 使用非E技能,重置连续E计数 - new_round = round_cnt + 1 # 回合数+1 - new_seq = seq_tuple + ('A',) # 添加技能到序列 - - # 压缩连续E计数状态(>=3视为3) - ce_compressed = min(new_ce, 3) - # 创建状态键用于去重 - state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) - - # 检查是否为新状态 - if state_key not in visited: - visited.add(state_key) # 标记为已访问 - cost = start_coin - new_coin # 计算已消耗金币 - # 创建新状态 - new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq) - # 将新状态加入优先队列 - heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) - - # 尝试使用技能E - cost_e = 3 # 默认消耗金币 - if ce >= 2: # 检查是否为连续第三次使用E - cost_e = 2 # 第三次消耗2金币 - - if cur_coin >= cost_e: # 检查金币是否足够 - new_coin = cur_coin - cost_e # 扣除金币 - new_blood = cur_blood - 3 # 减少BOSS血量 - new_energy = energy + 1 # 增加充能 - new_ce = ce + 1 # 增加连续E计数 - new_round = round_cnt + 1 # 回合数+1 - new_seq = seq_tuple + ('E',) # 添加技能到序列 - - # 压缩连续E计数状态 - ce_compressed = min(new_ce, 3) - # 创建状态键用于去重 - state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) - - # 检查是否为新状态 - if state_key not in visited: - visited.add(state_key) # 标记为已访问 - cost = start_coin - new_coin # 计算已消耗金币 - # 创建新状态 - new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq) - # 将新状态加入优先队列 - heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) - - # 尝试使用技能Q - if energy >= 3 and cur_coin >= 3: # 检查充能和金币是否足够 - new_coin = cur_coin - 3 # 扣除金币 - new_blood = cur_blood - 8 # 减少BOSS血量 - new_energy = energy - 3 # 消耗充能 - new_ce = 0 # 使用非E技能,重置连续E计数 - new_round = round_cnt + 1 # 回合数+1 - new_seq = seq_tuple + ('Q',) # 添加技能到序列 - - # 压缩连续E计数状态 - ce_compressed = min(new_ce, 3) - # 创建状态键用于去重 - state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) - - # 检查是否为新状态 - if state_key not in visited: - visited.add(state_key) # 标记为已访问 - cost = start_coin - new_coin # 计算已消耗金币 - # 创建新状态 - new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq) - # 将新状态加入优先队列 - heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) - - return None # 队列为空,无解 - - -# 主程序入口 -if __name__ == "__main__": - # 测试示例: 金币=10, BOSS血量=10 - result = boss_strategy(20, 20) - - if result is None: - print("无法击败BOSS") - else: - skill_sequence, remaining_coins = result - print("最小回合数技能序列:", skill_sequence) # 预期输出: ['A', 'A', 'A', 'Q'] - print("剩余金币:", remaining_coins) # 预期输出: 1 +# -*-coding: GBK -*- +import heapq # 导入堆模块,用于实现优先队列 +from typing import List, Optional, Tuple # 导入类型提示相关模块 + + +def boss_strategy(coin: int, blood: int) -> Optional[Tuple[List[str], int]]: + # 使用分支限界法寻找最小回合数击败BOSS的技能序列 + + # 参数: + # coin: 玩家初始金币数 + # blood: BOSS初始血量 + + # 返回: + # 最小回合数的技能序列列表,如果无解则返回None + + start_coin = coin # 记录初始金币数,用于计算消耗金币 + + # 初始状态: (回合数, 剩余金币, BOSS血量, 充能, 连续E计数, 技能序列元组) + start_state = (0, coin, blood, 0, 0, ()) + + # 创建优先队列: 元素为 (优先级, 状态) + # 优先级元组: (回合数, 消耗金币, BOSS血量) - 值越小优先级越高 + heap = [] + heapq.heappush(heap, ((0, 0, blood), start_state)) # 将初始状态加入优先队列 + + # 创建访问集合: 用于避免重复状态 + # 状态键: (回合数, 剩余金币, BOSS血量, 充能, min(连续E计数,3)) + visited = set() + start_ce_compressed = min(0, 3) # 压缩连续E计数状态 + visited.add((0, coin, blood, 0, start_ce_compressed)) # 将初始状态加入已访问集合 + + # 设置最大回合数限制,避免无限循环 + max_round = blood * 2 # 每次至少造成1点伤害,最多回合数为血量两倍 + + # 主循环: 处理优先队列中的状态 + while heap: + # 从优先队列中取出优先级最高的状态 + priority, state = heapq.heappop(heap) + # 解包状态元组 + round_cnt, cur_coin, cur_blood, energy, ce, seq_tuple = state + + # 检查是否已击败BOSS + if cur_blood <= 0: + return (list(seq_tuple), cur_coin) # 返回技能序列和剩余金币 + + # 超过最大回合数则跳过当前状态 + if round_cnt >= max_round: + continue + + # 尝试使用技能A + if cur_coin >= 2: # 检查金币是否足够 + new_coin = cur_coin - 2 # 扣除金币 + new_blood = cur_blood - 1 # 减少BOSS血量 + new_energy = energy + 1 # 增加充能 + new_ce = 0 # 使用非E技能,重置连续E计数 + new_round = round_cnt + 1 # 回合数+1 + new_seq = seq_tuple + ('A',) # 添加技能到序列 + + # 压缩连续E计数状态(>=3视为3) + ce_compressed = min(new_ce, 3) + # 创建状态键用于去重 + state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) + + # 检查是否为新状态 + if state_key not in visited: + visited.add(state_key) # 标记为已访问 + cost = start_coin - new_coin # 计算已消耗金币 + # 创建新状态 + new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq) + # 将新状态加入优先队列 + heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) + + # 尝试使用技能E + cost_e = 3 # 默认消耗金币 + if ce >= 2: # 检查是否为连续第三次使用E + cost_e = 2 # 第三次消耗2金币 + + if cur_coin >= cost_e: # 检查金币是否足够 + new_coin = cur_coin - cost_e # 扣除金币 + new_blood = cur_blood - 3 # 减少BOSS血量 + new_energy = energy + 1 # 增加充能 + new_ce = ce + 1 # 增加连续E计数 + new_round = round_cnt + 1 # 回合数+1 + new_seq = seq_tuple + ('E',) # 添加技能到序列 + + # 压缩连续E计数状态 + ce_compressed = min(new_ce, 3) + # 创建状态键用于去重 + state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) + + # 检查是否为新状态 + if state_key not in visited: + visited.add(state_key) # 标记为已访问 + cost = start_coin - new_coin # 计算已消耗金币 + # 创建新状态 + new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq) + # 将新状态加入优先队列 + heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) + + # 尝试使用技能Q + if energy >= 3 and cur_coin >= 3: # 检查充能和金币是否足够 + new_coin = cur_coin - 3 # 扣除金币 + new_blood = cur_blood - 8 # 减少BOSS血量 + new_energy = energy - 3 # 消耗充能 + new_ce = 0 # 使用非E技能,重置连续E计数 + new_round = round_cnt + 1 # 回合数+1 + new_seq = seq_tuple + ('Q',) # 添加技能到序列 + + # 压缩连续E计数状态 + ce_compressed = min(new_ce, 3) + # 创建状态键用于去重 + state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) + + # 检查是否为新状态 + if state_key not in visited: + visited.add(state_key) # 标记为已访问 + cost = start_coin - new_coin # 计算已消耗金币 + # 创建新状态 + new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq) + # 将新状态加入优先队列 + heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) + + return None # 队列为空,无解 + + +# 主程序入口 +if __name__ == "__main__": + # 测试示例: 金币=10, BOSS血量=10 + result = boss_strategy(20, 20) + + if result is None: + print("无法击败BOSS") + else: + skill_sequence, remaining_coins = result + print("最小回合数技能序列:", skill_sequence) # 预期输出: ['A', 'A', 'A', 'Q'] + print("剩余金币:", remaining_coins) # 预期输出: 1 diff --git a/main.py b/main.py index dff69ed..237f6df 100644 --- a/main.py +++ b/main.py @@ -7,10 +7,10 @@ from draw import Button, Toast import sys import os -UI_HEIGHT = 800 -UI_WIDTH = 1100 +UI_HEIGHT = 1000 +UI_WIDTH = 1500 -MAZE_SIZE = 800 +MAZE_SIZE = 150 WALL_SIZE = 50 FPS = 120 diff --git a/maze.csv b/maze.csv index dd12e14..320e83c 100644 --- a/maze.csv +++ b/maze.csv @@ -1,16 +1,16 @@ 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,1,1,1,t17,1,0,1,0,1,0,0,0,t6,1 -1,0,1,0,1,0,0,0,1,0,1,0,1,0,g25,1 -1,0,1,0,0,0,1,0,1,0,1,0,1,1,1,1 -1,0,1,b89,1,0,1,0,1,0,1,0,1,g30,0,1 -1,0,0,0,1,0,1,0,1,0,1,0,1,l11,0,1 -1,g30,1,0,1,0,1,0,1,0,1,0,0,g21,0,1 -1,0,1,0,1,s,1,t11,1,1,1,0,1,0,0,1 -1,0,1,0,1,t14,1,0,0,0,1,0,1,0,0,1 -1,1,1,1,1,1,1,0,1,1,1,0,1,0,0,1 -1,0,0,g21,0,0,0,0,0,0,1,0,1,0,0,1 -1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1 -1,0,l23,0,0,0,g17,0,0,g22,1,0,0,l26,0,1 -1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 +1,0,0,1,0,0,0,0,0,l25,0,t10,0,1,0,1 +1,1,0,1,1,1,1,1,1,1,1,1,l15,1,t7,1 +1,0,0,g26,0,e,t20,s,0,0,0,0,0,0,l25,1 +1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1 +1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1 +1,0,1,1,1,1,0,1,1,1,1,1,g24,1,0,1 +1,0,0,1,0,t16,0,0,1,0,0,0,0,1,l16,1 +1,1,1,1,1,1,1,1,1,1,1,0,1,1,g15,1 +1,0,t8,1,0,1,0,0,g12,0,1,0,0,1,0,1 +1,0,0,1,0,1,1,0,1,0,1,0,1,1,0,1 +1,0,0,0,0,0,0,0,1,0,1,0,t15,1,l16,1 +1,0,0,1,0,1,0,t16,1,0,1,0,0,1,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,1,0,t5,b89,0,1,0,1 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 diff --git a/maze.py b/maze.py index 5ad6363..3cfb2b7 100644 --- a/maze.py +++ b/maze.py @@ -1,5 +1,6 @@ import pygame from maze_generator import MazeGenerator +from SourceCollector import SourceCollector from tanxin import * import time @@ -18,9 +19,10 @@ class Maze: def generate(self): seed = int(time.time() * 1000) % (2**32) self.generater.generate(seed=seed) - # player = GreedyPlayer(generater.maze) - # player.find_path() - self.grid = self.generater.maze + obj = SourceCollector(maze=self.generater.maze) + obj.run() + self.grid = obj.output_list() + print(self.grid) def export_to_csv(self, filename): self.generater.export_to_csv(filename=filename) @@ -39,8 +41,38 @@ class Maze: screen.blit(wall_texture, (x * tile_size, y * tile_size)) if self.grid[y][x].startswith('g'): 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'): 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('-'): font = pygame.font.SysFont(None, tile_size // 2) num = 12 @@ -73,6 +105,16 @@ class Maze: text = font.render(text, True, (0, 0, 0)) text_rect = text.get_rect(center=center) 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) diff --git a/maze_generator.py b/maze_generator.py index 1474d88..4f2f9b0 100644 --- a/maze_generator.py +++ b/maze_generator.py @@ -22,82 +22,82 @@ class MazeGenerator: self.name = name # 杩峰鍚嶇О self.special_elements = [] # 瀛樺偍鐗规畩鍏冪礌鐨勪綅缃拰鍊 self.history_mazes = [] - 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 + """鍒濆鍖栬糠瀹紝鍏ㄩ儴濉厖涓哄""" + self.maze = [[self.WALL for _ in range(self.size)] for _ in range(self.size)] def create_maze(self, x1, y1, x2, y2): - """閫掑綊鍒嗗壊娉曠敓鎴愯糠瀹""" - if x2 - x1 < 2 or y2 - y1 < 2: - return + """閫掑綊鍒嗗壊娉曠敓鎴愯糠瀹紝澧欏濮嬬粓鍦ㄥ伓鏁板潗鏍""" + def getWallIndex(start, length): + 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)) - y = y1 + 1 + random.randint(0, (y2 - y1 - 2)) + def isValid(x, y): + return 0 <= x < self.size and 0 <= y < self.size - # 鐢诲 - 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 + def isMovable(x, y): + return self.maze[y][x] != 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) + def generateHoles(x, y, width, height, wall_x, wall_y): + holes = [] + hole_entrys = [ + (random.randint(x, wall_x - 1), wall_y), + (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 - # 闅忔満鎵撻氫笁闈㈠ - 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 - self.history_mazes.append(self.maze) - - # self.history_mazes.append(self.maze) + def recursiveDivision(x, y, width, height): + if width < 3 or height < 3: + return + wall_x = getWallIndex(x, width) + wall_y = getWallIndex(y, height) + for i in range(x, x + width): + self.maze[wall_y][i] = self.WALL + for i in range(y, y + height): + self.maze[i][wall_x] = self.WALL + generateHoles(x, y, width, height, wall_x, wall_y) + recursiveDivision(x, y, wall_x - x, wall_y - y) + 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) + recursiveDivision(wall_x + 1, wall_y + 1, x + width - wall_x - 1, y + height - wall_y - 1) + # 鍏堝叏閮ㄩ氳矾 + self.maze = [[self.ROUTE for _ in range(self.size)] for _ in range(self.size)] + # 鍥涘懆鍔犲 + for x in range(self.size): + self.maze[0][x] = self.WALL + self.maze[self.size - 1][x] = self.WALL + for y in range(self.size): + self.maze[y][0] = self.WALL + self.maze[y][self.size - 1] = self.WALL + # 閫掑綊鍒嗗壊 + try: + recursiveDivision(1, 1, self.size - 2, self.size - 2) + except: + self.create_maze(x1, y1, x2, y2) # 濡傛灉閫掑綊澶辫触锛岄噸鏂板皾璇 def set_random_exits(self): """闅忔満璁剧疆杩峰鍏ュ彛鍜屽嚭鍙""" available = self.get_available_cells() @@ -171,6 +171,7 @@ class MazeGenerator: random.seed(seed or random.randint(0, 1000)) self.initialize_maze() 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) print(f"鎴愬姛鐢熸垚杩峰: {self.name}") @@ -229,27 +230,77 @@ class MazeGenerator: for row in reader: l.append(row) 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(): # 绀轰緥1: 鐢熸垚甯︽妧鑳介櫡闃辩殑杩峰 generator = MazeGenerator( size=20, - filename="dungeon_maze.csv", - name="榫欒剨宄¤胺杩峰" + filename="dungeon_maze.csv" ) generator.generate( - seed=666, - boss_count=2, - traps_range=(5, 10), - mechanisms_range=(3, 7), - skill_traps=8 + seed=666 ) 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="dungeon_maze.csv") + reader = MazeGenerator(size=1, filename="d.csv") if reader.read_from_csv(): print("\n璇诲彇鐨勮糠瀹:") reader.print_maze() diff --git a/mylock.py b/mylock.py index e7656e8..35a5126 100644 --- a/mylock.py +++ b/mylock.py @@ -1,308 +1,308 @@ -import os -import json -from Lock import PasswordLock - - -def is_prime(n): - """鍒ゆ柇涓涓暟瀛楁槸鍚︽槸绱犳暟""" - if n < 2: - return False - for i in range(2, int(n ** 0.5) + 1): - if n % i == 0: - return False - return True - - -def satisfies_prime_unique_condition(digits): - """妫鏌ユ槸鍚︽弧瓒砙-1, -1]鏉′欢锛氭瘡浣嶅瘑鐮佷负绱犳暟涓斾笉閲嶅""" - return all(is_prime(d) for d in digits) and len(set(digits)) == 3 - - -def crack_method1(conditions): - """浠庨珮浣嶅埌浣庝綅鍥炴函锛堢涓浣嶁啋绗簩浣嶁啋绗笁浣嶏級""" - possible_passwords = [] - tries = 0 - - def backtrack(index, current_digits): - nonlocal tries - tries += 1 - if index == 3: - for condition in conditions: - if condition == [-1, -1]: - if not satisfies_prime_unique_condition(current_digits): - return - elif len(condition) == 2: - a, t = condition - a = abs(a) - if 1 <= a <= 3: - if t == 0 and current_digits[a - 1] % 2 != 0: - return - elif t == 1 and current_digits[a - 1] % 2 != 1: - return - else: - return - elif len(condition) == 3: - b1, b2, b3 = condition - if b1 != -1 and current_digits[0] != b1: - return - if b2 != -1 and current_digits[1] != b2: - return - if b3 != -1 and current_digits[2] != b3: - return - possible_passwords.append("".join(map(str, current_digits))) - return - - for digit in range(10): - if index == 0: - has_fixed_value = any(len(cond) == 3 and cond[0] != -1 for cond in conditions) - if has_fixed_value: - fixed_values = [cond[0] for cond in conditions if len(cond) == 3 and cond[0] != -1] - if digit not in fixed_values: - continue - elif index == 1: - has_fixed_value = any(len(cond) == 3 and cond[1] != -1 for cond in conditions) - if has_fixed_value: - fixed_values = [cond[1] for cond in conditions if len(cond) == 3 and cond[1] != -1] - if digit not in fixed_values: - continue - elif index == 2: - has_fixed_value = any(len(cond) == 3 and cond[2] != -1 for cond in conditions) - if has_fixed_value: - fixed_values = [cond[2] for cond in conditions if len(cond) == 3 and cond[2] != -1] - if digit not in fixed_values: - continue - current_digits.append(digit) - backtrack(index + 1, current_digits) - current_digits.pop() - - backtrack(0, []) - return possible_passwords, tries - - -def crack_method2(conditions): - """浠庣浜屼綅寮濮嬪洖婧紙绗簩浣嶁啋绗笁浣嶁啋绗竴浣嶏級""" - possible_passwords = [] - tries = 0 - - def backtrack(index, current_digits): - nonlocal tries - tries += 1 - if index == 3: - reordered = [current_digits[2], current_digits[0], current_digits[1]] - for condition in conditions: - if condition == [-1, -1]: - if not satisfies_prime_unique_condition(reordered): - return - elif len(condition) == 2: - a, t = condition - a = abs(a) - if 1 <= a <= 3: - if t == 0 and reordered[a - 1] % 2 != 0: - return - elif t == 1 and reordered[a - 1] % 2 != 1: - return - else: - return - elif len(condition) == 3: - b1, b2, b3 = condition - if b1 != -1 and reordered[0] != b1: - return - if b2 != -1 and reordered[1] != b2: - return - if b3 != -1 and reordered[2] != b3: - return - possible_passwords.append("".join(map(str, reordered))) - return - - for digit in range(10): - if index == 0: # 绗簩浣 - has_fixed_value = any(len(cond) == 3 and cond[1] != -1 for cond in conditions) - if has_fixed_value: - fixed_values = [cond[1] for cond in conditions if len(cond) == 3 and cond[1] != -1] - if digit not in fixed_values: - continue - elif index == 1: # 绗笁浣 - has_fixed_value = any(len(cond) == 3 and cond[2] != -1 for cond in conditions) - if has_fixed_value: - fixed_values = [cond[2] for cond in conditions if len(cond) == 3 and cond[2] != -1] - if digit not in fixed_values: - continue - elif index == 2: # 绗竴浣 - has_fixed_value = any(len(cond) == 3 and cond[0] != -1 for cond in conditions) - if has_fixed_value: - fixed_values = [cond[0] for cond in conditions if len(cond) == 3 and cond[0] != -1] - if digit not in fixed_values: - continue - current_digits.append(digit) - backtrack(index + 1, current_digits) - current_digits.pop() - - backtrack(0, []) - return possible_passwords, tries - - -def crack_method3(conditions): - """浠庣涓変綅寮濮嬪洖婧紙绗笁浣嶁啋绗竴浣嶁啋绗簩浣嶏級""" - possible_passwords = [] - tries = 0 - - def backtrack(index, current_digits): - nonlocal tries - tries += 1 - if index == 3: - reordered = [current_digits[1], current_digits[2], current_digits[0]] - for condition in conditions: - if condition == [-1, -1]: - if not satisfies_prime_unique_condition(reordered): - return - elif len(condition) == 2: - a, t = condition - a = abs(a) - if 1 <= a <= 3: - if t == 0 and reordered[a - 1] % 2 != 0: - return - elif t == 1 and reordered[a - 1] % 2 != 1: - return - else: - return - elif len(condition) == 3: - b1, b2, b3 = condition - if b1 != -1 and reordered[0] != b1: - return - if b2 != -1 and reordered[1] != b2: - return - if b3 != -1 and reordered[2] != b3: - return - possible_passwords.append("".join(map(str, reordered))) - return - - for digit in range(10): - if index == 0: # 绗笁浣 - has_fixed_value = any(len(cond) == 3 and cond[2] != -1 for cond in conditions) - if has_fixed_value: - fixed_values = [cond[2] for cond in conditions if len(cond) == 3 and cond[2] != -1] - if digit not in fixed_values: - continue - elif index == 1: # 绗竴浣 - has_fixed_value = any(len(cond) == 3 and cond[0] != -1 for cond in conditions) - if has_fixed_value: - fixed_values = [cond[0] for cond in conditions if len(cond) == 3 and cond[0] != -1] - if digit not in fixed_values: - continue - elif index == 2: # 绗簩浣 - has_fixed_value = any(len(cond) == 3 and cond[1] != -1 for cond in conditions) - if has_fixed_value: - fixed_values = [cond[1] for cond in conditions if len(cond) == 3 and cond[1] != -1] - if digit not in fixed_values: - continue - current_digits.append(digit) - backtrack(index + 1, current_digits) - current_digits.pop() - - backtrack(0, []) - return possible_passwords, tries - - -def format_json(data): - """鑷畾涔 JSON 鏍煎紡鍖栧嚱鏁""" - lines = ['{'] - - # 鏍煎紡鍖 C 绾跨储閮ㄥ垎 - if "C" in data: - lines.append(' "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(' ],') - - # 鏍煎紡鍖 L 鍝堝笇鍊 - if "L" in data: - lines.append(f' "L": {json.dumps(data["L"], ensure_ascii=False)},') - - # 鏍煎紡鍖 password - if "password" in data: - lines.append(f' "password": {json.dumps(data["password"], ensure_ascii=False)},') - - # 鏍煎紡鍖 results - if "results" in data: - lines.append(' "results": {') - result_items = data["results"] - method_names = list(result_items.keys()) - for i, method in enumerate(method_names): - line = f' "{method}": {json.dumps(result_items[method], ensure_ascii=False)}' - if i < len(result_items) - 1: - line += "," - lines.append(line) - lines.append(' }') - - lines.append('}') - return "\n".join(lines) - - -def main(): - # 杈撳叆鍜岃緭鍑鸿矾寰 - input_dir = r"" # path - output_dir = r"" # path - - # 濡傛灉杈撳嚭鐩綍涓嶅瓨鍦紝鍒欏垱寤 - os.makedirs(output_dir, exist_ok=True) - - # 閬嶅巻杈撳叆鐩綍涓嬫墍鏈 .json 鏂囦欢 - for filename in os.listdir(input_dir): - if filename.endswith(".json"): - input_file_path = os.path.join(input_dir, filename) - output_file_path = os.path.join(output_dir, filename) - - with open(input_file_path, 'r', encoding='utf-8') as f: - try: - # 璇诲彇鍘熷 JSON 鏂囨湰鍐呭锛堜繚鐣欑粨鏋勶級 - original_content = f.read() - # 瑙f瀽涓哄瓧鍏哥敤浜庡鐞 - sample_data = json.loads(original_content) - except json.JSONDecodeError: - print(f"璺宠繃鏃犳晥鐨 JSON 鏂囦欢: {filename}") - continue - - conditions = sample_data["C"] - stored_hash = sample_data["L"] - - print(f"\n姝e湪澶勭悊鏂囦欢: {filename}") - - pwd1, tries1 = crack_method1(conditions) - pwd2, tries2 = crack_method2(conditions) - pwd3, tries3 = crack_method3(conditions) - - lock = PasswordLock() - matched_passwords = [] - - for pwd in pwd1 + pwd2 + pwd3: - if pwd not in matched_passwords and lock.verify_password(pwd, stored_hash): - matched_passwords.append(pwd) - - first_match = matched_passwords[0] if matched_passwords else "" - - # 鏇存柊 JSON 鍐呭涓殑缁撴灉閮ㄥ垎 - result_update = { - "password": first_match, - "results": { - "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 []}, - "method3": {"tries": tries3, "password": list(map(int, first_match)) if first_match else []} - } - } - - # 鍔犺浇鍘熷鍐呭涓 dict 骞舵洿鏂板叧閿瓧娈 - data = json.loads(original_content) - data.update(result_update) - - # 浣跨敤鑷畾涔夋牸寮忓寲鍑芥暟鐢熸垚 JSON 瀛楃涓 - formatted_json = format_json(data) - - # 鍐欏叆鏂囦欢 - with open(output_file_path, 'w', encoding='utf-8') as f: - f.write(formatted_json) - - print(f"缁撴灉宸蹭繚瀛樿嚦: {output_file_path}") - - -if __name__ == "__main__": +import os +import json +from Lock import PasswordLock + + +def is_prime(n): + """鍒ゆ柇涓涓暟瀛楁槸鍚︽槸绱犳暟""" + if n < 2: + return False + for i in range(2, int(n ** 0.5) + 1): + if n % i == 0: + return False + return True + + +def satisfies_prime_unique_condition(digits): + """妫鏌ユ槸鍚︽弧瓒砙-1, -1]鏉′欢锛氭瘡浣嶅瘑鐮佷负绱犳暟涓斾笉閲嶅""" + return all(is_prime(d) for d in digits) and len(set(digits)) == 3 + + +def crack_method1(conditions): + """浠庨珮浣嶅埌浣庝綅鍥炴函锛堢涓浣嶁啋绗簩浣嶁啋绗笁浣嶏級""" + possible_passwords = [] + tries = 0 + + def backtrack(index, current_digits): + nonlocal tries + tries += 1 + if index == 3: + for condition in conditions: + if condition == [-1, -1]: + if not satisfies_prime_unique_condition(current_digits): + return + elif len(condition) == 2: + a, t = condition + a = abs(a) + if 1 <= a <= 3: + if t == 0 and current_digits[a - 1] % 2 != 0: + return + elif t == 1 and current_digits[a - 1] % 2 != 1: + return + else: + return + elif len(condition) == 3: + b1, b2, b3 = condition + if b1 != -1 and current_digits[0] != b1: + return + if b2 != -1 and current_digits[1] != b2: + return + if b3 != -1 and current_digits[2] != b3: + return + possible_passwords.append("".join(map(str, current_digits))) + return + + for digit in range(10): + if index == 0: + has_fixed_value = any(len(cond) == 3 and cond[0] != -1 for cond in conditions) + if has_fixed_value: + fixed_values = [cond[0] for cond in conditions if len(cond) == 3 and cond[0] != -1] + if digit not in fixed_values: + continue + elif index == 1: + has_fixed_value = any(len(cond) == 3 and cond[1] != -1 for cond in conditions) + if has_fixed_value: + fixed_values = [cond[1] for cond in conditions if len(cond) == 3 and cond[1] != -1] + if digit not in fixed_values: + continue + elif index == 2: + has_fixed_value = any(len(cond) == 3 and cond[2] != -1 for cond in conditions) + if has_fixed_value: + fixed_values = [cond[2] for cond in conditions if len(cond) == 3 and cond[2] != -1] + if digit not in fixed_values: + continue + current_digits.append(digit) + backtrack(index + 1, current_digits) + current_digits.pop() + + backtrack(0, []) + return possible_passwords, tries + + +def crack_method2(conditions): + """浠庣浜屼綅寮濮嬪洖婧紙绗簩浣嶁啋绗笁浣嶁啋绗竴浣嶏級""" + possible_passwords = [] + tries = 0 + + def backtrack(index, current_digits): + nonlocal tries + tries += 1 + if index == 3: + reordered = [current_digits[2], current_digits[0], current_digits[1]] + for condition in conditions: + if condition == [-1, -1]: + if not satisfies_prime_unique_condition(reordered): + return + elif len(condition) == 2: + a, t = condition + a = abs(a) + if 1 <= a <= 3: + if t == 0 and reordered[a - 1] % 2 != 0: + return + elif t == 1 and reordered[a - 1] % 2 != 1: + return + else: + return + elif len(condition) == 3: + b1, b2, b3 = condition + if b1 != -1 and reordered[0] != b1: + return + if b2 != -1 and reordered[1] != b2: + return + if b3 != -1 and reordered[2] != b3: + return + possible_passwords.append("".join(map(str, reordered))) + return + + for digit in range(10): + if index == 0: # 绗簩浣 + has_fixed_value = any(len(cond) == 3 and cond[1] != -1 for cond in conditions) + if has_fixed_value: + fixed_values = [cond[1] for cond in conditions if len(cond) == 3 and cond[1] != -1] + if digit not in fixed_values: + continue + elif index == 1: # 绗笁浣 + has_fixed_value = any(len(cond) == 3 and cond[2] != -1 for cond in conditions) + if has_fixed_value: + fixed_values = [cond[2] for cond in conditions if len(cond) == 3 and cond[2] != -1] + if digit not in fixed_values: + continue + elif index == 2: # 绗竴浣 + has_fixed_value = any(len(cond) == 3 and cond[0] != -1 for cond in conditions) + if has_fixed_value: + fixed_values = [cond[0] for cond in conditions if len(cond) == 3 and cond[0] != -1] + if digit not in fixed_values: + continue + current_digits.append(digit) + backtrack(index + 1, current_digits) + current_digits.pop() + + backtrack(0, []) + return possible_passwords, tries + + +def crack_method3(conditions): + """浠庣涓変綅寮濮嬪洖婧紙绗笁浣嶁啋绗竴浣嶁啋绗簩浣嶏級""" + possible_passwords = [] + tries = 0 + + def backtrack(index, current_digits): + nonlocal tries + tries += 1 + if index == 3: + reordered = [current_digits[1], current_digits[2], current_digits[0]] + for condition in conditions: + if condition == [-1, -1]: + if not satisfies_prime_unique_condition(reordered): + return + elif len(condition) == 2: + a, t = condition + a = abs(a) + if 1 <= a <= 3: + if t == 0 and reordered[a - 1] % 2 != 0: + return + elif t == 1 and reordered[a - 1] % 2 != 1: + return + else: + return + elif len(condition) == 3: + b1, b2, b3 = condition + if b1 != -1 and reordered[0] != b1: + return + if b2 != -1 and reordered[1] != b2: + return + if b3 != -1 and reordered[2] != b3: + return + possible_passwords.append("".join(map(str, reordered))) + return + + for digit in range(10): + if index == 0: # 绗笁浣 + has_fixed_value = any(len(cond) == 3 and cond[2] != -1 for cond in conditions) + if has_fixed_value: + fixed_values = [cond[2] for cond in conditions if len(cond) == 3 and cond[2] != -1] + if digit not in fixed_values: + continue + elif index == 1: # 绗竴浣 + has_fixed_value = any(len(cond) == 3 and cond[0] != -1 for cond in conditions) + if has_fixed_value: + fixed_values = [cond[0] for cond in conditions if len(cond) == 3 and cond[0] != -1] + if digit not in fixed_values: + continue + elif index == 2: # 绗簩浣 + has_fixed_value = any(len(cond) == 3 and cond[1] != -1 for cond in conditions) + if has_fixed_value: + fixed_values = [cond[1] for cond in conditions if len(cond) == 3 and cond[1] != -1] + if digit not in fixed_values: + continue + current_digits.append(digit) + backtrack(index + 1, current_digits) + current_digits.pop() + + backtrack(0, []) + return possible_passwords, tries + + +def format_json(data): + """鑷畾涔 JSON 鏍煎紡鍖栧嚱鏁""" + lines = ['{'] + + # 鏍煎紡鍖 C 绾跨储閮ㄥ垎 + if "C" in data: + lines.append(' "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(' ],') + + # 鏍煎紡鍖 L 鍝堝笇鍊 + if "L" in data: + lines.append(f' "L": {json.dumps(data["L"], ensure_ascii=False)},') + + # 鏍煎紡鍖 password + if "password" in data: + lines.append(f' "password": {json.dumps(data["password"], ensure_ascii=False)},') + + # 鏍煎紡鍖 results + if "results" in data: + lines.append(' "results": {') + result_items = data["results"] + method_names = list(result_items.keys()) + for i, method in enumerate(method_names): + line = f' "{method}": {json.dumps(result_items[method], ensure_ascii=False)}' + if i < len(result_items) - 1: + line += "," + lines.append(line) + lines.append(' }') + + lines.append('}') + return "\n".join(lines) + + +def main(): + # 杈撳叆鍜岃緭鍑鸿矾寰 + input_dir = r"" # path + output_dir = r"" # path + + # 濡傛灉杈撳嚭鐩綍涓嶅瓨鍦紝鍒欏垱寤 + os.makedirs(output_dir, exist_ok=True) + + # 閬嶅巻杈撳叆鐩綍涓嬫墍鏈 .json 鏂囦欢 + for filename in os.listdir(input_dir): + if filename.endswith(".json"): + input_file_path = os.path.join(input_dir, filename) + output_file_path = os.path.join(output_dir, filename) + + with open(input_file_path, 'r', encoding='utf-8') as f: + try: + # 璇诲彇鍘熷 JSON 鏂囨湰鍐呭锛堜繚鐣欑粨鏋勶級 + original_content = f.read() + # 瑙f瀽涓哄瓧鍏哥敤浜庡鐞 + sample_data = json.loads(original_content) + except json.JSONDecodeError: + print(f"璺宠繃鏃犳晥鐨 JSON 鏂囦欢: {filename}") + continue + + conditions = sample_data["C"] + stored_hash = sample_data["L"] + + print(f"\n姝e湪澶勭悊鏂囦欢: {filename}") + + pwd1, tries1 = crack_method1(conditions) + pwd2, tries2 = crack_method2(conditions) + pwd3, tries3 = crack_method3(conditions) + + lock = PasswordLock() + matched_passwords = [] + + for pwd in pwd1 + pwd2 + pwd3: + if pwd not in matched_passwords and lock.verify_password(pwd, stored_hash): + matched_passwords.append(pwd) + + first_match = matched_passwords[0] if matched_passwords else "" + + # 鏇存柊 JSON 鍐呭涓殑缁撴灉閮ㄥ垎 + result_update = { + "password": first_match, + "results": { + "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 []}, + "method3": {"tries": tries3, "password": list(map(int, first_match)) if first_match else []} + } + } + + # 鍔犺浇鍘熷鍐呭涓 dict 骞舵洿鏂板叧閿瓧娈 + data = json.loads(original_content) + data.update(result_update) + + # 浣跨敤鑷畾涔夋牸寮忓寲鍑芥暟鐢熸垚 JSON 瀛楃涓 + formatted_json = format_json(data) + + # 鍐欏叆鏂囦欢 + with open(output_file_path, 'w', encoding='utf-8') as f: + f.write(formatted_json) + + print(f"缁撴灉宸蹭繚瀛樿嚦: {output_file_path}") + + +if __name__ == "__main__": main() \ No newline at end of file diff --git a/readme.md b/readme.md index 79cfb31..ea761e2 100644 --- a/readme.md +++ b/readme.md @@ -1,100 +1,100 @@ -# 绠楁硶椹卞姩鐨勮糠瀹帰闄╂父鎴忓紑鍙 - -## 璁捐鐩爣 - -***\*鍦板浘锛歕**** - -涓涓簩缁寸煩闃碉紝閲団饯鍒嗘不娉曗剑鎴愶紝饨嗗饨村尯鍩燂紝瀛樺湪鍞紑閫氳矾銆 - -杈撯紛锛氳糠瀹昂饧 銆 - -杈撳嚭锛氳糠瀹煩闃碉紙鍙瓨鍌ㄤ负JSON鎴朇SV锛夛紝鍖呮嫭璧风偣Start锛圫锛夈 缁堢偣Exit锛圗锛夈佸澹侊紙#锛夈侀氳矾锛堢┖鏍硷級銆佽祫婧愶紙渚嬪饩﹀竵G锛夈 闄烽槺Trap锛圱锛夈佹満鍏矻ocker锛圠锛夈丅OSS锛圔锛夈 - - - -澧欏锛氫笉鍙氳繃锛屾棤value鐨勮妭鐐 - -閫氳矾锛氬彲閫氳繃锛屾棤value鐨勮妭鐐 - -閲戝竵锛氬彲閫氳繃锛屾湁value 鐨勮妭鐐广侭OSS鎴樻椂鐨勮鍔ㄩ渶瑕佹秷鑰楅噾甯 - -闄烽槺锛氬彲閫氳繃锛屼絾缁忚繃鏃朵細鎵i櫎鐜╁鐨勯噾甯 - -鏈哄叧锛氫笁浣嶅瘑鐮侀攣銆備竴鑸垎甯冨湪鏌愭潯璺殑灏藉ご锛屽繀椤诲紑鍚墍鏈夋満鍏冲悗锛岀粓鐐瑰ぇ闂ㄦ墠浼氭墦寮 - -BOSS锛氬湪蹇呯粡涔嬭矾涓婏紝鏈塿alue(琛閲) , 蹇呴』鎵撹触鎵嶈兘缁х画鍓嶈繘 - - - - - -***\*鐜╁锛歕**** - -鏈変笁绉嶆敾鍑绘柟寮忥紙鍒濆鍏呰兘涓0锛夛細 - -A锛氭秷鑰2鏋氶噾甯侀犳垚1鐐逛激瀹冲苟鑾峰緱1鐐瑰厖鑳 - -E锛氭秷鑰3鏋氶噾甯侀犳垚3鐐逛激瀹冲苟鑾峰緱1鐐瑰厖鑳斤紝杩炵画绗笁娆′娇鐢‥鎶鑳芥椂灏戞秷鑰1鏋氶噾甯 - -Q锛氭秷鑰3鏋氶噾甯佸拰3鐐瑰厖鑳斤紝閫犳垚8鐐逛激瀹 - - - -## 浠诲姟鍒嗚В - -### 1. 鍒嗘不娉曠敓鎴愯糠瀹 - -**闇姹 : ** - -杈撳叆 : 姝f暣鏁 n( 100>=n>=7 ) , 鐢熸垚绫诲瀷閫夋嫨(json鎴栬卌sv) - -杈撳嚭 : json鏂囦欢 , csv鏂囦欢 , 琛ㄧず鍦板浘 , 鏃犲绔嬪尯 , 瀛樺湪鍞竴閫氳矾 - -S : 璧风偣 - -E : 缁堢偣 - -\# :澧欏 - -blank : 閫氳矾 - -G : 璧勬簮 - -T : 闄烽槺 - -L : 鏈哄叧 - -B : Boss - -**閫掑綊鍒嗗壊娉曠敓鎴愯糠瀹** - - - - - - - -### 2. 鍔ㄦ佽鍒掕繘琛岃祫婧愭敹闆嗚矾寰勮鍒 - - - - - -### 3. 璐績绠楁硶璁捐瀹炴椂璧勬簮鎷惧彇绛栫暐 - - - - - -### 4. 鍥炴函娉曡В杩峰叧鍗 - - - - - -### 5. 鍒嗘敮闄愮晫璁捐boss鎴 - - - - - +# 绠楁硶椹卞姩鐨勮糠瀹帰闄╂父鎴忓紑鍙 + +## 璁捐鐩爣 + +***\*鍦板浘锛歕**** + +涓涓簩缁寸煩闃碉紝閲団饯鍒嗘不娉曗剑鎴愶紝饨嗗饨村尯鍩燂紝瀛樺湪鍞紑閫氳矾銆 + +杈撯紛锛氳糠瀹昂饧 銆 + +杈撳嚭锛氳糠瀹煩闃碉紙鍙瓨鍌ㄤ负JSON鎴朇SV锛夛紝鍖呮嫭璧风偣Start锛圫锛夈 缁堢偣Exit锛圗锛夈佸澹侊紙#锛夈侀氳矾锛堢┖鏍硷級銆佽祫婧愶紙渚嬪饩﹀竵G锛夈 闄烽槺Trap锛圱锛夈佹満鍏矻ocker锛圠锛夈丅OSS锛圔锛夈 + + + +澧欏锛氫笉鍙氳繃锛屾棤value鐨勮妭鐐 + +閫氳矾锛氬彲閫氳繃锛屾棤value鐨勮妭鐐 + +閲戝竵锛氬彲閫氳繃锛屾湁value 鐨勮妭鐐广侭OSS鎴樻椂鐨勮鍔ㄩ渶瑕佹秷鑰楅噾甯 + +闄烽槺锛氬彲閫氳繃锛屼絾缁忚繃鏃朵細鎵i櫎鐜╁鐨勯噾甯 + +鏈哄叧锛氫笁浣嶅瘑鐮侀攣銆備竴鑸垎甯冨湪鏌愭潯璺殑灏藉ご锛屽繀椤诲紑鍚墍鏈夋満鍏冲悗锛岀粓鐐瑰ぇ闂ㄦ墠浼氭墦寮 + +BOSS锛氬湪蹇呯粡涔嬭矾涓婏紝鏈塿alue(琛閲) , 蹇呴』鎵撹触鎵嶈兘缁х画鍓嶈繘 + + + + + +***\*鐜╁锛歕**** + +鏈変笁绉嶆敾鍑绘柟寮忥紙鍒濆鍏呰兘涓0锛夛細 + +A锛氭秷鑰2鏋氶噾甯侀犳垚1鐐逛激瀹冲苟鑾峰緱1鐐瑰厖鑳 + +E锛氭秷鑰3鏋氶噾甯侀犳垚3鐐逛激瀹冲苟鑾峰緱1鐐瑰厖鑳斤紝杩炵画绗笁娆′娇鐢‥鎶鑳芥椂灏戞秷鑰1鏋氶噾甯 + +Q锛氭秷鑰3鏋氶噾甯佸拰3鐐瑰厖鑳斤紝閫犳垚8鐐逛激瀹 + + + +## 浠诲姟鍒嗚В + +### 1. 鍒嗘不娉曠敓鎴愯糠瀹 + +**闇姹 : ** + +杈撳叆 : 姝f暣鏁 n( 100>=n>=7 ) , 鐢熸垚绫诲瀷閫夋嫨(json鎴栬卌sv) + +杈撳嚭 : json鏂囦欢 , csv鏂囦欢 , 琛ㄧず鍦板浘 , 鏃犲绔嬪尯 , 瀛樺湪鍞竴閫氳矾 + +S : 璧风偣 + +E : 缁堢偣 + +\# :澧欏 + +blank : 閫氳矾 + +G : 璧勬簮 + +T : 闄烽槺 + +L : 鏈哄叧 + +B : Boss + +**閫掑綊鍒嗗壊娉曠敓鎴愯糠瀹** + + + + + + + +### 2. 鍔ㄦ佽鍒掕繘琛岃祫婧愭敹闆嗚矾寰勮鍒 + + + + + +### 3. 璐績绠楁硶璁捐瀹炴椂璧勬簮鎷惧彇绛栫暐 + + + + + +### 4. 鍥炴函娉曡В杩峰叧鍗 + + + + + +### 5. 鍒嗘敮闄愮晫璁捐boss鎴 + + + + +