-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcard_to_python.py
More file actions
234 lines (188 loc) · 7.59 KB
/
Copy pathcard_to_python.py
File metadata and controls
234 lines (188 loc) · 7.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
"""
卡牌命令翻译为Python代码的CLI工具
支持将GCodes格式的卡牌命令自动转换为Python代码
并智能识别from子句,自动将choose转换为target_field
"""
import argparse
import re
import sys
from typing import Optional
# 需要自动转换的区域列表
TARGET_FIELD_AREAS = ['allyRows', 'enemyRows', 'battleGround']
def parse_card_command(gcode: str) -> str:
"""
解析GCodes格式的卡牌命令并转换为Python代码
Args:
gcode: GCodes格式的原始字符串
Returns:
转换后的Python代码字符串
"""
lines = gcode.strip().split('\n')
result = []
indent_level = 0
for line in lines:
# 跳过空行
if not line.strip():
result.append('')
continue
# 计算缩进
stripped_line = line.lstrip()
current_indent = len(line) - len(stripped_line)
# 处理Command[...]行
if stripped_line.startswith('Command['):
# 提取[]中的内容作为函数名
match = re.match(r'Command\[(.*?)\]', stripped_line)
if match:
func_name = match.group(1)
# 将self替换为更合适的函数名
if func_name == 'self':
func_name = 'Order1'
result.append(f"async def {func_name}(event):")
indent_level = 1
else:
result.append(stripped_line)
# 处理choose语句
elif stripped_line.startswith('choose'):
# 解析choose语句
python_line = parse_choose_statement(stripped_line)
result.append(' ' * indent_level + python_line)
# 处理其他语句
else:
# 调整缩进 level
if current_indent > 0:
# 保持相对缩进
relative_indent = current_indent // 4 # 假设4个空格为一个缩进级别
result.append(' ' * relative_indent + stripped_line)
else:
result.append(stripped_line)
return '\n'.join(result)
def parse_choose_statement(line: str) -> str:
"""
解析choose语句并根据from子句决定使用choose还是target_field
Args:
line: 原始choose语句
Returns:
转换后的Python语句
"""
# 匹配choose语句的正则表达式
# 格式: choose 1 from enemyRows[Unit] as target:
# 或: choose 1 from enemyRows as target:
# 尝试匹配完整的choose语句
pattern = r'choose\s+(\d+)\s+from\s+([\w\.]+)(?:\[[\w]+\])?\s+as\s+(\w+)'
match = re.match(pattern, line.strip().rstrip(':'))
if match:
num = match.group(1)
from_area = match.group(2)
var_name = match.group(3)
# 智能检测:如果是 allyRows, enemyRows, battleGround 之一,使用 target_field
if from_area in TARGET_FIELD_AREAS:
return f"target = await self_reference.await_target({from_area}, {num}, {num})"
else:
# 其他情况使用原来的choose逻辑
return f"target = await choose({from_area}, {var_name})"
# 如果不匹配,返回原行
return line
def convert_gcode_to_python(gcode: str, add_imports: bool = True) -> str:
"""
将GCodes格式转换为完整的Python代码
Args:
gcode: GCodes格式的字符串
add_imports: 是否添加导入语句
Returns:
完整的Python代码字符串
"""
# 首先解析命令
parsed = parse_card_command(gcode)
lines = parsed.split('\n')
result = []
current_var_name = None # 当前choose语句使用的变量名
# 添加导入语句
if add_imports:
result.append("from ServerUtils import *")
result.append("import ServerUtils")
result.append("")
# 处理解析后的代码
for i, line in enumerate(lines):
# 处理函数定义行,添加async
if line.startswith('async def'):
# 提取函数名
match = re.match(r'async def (\w+)\(event\):', line)
if match:
func_name = match.group(1)
result.append(f"async def {func_name}(event):")
result.append(' """卡牌效果函数"""')
# 重置变量名
current_var_name = None
else:
result.append(line)
elif line.startswith('target = await self_reference.await_target'):
# 已经转换为target_field的情况,变量名是target
current_var_name = 'target'
result.append(line)
elif line.startswith('target = await choose'):
# 保持原有的choose调用,但需要提取变量名
match = re.search(r'choose\([^,]+,\s*(\w+)\)', line)
if match:
current_var_name = match.group(1)
# 将target替换为正确的变量名
result.append(line.replace('target = ', f'{current_var_name} = '))
else:
result.append(line)
else:
# 处理缩进块中的语句,尝试修复变量名
if current_var_name and current_var_name != 'target':
# 将所有target替换为实际的变量名
line = re.sub(r'\btarget\b', current_var_name, line)
result.append(line)
return '\n'.join(result)
def process_file(input_path: str, output_path: Optional[str] = None) -> str:
"""
处理文件并转换代码
Args:
input_path: 输入文件路径
output_path: 输出文件路径,如果为None则返回字符串
Returns:
转换后的代码字符串(如果output_path为None)
"""
with open(input_path, 'r', encoding='utf-8') as f:
gcode = f.read()
python_code = convert_gcode_to_python(gcode)
if output_path:
with open(output_path, 'w', encoding='utf-8') as f:
f.write(python_code)
print(f"已成功转换并保存到: {output_path}")
return python_code
def main():
"""主函数:命令行入口"""
parser = argparse.ArgumentParser(
description='将GCodes格式的卡牌命令翻译为Python代码',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog='''
示例用法:
python card_to_python.py input.txt # 转换并输出到控制台
python card_to_python.py input.txt output.py # 转换并保存到文件
python card_to_python.py -i input.txt -o out.py --no-imports # 不添加导入语句
支持的from区域:
- allyRows, enemyRows, battleGround → 自动使用 target_field
- 其他区域 → 使用传统的 choose
'''
)
parser.add_argument('input', help='输入文件路径(GCodes格式)')
parser.add_argument('-o', '--output', help='输出文件路径(Python代码)', default=None)
parser.add_argument('--no-imports', action='store_true',
help='不添加默认的导入语句(from ServerUtils import *)')
args = parser.parse_args()
try:
# 处理文件
python_code = process_file(args.input, args.output)
# 如果没有指定输出文件,打印到控制台
if not args.output:
print(python_code)
except FileNotFoundError:
print(f"错误: 文件 '{args.input}' 不存在", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"错误: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == '__main__':
main()