forked from LingFeng-bbben/MajdataEdit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Mirror.cs
306 lines (277 loc) · 9.99 KB
/
Mirror.cs
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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
using System.Text;
using System.Text.RegularExpressions;
namespace MajdataEdit;
//小额负责的部分哟
internal static class Mirror
{
public enum HandleType
{
LRMirror,
UDMirror,
HalfRotation,
Rotation45,
CcwRotation45
}
private static readonly Dictionary<char, char> MIRROR_LEFT_RIGHT_MAP = new()
{
{ '1', '8' },
{ '2', '7' },
{ '3', '6' },
{ '4', '5' },
{ '5', '4' },
{ '6', '3' },
{ '7', '2' },
{ '8', '1' },
{ 'q', 'p' },
{ 'p', 'q' },
{ '<', '>' },
{ '>', '<' },
{ 'z', 's' },
{ 's', 'z' }
};
// 当遇到这些字符时 使用特殊的映射表
private static readonly HashSet<char> MIRROR_SPECIAL_PREFIX = new() { 'D', 'E' };
private static readonly Dictionary<char, char> MIRROR_LEFT_RIGHT_SPECIAL_MAP = new()
{
{ '8', '2' },
{ '2', '8' },
{ '3', '7' },
{ '7', '3' },
{ '4', '6' },
{ '6', '4' },
{ '1', '1' },
{ '5', '5' }
};
private static readonly Dictionary<char, char> MIRROR_UPSIDE_DOWN_MAP = new()
{
{ '4', '1' },
{ '5', '8' },
{ '6', '7' },
{ '3', '2' },
{ '7', '6' },
{ '2', '3' },
{ '8', '5' },
{ '1', '4' },
{ 'q', 'p' },
{ 'p', 'q' },
{ 'z', 's' },
{ 's', 'z' }
};
private static readonly Dictionary<char, char> MIRROR_UPSIDE_DOWN_SPECIAL_MAP = new()
{
{ '4', '2' },
{ '2', '4' },
{ '1', '5' },
{ '5', '1' },
{ '8', '6' },
{ '6', '8' },
{ '3', '3' },
{ '7', '7' }
};
private static readonly Dictionary<char, char> ROTATE_CW_45_MAP = new()
{
{ '8', '1' },
{ '7', '8' },
{ '6', '7' },
{ '5', '6' },
{ '4', '5' },
{ '3', '4' },
{ '2', '3' },
{ '1', '2' }
};
private static readonly Dictionary<char, char> ROTATE_CCW_45_MAP = new()
{
{ '1', '8' },
{ '2', '1' },
{ '3', '2' },
{ '4', '3' },
{ '5', '4' },
{ '6', '5' },
{ '7', '6' },
{ '8', '7' }
};
private static readonly HashSet<char> ROTATE_CW_45_SPECIAL_PREFIX = new() { '2', '6' };
private static readonly HashSet<char> ROTATE_CCW_45_SPECIAL_PREFIX = new() { '3', '7' };
private static readonly Dictionary<char, char> ROTATE_45_SPECIAL_MAP = new()
{
{ '<', '>' },
{ '>', '<' }
};
private static readonly string HS_SEQUENCE = "<HS*";
public static string NoteMirrorHandle(string str, HandleType type)
{
// NOTE: 类似 1-5[8:1]{16}, 这样的字符串 可以被SimaiProcess处理 但无法被正确镜像
// 我认为这是对的 因为这种语法本身就是错误的 只不过SimaiProcess没有做处理而已 不能因此而妥协 以上
StringBuilder resultString = new StringBuilder(); // 最终的结果
StringBuilder curPart = new StringBuilder(); // 当前的一部分
bool isPartIgnored = false; // 当前部分是否需要被忽略
int hsStatus = 0; // 当前部分是否是HS语法的一部分 0-未检测到 1-检测到< 2-检测到H 3-检测到S 4-检测到* 必须按照01234的顺序走完才算HS 否则不算
// 空白字符会被正常加入每一个part 因此应当在子方法中进行忽略处理 这是为了保持空白字符位置不变
foreach (char c in str)
{
curPart.Append(c);
// 如果存在以下字符 则本部分一定是被忽略的
if (!isPartIgnored && (c == '{' || c == '}' || c == '(' || c == ')'))
{
isPartIgnored = true;
}
if (hsStatus == 0)
{
if (HS_SEQUENCE[0] == c)
{
// 检查到了疑似HS语法的开头 开始检查接下来的字符
hsStatus = 1;
}
}
else if (hsStatus != HS_SEQUENCE.Length)
{
// 如果hsStatus不是0 说明已经开始检查了 那么接下来就必须严格紧凑地检查到剩余的HS语法字符
// 当然 空白字符不算
if (!Char.IsWhiteSpace(c))
{
if (HS_SEQUENCE[hsStatus] == c)
{
// 符合 则步进
hsStatus++;
if (hsStatus == HS_SEQUENCE.Length)
{
// 检查到结尾了 则肯定是一个hs结构了
isPartIgnored = true;
}
}
else
{
// 不符合 说明这不是一个HS结构 则归零重新开始探索
hsStatus = 0;
}
}
}
// 以下字符表示本part结束
if (c == '}' || c == ')' || c == ',' || c == '/' || c == '`' ||
(hsStatus == 4 && c == '>'))
{
if (isPartIgnored)
{
// 需要忽略的段落 直接原样加进去就行了
resultString.Append(curPart.ToString());
}
else
{
// 需要镜像计算的段落 调用子方法进行转换
resultString.Append(NoteMirrorPart(curPart.ToString(), type));
}
isPartIgnored = false;
hsStatus = 0;
curPart.Clear();
}
}
// 处理完以后可能还会有剩余的没做转换(可能结尾的逗号没选进去) 也要处理一下
if (curPart.Length > 0)
{
if (isPartIgnored)
{
// 需要忽略的段落 直接原样加进去就行了
resultString.Append(curPart.ToString());
}
else
{
// 需要镜像计算的段落 调用子方法进行转换
resultString.Append(NoteMirrorPart(curPart.ToString(), type));
}
}
return resultString.ToString();
}
private static string NoteMirrorPart(string str, HandleType type)
{
switch (type)
{
case HandleType.LRMirror:
str = NormalMirrorPart(str, MIRROR_LEFT_RIGHT_MAP, MIRROR_LEFT_RIGHT_SPECIAL_MAP, MIRROR_SPECIAL_PREFIX);
break;
case HandleType.UDMirror:
str = NormalMirrorPart(str, MIRROR_UPSIDE_DOWN_MAP, MIRROR_UPSIDE_DOWN_SPECIAL_MAP, MIRROR_SPECIAL_PREFIX);
break;
case HandleType.HalfRotation:
// 180 = 左右+上下
str = NormalMirrorPart(str, MIRROR_LEFT_RIGHT_MAP, MIRROR_LEFT_RIGHT_SPECIAL_MAP, MIRROR_SPECIAL_PREFIX);
str = NormalMirrorPart(str, MIRROR_UPSIDE_DOWN_MAP, MIRROR_UPSIDE_DOWN_SPECIAL_MAP, MIRROR_SPECIAL_PREFIX);
break;
case HandleType.Rotation45:
str = NormalMirrorPart(str, ROTATE_CW_45_MAP, ROTATE_45_SPECIAL_MAP, ROTATE_CW_45_SPECIAL_PREFIX);
break;
case HandleType.CcwRotation45:
str = NormalMirrorPart(str, ROTATE_CCW_45_MAP, ROTATE_45_SPECIAL_MAP, ROTATE_CCW_45_SPECIAL_PREFIX);
break;
}
return str;
}
private static string NormalMirrorPart(string str, Dictionary<char, char> normalMap, Dictionary<char, char> specialMap, HashSet<char> specialPrefix)
{
StringBuilder result = new StringBuilder();
bool isSpecialPrefix = false;
bool isInBracket = false;
foreach (char c in str)
{
// 空白字符忽略
if (Char.IsWhiteSpace(c))
{
result.Append(c);
continue;
}
// 以下是处理字符的部分
if (isInBracket || c == '[')
{
// 进入方括号时忽略 因为这里是时长之类的设置
// 注意当前字符为'['的时候也进入此分支 因为此时isInBrancket还是false 需要等到下面那个if块才会变
result.Append(c);
}
else if (isSpecialPrefix)
{
// 如果前面读到一个D或者E 则使用特殊的映射
isSpecialPrefix = false;
if (specialMap.ContainsKey(c))
{
result.Append(specialMap[c]);
}
else if (int.TryParse(c.ToString(), out int i) && normalMap.ContainsKey(c))
{
result.Append(normalMap[c]);
}
else
{
result.Append(c);
}
}
else
{
// 其他情况 则使用默认映射
if (normalMap.ContainsKey(c))
{
result.Append(normalMap[c]);
}
else
{
result.Append(c);
}
}
// 以下是记录状态的部分
// 记录是否进入了方括号内(即时间)
if (c == '[')
{
isInBracket = true;
}
else if (c == ']')
{
isInBracket = false;
}
// 记录是否是一个特殊前缀 若是 则下面的字符需要使用特别的映射
// 在左右或上下镜像中,用于D、E区Touch的特殊处理
// 在45旋转中,本意是对Simai的弱智">","<"进行特殊处理,但没有判断本Note是否为Tap
if (specialPrefix.Contains(c))
{
isSpecialPrefix = true;
}
}
return result.ToString();
}
}