InternBootcamp/internbootcamp/libs/wordladder/solver_main.py
2025-05-23 15:27:15 +08:00

324 lines
No EOL
13 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import sys
from libs.wordladder.solving.puzzle import Puzzle
from libs.wordladder.solving.solver import Solver
from libs.wordladder.words.dictionary import Dictionary
from libs.wordladder.words.word import Word
from libs.wordladder.interactive import Interactive
from time import perf_counter
import json
def solver_main():
if len(sys.argv) > 2:
solve(sys.argv[1:])
else:
Interactive(sys.argv[1:]).run()
def solver_main2(param_data):
if len(sys.argv) > 0:
return solve2(sys.argv[1:],param_data)
else:
Interactive(sys.argv[1:]).run()
def solve(args):
first = args[0]
second = args[1]
if len(second) != len(first):
print('Start word \'%s\' and end word \'%s\' not the same length!' % (first, second))
sys.exit(-1)
start = perf_counter()
dictionary = Dictionary(len(first))
took = (perf_counter() - start) * 1000
print('Took %.2fms to load dictionary' % took)
start_word: Word = dictionary[first]
if start_word is None:
print('Start word \'%s\' not in dictionary' % first)
sys.exit(-1)
elif start_word.is_island:
print('Start word \'%s\' is an island word' % first)
sys.exit(-1)
end_word: Word = dictionary[second]
if end_word is None:
print('End word \'%s\' not in dictionary' % second)
sys.exit(-1)
elif end_word.is_island:
print('End word \'%s\' is an island word' % second)
sys.exit(-1)
puzzle: Puzzle = Puzzle(start_word, end_word)
max_ladder_length: int = -1
if len(args) > 2:
try:
max_ladder_length = int(args[2])
if max_ladder_length < 1:
raise ValueError
except ValueError:
print('Max ladder length arg must be an integer (greater than zero)')
sys.exit(-1)
else:
start = perf_counter()
min_ladder = puzzle.calculate_minimum_ladder_length()
took = (perf_counter() - start) * 1000
if min_ladder is None:
print('Cannot solve \'%s\' to \'%s\'' % (first, second))
sys.exit(-1)
max_ladder_length = min_ladder
print('Took %.2fms to determine minimum ladder length of %d' % (took, max_ladder_length))
solver = Solver(puzzle)
start = perf_counter()
solutions = solver.solve(max_ladder_length)
took = (perf_counter() - start) * 1000
if len(solutions) == 0:
print('Cannot solve \'%s\' to \'%s\' in ladder length %d (took %.2fms)' % (first, second, max_ladder_length, took))
sys.exit(-1)
slen = len(solutions)
print('Took %.2fms to find %d solutions (explored %d solutions)' % (took, slen, solver.explored_count))
solutions.sort()
for i in range(slen):
print('%d/%d %s' % (i + 1, slen, solutions[i]))
def solve2(args,param_data):
solutions_cnt = 0
current_ladder = 1
solutions_rounds = 0
first = param_data["start_word"]
second = param_data["end_word"]
if len(second) != len(first):
print('Start word \'%s\' and end word \'%s\' not the same length!' % (first, second))
sys.exit(-1)
start = perf_counter()
dictionary = Dictionary(len(first))
took = (perf_counter() - start) * 1000
print('Took %.2fms to load dictionary' % took)
start_word: Word = dictionary[first]
if start_word is None:
print('Start word \'%s\' not in dictionary' % first)
return save_to_file(param_data,None,code = 2)
sys.exit(-1)
elif start_word.is_island:
print('Start word \'%s\' is an island word' % first)
return save_to_file(param_data,None,code = 3)
sys.exit(-1)
end_word: Word = dictionary[second]
if end_word is None:
print('End word \'%s\' not in dictionary' % second)
return save_to_file(param_data,None,code = 4)
sys.exit(-1)
elif end_word.is_island:
print('End word \'%s\' is an island word' % second)
return save_to_file(param_data,None,code = 5)
sys.exit(-1)
puzzle: Puzzle = Puzzle(start_word, end_word)
max_ladder_length: int = -1
while(solutions_cnt<param_data["solutions"] ):
if len(args) > 2:
try:
max_ladder_length = current_ladder
if max_ladder_length < 1:
raise ValueError
except ValueError:
print('Max ladder length arg must be an integer (greater than zero)')
sys.exit(-1)
else:
start = perf_counter()
min_ladder = puzzle.calculate_minimum_ladder_length()
took = (perf_counter() - start) * 1000
if min_ladder is None:
print('Cannot solve \'%s\' to \'%s\'' % (first, second))
return save_to_file(param_data,solutions="", code = 6)
sys.exit(-1)
max_ladder_length = min_ladder + solutions_rounds
# print('Took %.2fms to determine minimum ladder length of %d' % (took, max_ladder_length))
if( max_ladder_length > param_data["max_ladder"] or max_ladder_length > 20):
print("max_ladder 超出限额")
break
solver = Solver(puzzle)
start = perf_counter()
# print("-- max_ladder_length (start solve):" + str(max_ladder_length))
solutions = solver.solve(max_ladder_length)
took = (perf_counter() - start) * 1000
if len(solutions) == 0:
print('Cannot solve \'%s\' to \'%s\' in ladder length %d (took %.2fms)' % (first, second, max_ladder_length, took))
sys.exit(-1)
slen = len(solutions)
solutions_rounds += 1
if slen < param_data["solutions"]:
print('Took %.2fms to find %d solutions (explored %d solutions)' % (took, slen, solver.explored_count))
print("not enough,pass to next ladder")
current_ladder += 1
max_ladder_length += 1
continue
else:
solutions_cnt += slen
print('Took %.2fms to find %d solutions (explored %d solutions)' % (took, slen, solver.explored_count))
solutions.sort()
for i in range(slen):
print('%d/%d %s' % (i + 1, slen, solutions[i]))
return save_to_file(param_data,solutions, code = 0)
sys.exit(-1)
return save_to_file(param_data,None,code = 1)
def save_to_file2(param_data, solutions , code):
# 获取前n个元素
# txt输出已弃用
is_nlp = param_data["is_nlp"]
filepath = param_data["output_filepath"]
n = param_data["solutions"]
with open(filepath, 'a', encoding='utf-8') as file:
if code == 0:
if is_nlp :
title = "在一次Word Ladder中,当start word是" + param_data["start_word"] + "end word是" + param_data["end_word"] + "时,至少可以得出以下" + str (n) + "条ladder路径"
else:
title = param_data["start_word"] + " " + param_data["end_word"]
file.write(title + '\n')
for i in range(n):
file.write(str(solutions[i]) + '\n')
elif code == 1:
if is_nlp :
title = "在一次Word Ladder中,当start word是" + param_data["start_word"] + "end word是" + param_data["end_word"] + "时,没能解出" + str (n) + "条ladder路径"
else:
title = param_data["start_word"] + " " + param_data["end_word"]
file.write(title + '\n')
elif code == 2:
if is_nlp :
title = "在一次Word Ladder中,当start word是" + param_data["start_word"] + "end word是" + param_data["end_word"] + "时,无法求解,因为" + param_data["start_word"] + "不在字典中"
else:
title = param_data["start_word"] + " " + param_data["end_word"]
file.write(title + '\n')
elif code == 3:
if is_nlp :
title = "在一次Word Ladder中,当start word是" + param_data["start_word"] + "end word是" + param_data["end_word"] + "时,无法求解,因为" + param_data["start_word"] + "是一个island word"
else:
title = param_data["start_word"] + " " + param_data["end_word"]
file.write(title + '\n')
elif code == 4:
if is_nlp :
title = "在一次Word Ladder中,当start word是" + param_data["start_word"] + "end word是" + param_data["end_word"] + "时,无法求解,因为" + param_data["end_word"] + "不在字典中"
else:
title = param_data["start_word"] + " " + param_data["end_word"]
file.write(title + '\n')
elif code == 5:
if is_nlp :
title = "在一次Word Ladder中,当start word是" + param_data["start_word"] + "end word是" + param_data["end_word"] + "时,无法求解,因为" + param_data["end_word"] + "是一个island word"
else:
title = param_data["start_word"] + " " + param_data["end_word"]
file.write(title + '\n')
elif code == 6:
if is_nlp :
title = "在一次Word Ladder中,当start word是" + param_data["start_word"] + "end word是" + param_data["end_word"] + "无法求解因为没有路径可以从start word到end word"
else:
title = param_data["start_word"] + " " + param_data["end_word"]
file.write(title + '\n')
else:
if is_nlp :
title = "【出现未知异常跳过此条训练数据1】"
else:
title = "error"
file.write(title + '\n')
def save_to_file(param_data, solutions, code):
is_nlp = param_data["is_nlp"]
filepath = param_data["output_filepath"]
start_word = param_data["start_word"]
end_word = param_data["end_word"]
n = param_data["solutions"]
# 定义基础描述
base_title = f"{start_word} {end_word}" if not is_nlp else f"在一次Word Ladder中,当start word是{start_word}end word是{end_word}时,"
# 处理不同的code
if code == 0:
describe = f"{base_title}至少可以得出以下{n}条ladder路径" if is_nlp else base_title
solutions_data = [str(solutions[i]) for i in range(n)] if solutions else []
describe = parse_word_ladder(solutions_data,start_word=start_word,end_word=end_word,n=n)
elif code == 1:
describe = f"{base_title}没能解出{n}条ladder路径" if is_nlp else base_title
solutions_data = "此题目无解"
elif code == 2:
describe = f"{base_title}无法求解,因为{start_word}不在字典中" if is_nlp else base_title
solutions_data = "此题目无解"
elif code == 3:
describe = f"{base_title}无法求解,因为{start_word}是一个island word" if is_nlp else base_title
solutions_data = "此题目无解"
elif code == 4:
describe = f"{base_title}无法求解,因为{end_word}不在字典中" if is_nlp else base_title
solutions_data = "此题目无解"
elif code == 5:
describe = f"{base_title}无法求解,因为{end_word}是一个island word" if is_nlp else base_title
solutions_data = "此题目无解"
elif code == 6:
describe = f"{base_title}无法求解因为没有路径可以从start word到end word" if is_nlp else base_title
solutions_data = "此题目无解"
else:
describe = "【出现未知异常跳过此条训练数据2】" if is_nlp else "error"
solutions_data = "此题目无解"
return solutions_data,describe
# 准备要写入的数据
record = {
"start_word": start_word,
"end_word": end_word,
"describe": describe,
"solutions": solutions_data
}
# 写入文件
with open(filepath, 'a', encoding='utf-8') as file:
file.write(json.dumps(record, ensure_ascii=False) + '\n')
def parse_word_ladder(data, start_word, end_word, n):
"""
解析 Word Ladder 数据为自然语言格式。
参数:
data (list of str): 包含每条路径的字符串列表。
start_word (str): 初始单词。
end_word (str): 结束单词。
n (int): 数据中路径的数量。
返回:
str: 格式化后的自然语言文本。
"""
nl_output = []
nl_output.append(f"在一次Word Ladder中{start_word}{end_word}至少可以得出以下{n}条ladder路径")
for i, path in enumerate(data[:n], start=1):
words = path.strip('[]').split(',')
words = [word.strip() for word in words]
changes = []
# 解析路径中的每步变化
for j in range(1, len(words)):
prev_word, curr_word = words[j - 1], words[j]
for k, (prev_char, curr_char) in enumerate(zip(prev_word, curr_word)):
if prev_char != curr_char:
changes.append(f"将第{k + 1}个字母由{prev_char}更换成{curr_char}")
# 构建路径描述
path_description = f"{i}条:{words[0]}" + ''.join([f"{change},得到{words[j]}" for j, change in enumerate(changes, start=1)])
nl_output.append(path_description + '')
return '\n'.join(nl_output)
# 完整的原solver
if __name__ == '__main__':
solver_main()