jkf 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,608 @@
1
+ module Jkf::Parser
2
+ module Kifuable
3
+ def parse_initialboard
4
+ s0 = s1 = @current_pos
5
+ if match_space != :failed
6
+ parse_nonls
7
+ s2 = parse_nl
8
+ @current_pos = s1 if s2 == :failed
9
+ else
10
+ @current_pos = s1
11
+ end
12
+ s2 = @current_pos
13
+ if match_str("+") != :failed
14
+ parse_nonls
15
+ @current_pos = s2 if parse_nl == :failed
16
+ else
17
+ @current_pos = s2
18
+ end
19
+ s4 = parse_ikkatsuline
20
+ if s4 != :failed
21
+ s3 = []
22
+ while s4 != :failed
23
+ s3 << s4
24
+ s4 = parse_ikkatsuline
25
+ end
26
+ else
27
+ s3 = :failed
28
+ end
29
+ if s3 != :failed
30
+ s4 = @current_pos
31
+ if match_str("+") != :failed
32
+ parse_nonls
33
+ @current_pos = s4 if parse_nl == :failed
34
+ else
35
+ @current_pos = s4
36
+ end
37
+ @reported_pos = s0
38
+ transform_initialboard(s3)
39
+ else
40
+ @current_pos = s0
41
+ :failed
42
+ end
43
+ end
44
+
45
+ def parse_ikkatsuline
46
+ s0 = @current_pos
47
+ if match_str("|") != :failed
48
+ s3 = parse_masu
49
+ if s3 != :failed
50
+ s2 = []
51
+ while s3 != :failed
52
+ s2 << s3
53
+ s3 = parse_masu
54
+ end
55
+ else
56
+ s2 = :failed
57
+ end
58
+ if s2 != :failed
59
+ if match_str("|") != :failed
60
+ s4 = parse_nonls!
61
+ if s4 != :failed
62
+ if parse_nl != :failed
63
+ @reported_pos = s0
64
+ s0 = s2
65
+ else
66
+ @current_pos = s0
67
+ s0 = :failed
68
+ end
69
+ else
70
+ @current_pos = s0
71
+ s0 = :failed
72
+ end
73
+ else
74
+ @current_pos = s0
75
+ s0 = :failed
76
+ end
77
+ else
78
+ @current_pos = s0
79
+ s0 = :failed
80
+ end
81
+ else
82
+ @current_pos = s0
83
+ s0 = :failed
84
+ end
85
+
86
+ s0
87
+ end
88
+
89
+ def parse_masu
90
+ s0 = @current_pos
91
+ s1 = parse_teban
92
+ if s1 != :failed
93
+ s2 = parse_piece
94
+ if s2 != :failed
95
+ @reported_pos = s0
96
+ s0 = { "color" => s1, "kind" => s2 }
97
+ else
98
+ @current_pos = s0
99
+ s0 = :failed
100
+ end
101
+ else
102
+ @current_pos = s0
103
+ s0 = :failed
104
+ end
105
+ if s0 == :failed
106
+ s0 = @current_pos
107
+ s1 = match_str(" ・")
108
+ if s1 != :failed
109
+ @reported_pos = s0
110
+ s1 = {}
111
+ end
112
+ s0 = s1
113
+ end
114
+
115
+ s0
116
+ end
117
+
118
+ def parse_teban
119
+ s0 = @current_pos
120
+ s1 = match_space
121
+ if s1 == :failed
122
+ s1 = match_str("+")
123
+ s1 = match_str("^") if s1 == :failed
124
+ end
125
+ if s1 != :failed
126
+ @reported_pos = s0
127
+ s1 = 0
128
+ end
129
+ s0 = s1
130
+ if s0 == :failed
131
+ s0 = @current_pos
132
+ s1 = match_str("v")
133
+ s1 = match_str("V") if s1 == :failed
134
+ if s1 != :failed
135
+ @reported_pos = s0
136
+ s1 = 1
137
+ end
138
+ s0 = s1
139
+ end
140
+ s0
141
+ end
142
+
143
+ def parse_pointer
144
+ s0 = @current_pos
145
+ s1 = match_str("&")
146
+ if s1 != :failed
147
+ s2 = parse_nonls
148
+ s3 = parse_nl
149
+ if s3 != :failed
150
+ s0 = [s1, s2, s3]
151
+ else
152
+ @current_pos = s0
153
+ s0 = :failed
154
+ end
155
+ else
156
+ @current_pos = s0
157
+ s0 = :failed
158
+ end
159
+ s0
160
+ end
161
+
162
+ def parse_piece
163
+ s0 = @current_pos
164
+ s1 = match_str("成")
165
+ s1 = "" if s1 == :failed
166
+ s2 = match_regexp(/^[歩香桂銀金角飛王玉と杏圭全馬竜龍]/)
167
+ if s2 != :failed
168
+ @reported_pos = s0
169
+ kind2csa(s1 + s2)
170
+ else
171
+ @current_pos = s0
172
+ :failed
173
+ end
174
+ end
175
+
176
+ def parse_result
177
+ s0 = @current_pos
178
+ if match_str("まで") != :failed
179
+ s2 = match_digits!
180
+ if s2 != :failed
181
+ if match_str("手") != :failed
182
+ s4 = @current_pos
183
+ if match_str("で") != :failed
184
+ if parse_turn != :failed
185
+ if match_str("手の") != :failed
186
+ s8 = parse_result_toryo
187
+ s8 = parse_result_illegal if s8 == :failed
188
+ s4 = if s8 != :failed
189
+ @reported_pos = s4
190
+ s8
191
+ else
192
+ @current_pos = s4
193
+ :failed
194
+ end
195
+ else
196
+ @current_pos = s4
197
+ s4 = :failed
198
+ end
199
+ else
200
+ @current_pos = s4
201
+ s4 = :failed
202
+ end
203
+ else
204
+ @current_pos = s4
205
+ s4 = :failed
206
+ end
207
+ if s4 == :failed
208
+ s4 = parse_result_timeup
209
+ if s4 == :failed
210
+ s4 = parse_result_chudan
211
+ if s4 == :failed
212
+ s4 = parse_result_jishogi
213
+ if s4 == :failed
214
+ s4 = parse_result_sennichite
215
+ if s4 == :failed
216
+ s4 = parse_result_tsumi
217
+ s4 = parse_result_fuzumi if s4 == :failed
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
223
+ if s4 != :failed
224
+ if parse_nl != :failed || eos?
225
+ @reported_pos = s0
226
+ s4
227
+ else
228
+ @current_pos = s0
229
+ :failed
230
+ end
231
+ else
232
+ @current_pos = s0
233
+ :failed
234
+ end
235
+ else
236
+ @current_pos = s0
237
+ :failed
238
+ end
239
+ else
240
+ @current_pos = s0
241
+ :failed
242
+ end
243
+ else
244
+ @current_pos = s0
245
+ :failed
246
+ end
247
+ end
248
+
249
+ def parse_result_toryo
250
+ s0 = @current_pos
251
+ s1 = match_str("勝ち")
252
+ if s1 != :failed
253
+ @reported_pos = s0
254
+ "TORYO"
255
+ else
256
+ @current_pos = s0
257
+ :failed
258
+ end
259
+ end
260
+
261
+ def parse_result_illegal
262
+ s0 = @current_pos
263
+ if match_str("反則") != :failed
264
+ s10 = @current_pos
265
+ s11 = match_str("勝ち")
266
+ if s11 != :failed
267
+ @reported_pos = s10
268
+ s11 = "ILLEGAL_ACTION"
269
+ end
270
+ s10 = s11
271
+ if s10 == :failed
272
+ s10 = @current_pos
273
+ s11 = match_str("負け")
274
+ if s11 != :failed
275
+ @reported_pos = s10
276
+ s11 = "ILLEGAL_MOVE"
277
+ end
278
+ s10 = s11
279
+ end
280
+ if s10 != :failed
281
+ @reported_pos = s0
282
+ s10
283
+ else
284
+ @current_pos = s0
285
+ :failed
286
+ end
287
+ else
288
+ @current_pos = s0
289
+ :failed
290
+ end
291
+ end
292
+
293
+ def parse_result_timeup
294
+ s0 = @current_pos
295
+ if match_str("で時間切れにより") != :failed
296
+ if parse_turn != :failed
297
+ if match_str("手の勝ち") != :failed
298
+ @reported_pos = s0
299
+ "TIME_UP"
300
+ else
301
+ @current_pos = s0
302
+ :failed
303
+ end
304
+ else
305
+ @current_pos = s0
306
+ :failed
307
+ end
308
+ else
309
+ @current_pos = s0
310
+ :failed
311
+ end
312
+ end
313
+
314
+ def parse_result_chudan
315
+ s0 = @current_pos
316
+ s1 = match_str("で中断")
317
+ if s1 != :failed
318
+ @reported_pos = s0
319
+ "CHUDAN"
320
+ else
321
+ @current_pos = s0
322
+ :failed
323
+ end
324
+ end
325
+
326
+ def parse_result_jishogi
327
+ s0 = @current_pos
328
+ s1 = match_str("で持将棋")
329
+ if s1 != :failed
330
+ @reported_pos = s0
331
+ "JISHOGI"
332
+ else
333
+ @current_pos = s0
334
+ :failed
335
+ end
336
+ end
337
+
338
+ def parse_result_sennichite
339
+ s0 = @current_pos
340
+ s1 = match_str("で千日手")
341
+ if s1 != :failed
342
+ @reported_pos = s0
343
+ "SENNICHITE"
344
+ else
345
+ @current_pos = s0
346
+ :failed
347
+ end
348
+ end
349
+
350
+ def parse_result_tsumi
351
+ s0 = @current_pos
352
+ match_str("で")
353
+ if match_str("詰") != :failed
354
+ match_str("み")
355
+ @reported_pos = s0
356
+ "TSUMI"
357
+ else
358
+ @current_pos = s0
359
+ :failed
360
+ end
361
+ end
362
+
363
+ def parse_result_fuzumi
364
+ s0 = @current_pos
365
+ s1 = match_str("で不詰")
366
+ if s1 != :failed
367
+ @reported_pos = s0
368
+ "FUZUMI"
369
+ else
370
+ @current_pos = s0
371
+ :failed
372
+ end
373
+ end
374
+
375
+ def parse_skipline
376
+ s0 = @current_pos
377
+ s1 = match_str("#")
378
+ if s1 != :failed
379
+ s2 = parse_nonls
380
+ s3 = parse_newline
381
+ s0 = if s3 != :failed
382
+ [s1, s2, s3]
383
+ else
384
+ @current_pos = s0
385
+ :failed
386
+ end
387
+ else
388
+ @current_pos = s0
389
+ s0 = :failed
390
+ end
391
+ s0
392
+ end
393
+
394
+ def parse_num
395
+ s0 = @current_pos
396
+ s1 = match_regexp(/^[123456789]/)
397
+ if s1 != :failed
398
+ @reported_pos = s0
399
+ s1 = zen2n(s1)
400
+ end
401
+ s1
402
+ end
403
+
404
+ def parse_numkan
405
+ s0 = @current_pos
406
+ s1 = match_regexp(/^[一二三四五六七八九]/)
407
+ if s1 != :failed
408
+ @reported_pos = s0
409
+ s1 = kan2n(s1)
410
+ end
411
+ s1
412
+ end
413
+
414
+ def parse_whitespace
415
+ match_regexp(/^[ \t]/)
416
+ end
417
+
418
+ def parse_newline
419
+ s0 = @current_pos
420
+ s1 = []
421
+ s2 = parse_whitespace
422
+ while s2 != :failed
423
+ s1 << s2
424
+ s2 = parse_whitespace
425
+ end
426
+ s2 = match_str("\n")
427
+ if s2 == :failed
428
+ s2 = @current_pos
429
+ s3 = match_str("\r")
430
+ s2 = if s3 != :failed
431
+ s4 = match_str("\n")
432
+ s4 = nil if s4 == :failed
433
+ [s3, s4]
434
+ else
435
+ @current_pos = s2
436
+ :failed
437
+ end
438
+ end
439
+ if s2 != :failed
440
+ [s1, s2]
441
+ else
442
+ @current_pos = s0
443
+ :failed
444
+ end
445
+ end
446
+
447
+ def parse_nl
448
+ s0 = @current_pos
449
+ s2 = parse_newline
450
+ if s2 != :failed
451
+ s1 = []
452
+ while s2 != :failed
453
+ s1 << s2
454
+ s2 = parse_newline
455
+ end
456
+ else
457
+ s1 = :failed
458
+ end
459
+ if s1 != :failed
460
+ s2 = []
461
+ s3 = parse_skipline
462
+ while s3 != :failed
463
+ s2 << s3
464
+ s3 = parse_skipline
465
+ end
466
+ [s1, s2]
467
+ else
468
+ @current_pos = s0
469
+ :failed
470
+ end
471
+ end
472
+
473
+ def parse_nonl
474
+ match_regexp(/^[^\r\n]/)
475
+ end
476
+
477
+ def parse_nonls
478
+ stack = []
479
+ matched = parse_nonl
480
+ while matched != :failed
481
+ stack << matched
482
+ matched = parse_nonl
483
+ end
484
+ stack
485
+ end
486
+
487
+ def parse_nonls!
488
+ matched = parse_nonls
489
+ if matched.empty?
490
+ :failed
491
+ else
492
+ matched
493
+ end
494
+ end
495
+
496
+ protected
497
+
498
+ def transform_root_header_data(ret)
499
+ if ret["header"]["手番"]
500
+ ret["initial"]["data"]["color"] = "下先".include?(ret["header"]["手番"]) ? 0 : 1
501
+ ret["header"].delete("手番")
502
+ else
503
+ ret["initial"]["data"]["color"] = 0
504
+ end
505
+ ret["initial"]["data"]["hands"] = [
506
+ make_hand(ret["header"]["先手の持駒"] || ret["header"]["下手の持駒"]),
507
+ make_hand(ret["header"]["後手の持駒"] || ret["header"]["上手の持駒"])
508
+ ]
509
+ %w(先手の持駒 下手の持駒 後手の持駒 上手の持駒).each do |key|
510
+ ret["header"].delete(key)
511
+ end
512
+ end
513
+
514
+ def transform_root_forks(forks, moves)
515
+ fork_stack = [{ "te" => 0, "moves" => moves }]
516
+ forks.each do |f|
517
+ now_fork = f
518
+ _fork = fork_stack.pop
519
+ _fork = fork_stack.pop while _fork["te"] > now_fork["te"]
520
+ move = _fork["moves"][now_fork["te"] - _fork["te"]]
521
+ move["forks"] ||= []
522
+ move["forks"] << now_fork["moves"]
523
+ fork_stack << _fork
524
+ fork_stack << now_fork
525
+ end
526
+ end
527
+
528
+ def transform_initialboard(lines)
529
+ board = []
530
+ 9.times do |i|
531
+ line = []
532
+ 9.times do |j|
533
+ line << lines[j][8 - i]
534
+ end
535
+ board << line
536
+ end
537
+ { "preset" => "OTHER", "data" => { "board" => board } }
538
+ end
539
+
540
+ def zen2n(s)
541
+ "0123456789".index(s)
542
+ end
543
+
544
+ def kan2n(s)
545
+ "〇一二三四五六七八九".index(s)
546
+ end
547
+
548
+ def kan2n2(s)
549
+ case s.length
550
+ when 1
551
+ "〇一二三四五六七八九十".index(s)
552
+ when 2
553
+ "〇一二三四五六七八九十".index(s[1]) + 10
554
+ else
555
+ raise "21以上の数値に対応していません"
556
+ end
557
+ end
558
+
559
+ def kind2csa(kind)
560
+ if kind[0] == "成"
561
+ {
562
+ "香" => "NY",
563
+ "桂" => "NK",
564
+ "銀" => "NG"
565
+ }[kind[1]]
566
+ else
567
+ {
568
+ "歩" => "FU",
569
+ "香" => "KY",
570
+ "桂" => "KE",
571
+ "銀" => "GI",
572
+ "金" => "KI",
573
+ "角" => "KA",
574
+ "飛" => "HI",
575
+ "玉" => "OU",
576
+ "王" => "OU",
577
+ "と" => "TO",
578
+ "杏" => "NY",
579
+ "圭" => "NK",
580
+ "全" => "NG",
581
+ "馬" => "UM",
582
+ "竜" => "RY",
583
+ "龍" => "RY"
584
+ }[kind]
585
+ end
586
+ end
587
+
588
+ def preset2str(preset)
589
+ {
590
+ "平手" => "HIRATE",
591
+ "香落ち" => "KY",
592
+ "右香落ち" => "KY_R",
593
+ "角落ち" => "KA",
594
+ "飛車落ち" => "HI",
595
+ "飛香落ち" => "HIKY",
596
+ "二枚落ち" => "2",
597
+ "三枚落ち" => "3",
598
+ "四枚落ち" => "4",
599
+ "五枚落ち" => "5",
600
+ "左五枚落ち" => "5_L",
601
+ "六枚落ち" => "6",
602
+ "八枚落ち" => "8",
603
+ "十枚落ち" => "10",
604
+ "その他" => "OTHER"
605
+ }[preset.gsub(/\s/, "")]
606
+ end
607
+ end
608
+ end