jkf 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1240 @@
1
+ # coding: utf-8
2
+
3
+ module Jkf::Parser
4
+ class Ki2 < Base
5
+ def parse_root
6
+ s0 = @current_pos
7
+ s1 = []
8
+ s2 = parse_header
9
+ while s2 != :failed
10
+ s1 << s2
11
+ s2 = parse_header
12
+ end
13
+ if s1 != :failed
14
+ s2 = parse_initialboard
15
+ s2 = nil if s2 == :failed
16
+ if s2 != :failed
17
+ s3 = []
18
+ s4 = parse_header
19
+ while s4 != :failed
20
+ s3 << s4
21
+ s4 = parse_header
22
+ end
23
+ if s3 != :failed
24
+ s4 = parse_moves
25
+ if s4 != :failed
26
+ s5 = []
27
+ s6 = parse_fork
28
+ while s6 != :failed
29
+ s5 << s6
30
+ s6 = parse_fork
31
+ end
32
+ if s5 != :failed
33
+ @reported_pos = s0
34
+ s1 = -> (headers, ini, headers2, moves, forks) {
35
+ ret = { "header" => {}, "moves" => moves }
36
+ headers.compact.each { |h| ret["header"][h["k"]] = h["v"] }
37
+ headers2.compact.each { |h| ret["header"][h["k"]] = h["v"] }
38
+ if ini
39
+ ret["initial"] = ini
40
+ elsif ret["header"]["手合割"]
41
+ preset = preset2str(ret["header"]["手合割"])
42
+ ret["initial"] = { "preset" => preset } if preset != "OTHER"
43
+ end
44
+ if ret["initial"] && ret["initial"]["data"]
45
+ if ret["header"]["手番"]
46
+ ret["initial"]["data"]["color"] = ("下先".index(ret["header"]["手番"]) >= 0 ? 0 : 1)
47
+ ret["header"].delete("手番")
48
+ else
49
+ ret["initial"]["data"]["color"] = 0
50
+ end
51
+ ret["initial"]["data"]["hands"] = [
52
+ make_hand(ret["header"]["先手の持駒"] || ret["header"]["下手の持駒"]),
53
+ make_hand(ret["header"]["後手の持駒"] || ret["header"]["上手の持駒"])
54
+ ]
55
+ %w(先手の持駒 下手の持駒 後手の持駒 上手の持駒).each do |key|
56
+ ret["header"].delete(key)
57
+ end
58
+ end
59
+ fork_stack = [{ "te" => 0, "moves" => moves }]
60
+ forks.each do |f|
61
+ now_fork = f
62
+ _fork = fork_stack.pop
63
+ _fork = fork_stack.pop while _fork["te"] > now_fork["te"]
64
+ move = _fork["moves"][now_fork["te"] - _fork["te"]]
65
+ move["forks"] ||= []
66
+ move["forks"] << now_fork["moves"]
67
+ fork_stack << _fork
68
+ fork_stack << now_fork
69
+ end
70
+ ret
71
+ }.call(s1, s2, s3, s4, s5)
72
+ s0 = s1
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
+ else
86
+ @current_pos = s0
87
+ s0 = :failed
88
+ end
89
+ else
90
+ @current_pos = s0
91
+ s0 = :failed
92
+ end
93
+ s0
94
+ end
95
+
96
+ def parse_header
97
+ s0 = @current_pos
98
+ s1 = []
99
+ s2 = match_regexp(/^[^:\r\n]/)
100
+ if s2 != :failed
101
+ while s2 != :failed
102
+ s1 << s2
103
+ s2 = match_regexp(/^[^:\r\n]/)
104
+ end
105
+ else
106
+ s1 = :failed
107
+ end
108
+ if s1 != :failed
109
+ s2 = match_str(":")
110
+ if s2 != :failed
111
+ s3 = []
112
+ s4 = parse_nonl
113
+ while s4 != :failed
114
+ s3 << s4
115
+ s4 = parse_nonl
116
+ end
117
+ if s3 != :failed
118
+ s4 = []
119
+ s5 = parse_nl
120
+ if s5 != :failed
121
+ while s5 != :failed
122
+ s4 << s5
123
+ s5 = parse_nl
124
+ end
125
+ else
126
+ s4 = :failed
127
+ end
128
+ if s4 != :failed
129
+ @reported_pos = s0
130
+ s0 = s1 = { "k" => s1.join, "v" => s3.join }
131
+ else
132
+ @current_pos = s0
133
+ s0 = :failed
134
+ end
135
+ else
136
+ @current_pos = s0
137
+ s0 = :failed
138
+ end
139
+ else
140
+ @current_pos = s0
141
+ s0 = :failed
142
+ end
143
+ else
144
+ @current_pos = s0
145
+ s0 = :failed
146
+ end
147
+ if s0 == :failed
148
+ s0 = @current_pos
149
+ s1 = match_regexp(/^[先後上下]/)
150
+ if s1 != :failed
151
+ s2 = match_str("手番")
152
+ if s2 != :failed
153
+ s3 = parse_nl
154
+ if s3 != :failed
155
+ @reported_pos = s0
156
+ s0 = s1 = { "k" => "手番", "v" => s1 }
157
+ else
158
+ @current_pos = s0
159
+ s0 = :failed
160
+ end
161
+ else
162
+ @current_pos = s0
163
+ s0 = :failed
164
+ end
165
+ else
166
+ @current_pos = s0
167
+ s0 = :failed
168
+ end
169
+ end
170
+ s0
171
+ end
172
+
173
+ def parse_initialboard
174
+ s0 = s1 = @current_pos
175
+ s2 = match_str(" ")
176
+ if s2 != :failed
177
+ s3 = []
178
+ s4 = parse_nonl
179
+ while s4 != :failed
180
+ s3 << s4
181
+ s4 = parse_nonl
182
+ end
183
+ if s3 != :failed
184
+ s4 = parse_nl
185
+ if s4 != :failed
186
+ s1 = s2 = [s2, s3, s4]
187
+ else
188
+ @current_pos = s1
189
+ s1 = :failed
190
+ end
191
+ else
192
+ @current_pos = s1
193
+ s1 = :failed
194
+ end
195
+ else
196
+ @current_pos = s1
197
+ s1 = :failed
198
+ end
199
+ s1 = nil if s1 == :failed
200
+ if s1 != :failed
201
+ s2 = @current_pos
202
+ s3 = match_str("+")
203
+ if s3 != :failed
204
+ s4 = []
205
+ s5 = parse_nonl
206
+ while s5 != :failed
207
+ s4 << s5
208
+ s5 = parse_nonl
209
+ end
210
+ if s4 != :failed
211
+ s5 = parse_nl
212
+ if s5 != :failed
213
+ s2 = s3 = [s3, s4, s5]
214
+ else
215
+ @current_pos = s2
216
+ s2 = :failed
217
+ end
218
+ else
219
+ @current_pos = s2
220
+ s2 = :failed
221
+ end
222
+ else
223
+ @current_pos = s2
224
+ s2 = :failed
225
+ end
226
+ s2 = nil if s2 == :failed
227
+ if s2 != :failed
228
+ s3 = []
229
+ s4 = parse_ikkatsuline
230
+ if s4 != :failed
231
+ while s4 != :failed
232
+ s3 << s4
233
+ s4 = parse_ikkatsuline
234
+ end
235
+ else
236
+ s3 = :failed
237
+ end
238
+ if s3 != :failed
239
+ s4 = @current_pos
240
+ s5 = match_str("+")
241
+ if s5 != :failed
242
+ s6 = []
243
+ s7 = parse_nonl
244
+ while s7 != :failed
245
+ s6 << s7
246
+ s7 = parse_nonl
247
+ end
248
+ if s6 != :failed
249
+ s7 = parse_nl
250
+ if s7 != :failed
251
+ s4 = s5 = [s5, s6, s7]
252
+ else
253
+ @current_pos = s4
254
+ s4 = :failed
255
+ end
256
+ else
257
+ @current_pos = s4
258
+ s4 = :failed
259
+ end
260
+ else
261
+ @current_pos = s4
262
+ s4 = :failed
263
+ end
264
+ s4 = nil if s4 == :failed
265
+ if s4 != :failed
266
+ @reported_pos = s0
267
+ s1 = -> (lines) {
268
+ board = []
269
+ 9.times { |i|
270
+ line = []
271
+ 9.times { |j|
272
+ line << lines[j][8-i]
273
+ }
274
+ board << line
275
+ }
276
+ { "preset" => "OTHER", "data" => { "board" => board } }
277
+ }.call(s3)
278
+ s0 = s1
279
+ else
280
+ @current_pos = s0
281
+ s0 = :failed
282
+ end
283
+ else
284
+ @current_pos = s0
285
+ s0 = :failed
286
+ end
287
+ else
288
+ @current_pos = s0
289
+ s0 = :failed
290
+ end
291
+ else
292
+ @current_pos = s0
293
+ s0 = :failed
294
+ end
295
+
296
+ return s0
297
+ end
298
+
299
+ def parse_ikkatsuline
300
+ s0 = @current_pos
301
+ s1 = match_str("|")
302
+ if s1 != :failed
303
+ s2 = []
304
+ s3 = parse_masu
305
+ if s3 != :failed
306
+ while s3 != :failed
307
+ s2 << s3
308
+ s3 = parse_masu
309
+ end
310
+ else
311
+ s2 = :failed
312
+ end
313
+ if s2 != :failed
314
+ s3 = match_str("|")
315
+ if s3 != :failed
316
+ s4 = []
317
+ s5 = parse_nonl
318
+ if s5 != :failed
319
+ while s5 != :failed
320
+ s4 << s5
321
+ s5 = parse_nonl
322
+ end
323
+ else
324
+ s4 = :failed
325
+ end
326
+ if s4 != :failed
327
+ s5 = parse_nl
328
+ if s5 != :failed
329
+ @reported_pos = s0
330
+ s0 = s1 = s2
331
+ else
332
+ @current_pos = s0
333
+ s0 = :failed
334
+ end
335
+ else
336
+ @current_pos = s0
337
+ s0 = :failed
338
+ end
339
+ else
340
+ @current_pos = s0
341
+ s0 = :failed
342
+ end
343
+ else
344
+ @current_pos = s0
345
+ s0 = :failed
346
+ end
347
+ else
348
+ @current_pos = s0
349
+ s0 = :failed
350
+ end
351
+
352
+ return s0
353
+ end
354
+
355
+ def parse_masu
356
+ s0 = @current_pos
357
+ s1 = parse_teban
358
+ if s1 != :failed
359
+ s2 = parse_piece
360
+ if s2 != :failed
361
+ @reported_pos = s0
362
+ s1 = { "color" => s1, "kind" => s2 }
363
+ s0 = s1
364
+ else
365
+ @current_pos = s0
366
+ s0 = :failed
367
+ end
368
+ else
369
+ @current_pos = s0
370
+ s0 = :failed
371
+ end
372
+ if s0 == :failed
373
+ s0 = @current_pos
374
+ s1 = match_str(" ・")
375
+ if s1 != :failed
376
+ @reported_pos = s0
377
+ s1 = {}
378
+ end
379
+ s0 = s1
380
+ end
381
+
382
+ s0
383
+ end
384
+
385
+ def parse_teban
386
+ s0 = @current_pos
387
+ s1 = match_str(" ")
388
+ s1 = match_str("+") if s1 == :failed
389
+ s1 = match_str("^") if s1 == :failed
390
+ if s1 != :failed
391
+ @reported_pos = s0
392
+ s1 = 0
393
+ end
394
+ s0 = s1
395
+ if s0 == :failed
396
+ s0 = @current_pos
397
+ s1 = match_str("v")
398
+ s1 = match_str("V") if s1 == :failed
399
+ if s1 != :failed
400
+ @reported_pos = s0
401
+ s1 = 1
402
+ end
403
+ s0 = s1
404
+ end
405
+ s0
406
+ end
407
+
408
+ def parse_moves
409
+ s0 = @current_pos
410
+ s1 = parse_firstboard
411
+ if s1 != :failed
412
+ s2 = []
413
+ s3 = parse_move
414
+ while s3 != :failed
415
+ s2 << s3
416
+ s3 = parse_move
417
+ end
418
+ if s2 != :failed
419
+ s3 = parse_result
420
+ s3 = nil if s3 == :failed
421
+ if s3 != :failed
422
+ @reported_pos = s0
423
+ s1 = -> (hd, tl, res) {
424
+ tl.unshift(hd)
425
+ tl << { "special" => res } if res && !tl[tl.length-1]["special"]
426
+ tl
427
+ }.call(s1, s2, s3)
428
+ s0 = s1
429
+ else
430
+ @current_pos = s0
431
+ s0 = :failed
432
+ end
433
+ else
434
+ @current_pos = s0
435
+ s0 = :failed
436
+ end
437
+ else
438
+ @current_pos = s0
439
+ s0 = :failed
440
+ end
441
+ s0
442
+ end
443
+
444
+ def parse_firstboard
445
+ s0 = @current_pos
446
+ s1 = []
447
+ s2 = parse_comment
448
+ while s2 != :failed
449
+ s1 << s2
450
+ s2 = parse_comment
451
+ end
452
+ if s1 != :failed
453
+ s2 = parse_pointer
454
+ if s2 == :failed
455
+ s2 = nil
456
+ end
457
+ if s2 != :failed
458
+ @reported_pos = s0
459
+ s0 = s1 = (s1.length == 0 ? {} : {"comments" =>s1})
460
+ else
461
+ @current_pos = s0
462
+ s0 = :failed
463
+ end
464
+ else
465
+ @current_pos = s0
466
+ s0 = :failed
467
+ end
468
+ s0
469
+ end
470
+
471
+ def parse_move
472
+ s0 = @current_pos
473
+ s1 = parse_line
474
+ if s1 != :failed
475
+ s2 = []
476
+ s3 = parse_comment
477
+ while s3 != :failed
478
+ s2 << s3
479
+ s3 = parse_comment
480
+ end
481
+ if s2 != :failed
482
+ s3 = parse_pointer
483
+ if s3 == :failed
484
+ s3 = nil
485
+ end
486
+ if s3 != :failed
487
+ s4 = []
488
+ s5 = parse_nl
489
+ s5 = match_str(" ") if s5 == :failed
490
+ while s5 != :failed
491
+ s4 << s5
492
+ s5 = parse_nl
493
+ s5 = match_str(" ") if s5 == :failed
494
+ end
495
+ if s4 != :failed
496
+ @reported_pos = s0
497
+ s1 = -> (line, c) {
498
+ ret = { "move" => line }
499
+ ret["comments"] = c if c.length > 0
500
+ ret
501
+ }.call(s1, s2)
502
+ s0 = s1
503
+ else
504
+ @current_pos = s0
505
+ s0 = :failed
506
+ end
507
+ else
508
+ @current_pos = s0
509
+ s0 = :failed
510
+ end
511
+ else
512
+ @current_pos = s0
513
+ s0 = :failed
514
+ end
515
+ else
516
+ @current_pos = s0
517
+ s0 = :failed
518
+ end
519
+
520
+ s0
521
+ end
522
+
523
+ def parse_pointer
524
+ s0 = @current_pos
525
+ s1 = match_str("&")
526
+ if s1 != :failed
527
+ s2 = []
528
+ s3 = parse_nonl
529
+ while s3 != :failed
530
+ s2 << s3
531
+ s3 = parse_nonl
532
+ end
533
+ if s2 != :failed
534
+ s3 = parse_nl
535
+ if s3 != :failed
536
+ s0 = s1 = [s1, s2, s3]
537
+ else
538
+ @current_pos = s0
539
+ s0 = :failed
540
+ end
541
+ else
542
+ @current_pos = s0
543
+ s0 = :failed
544
+ end
545
+ else
546
+ @current_pos = s0
547
+ s0 = :failed
548
+ end
549
+ s0
550
+ end
551
+
552
+ def parse_line
553
+ s0 = @current_pos
554
+ s1 = match_regexp(/^[▲△]/)
555
+ if s1 != :failed
556
+ s1 = if s1 == '▲'
557
+ { 'color' => 0 }
558
+ else
559
+ { 'color' => 1 }
560
+ end
561
+ s2 = parse_fugou
562
+ if s2 != :failed
563
+ s3 = []
564
+ s4 = parse_nl
565
+ s4 = match_str(" ") if s4 == :failed
566
+ while s4 != :failed
567
+ s3 << s4
568
+ s4 = parse_nl
569
+ s4 = match_str(" ") if s4 == :failed
570
+ end
571
+ if s3 != :failed
572
+ @reported_pos = s0
573
+ s0 = s1 = s2.merge(s1)
574
+ else
575
+ @current_pos = s0
576
+ s0 = :failed
577
+ end
578
+ else
579
+ @current_pos = s0
580
+ s0 = :failed
581
+ end
582
+ else
583
+ @current_pos = s0
584
+ s0 = :failed
585
+ end
586
+ s0
587
+ end
588
+
589
+ def parse_fugou
590
+ s0 = @current_pos
591
+ s1 = parse_place
592
+ if s1 != :failed
593
+ s2 = parse_piece
594
+ if s2 != :failed
595
+ s3 = parse_soutai
596
+ s3 = nil if s3 == :failed
597
+ if s3 != :failed
598
+ s4 = parse_dousa
599
+ s4 = nil if s4 == :failed
600
+ if s4 != :failed
601
+ s5 = match_str("成")
602
+ s5 = match_str("不成") if s5 == :failed
603
+ s5 = nil if s5 == :failed
604
+ if s5 != :failed
605
+ s6 = match_str("打")
606
+ s6 = nil if s6 == :failed
607
+ if s6 != :failed
608
+ @reported_pos = s0
609
+ s1 = -> (pl, pi, sou, dou, pro, da) {
610
+ ret = { "piece" => pi }
611
+ if pl["same"]
612
+ ret["same"] = true
613
+ else
614
+ ret["to"] = pl
615
+ end
616
+ ret["promote"] = (pro == "成") if pro
617
+ if da
618
+ ret["relative"] = "H"
619
+ else
620
+ rel = soutai2relative(sou) + dousa2relative(dou)
621
+ ret["relative"] = rel unless rel.empty? !=""
622
+ end
623
+ ret
624
+ }.call(s1, s2, s3, s4, s5, s6)
625
+ s0 = s1
626
+ else
627
+ @current_pos = s0
628
+ s0 = :failed
629
+ end
630
+ else
631
+ @current_pos = s0
632
+ s0 = :failed
633
+ end
634
+ else
635
+ @current_pos = s0
636
+ s0 = :failed
637
+ end
638
+ else
639
+ @current_pos = s0
640
+ s0 = :failed
641
+ end
642
+ else
643
+ @current_pos = s0
644
+ s0 = :failed
645
+ end
646
+ else
647
+ @current_pos = s0
648
+ s0 = :failed
649
+ end
650
+ s0
651
+ end
652
+
653
+ def parse_place
654
+ s0 = @current_pos
655
+ s1 = parse_num
656
+ if s1 != :failed
657
+ s2 = parse_numkan
658
+ if s2 != :failed
659
+ @reported_pos = s0
660
+ s0 = s1 = { "x" => s1, "y" => s2 }
661
+ else
662
+ @current_pos = s0
663
+ s0 = :failed
664
+ end
665
+ else
666
+ @current_pos = s0
667
+ s0 = :failed
668
+ end
669
+ if s0 == :failed
670
+ s0 = @current_pos
671
+ s1 = match_regexp("同")
672
+ if s1 != :failed
673
+ s2 = match_str(" ")
674
+ s2 = nil if s2 == :failed
675
+ if s2 != :failed
676
+ @reported_pos = s0
677
+ s0 = s1 = { "same" => true }
678
+ else
679
+ @current_pos = s0
680
+ s0 = :failed
681
+ end
682
+ else
683
+ @current_pos = s0
684
+ s0 = :failed
685
+ end
686
+ end
687
+ s0
688
+ end
689
+
690
+ def parse_piece
691
+ s0 = @current_pos
692
+ s1 = match_regexp("成")
693
+ s1 = "" if s1 == :failed
694
+ if s1 != :failed
695
+ s2 = match_regexp(/^[歩香桂銀金角飛王玉と杏圭全馬竜龍]/)
696
+ if s2 != :failed
697
+ @reported_pos = s0
698
+ s0 = s1 = kind2csa(s1 + s2)
699
+ else
700
+ @current_pos = s0
701
+ s0 = :failed
702
+ end
703
+ else
704
+ @current_pos = s0
705
+ s0 = :failed
706
+ end
707
+
708
+ return s0
709
+ end
710
+
711
+ def parse_soutai
712
+ match_regexp(/^[左直右]/)
713
+ end
714
+
715
+ def parse_dousa
716
+ match_regexp(/^[上寄引]/)
717
+ end
718
+
719
+ def parse_num
720
+ s0 = @current_pos
721
+ s1 = match_regexp(/^[123456789]/)
722
+ if s1 != :failed
723
+ @reported_pos = s0
724
+ s1 = zen2n(s1)
725
+ end
726
+ s0 = s1
727
+ s0
728
+ end
729
+
730
+ def parse_numkan
731
+ s0 = @current_pos
732
+ s1 = match_regexp(/^[一二三四五六七八九]/)
733
+ if s1 != :failed
734
+ @reported_pos = s0
735
+ s1 = kan2n(s1)
736
+ end
737
+ s0 = s1
738
+ s0
739
+ end
740
+
741
+ def parse_comment
742
+ s0 = @current_pos
743
+ s1 = match_str("*")
744
+ if s1 != :failed
745
+ s2 = []
746
+ s3 = parse_nonl
747
+ while s3 != :failed
748
+ s2 << s3
749
+ s3 = parse_nonl
750
+ end
751
+ if s2 != :failed
752
+ s3 = parse_nl
753
+ if s3 != :failed
754
+ @reported_pos = s0
755
+ s0 = s1 = s2.join
756
+ else
757
+ @current_pos = s0
758
+ s0 = :failed
759
+ end
760
+ else
761
+ @current_pos = s0
762
+ s0 = :failed
763
+ end
764
+ else
765
+ @current_pos = s0
766
+ s0 = :failed
767
+ end
768
+ s0
769
+ end
770
+
771
+ def parse_result
772
+ s0 = @current_pos
773
+ s1 = match_str("まで")
774
+ if s1 != :failed
775
+ s2 = []
776
+ s3 = match_regexp(/^[0-9]/)
777
+ if s3 != :failed
778
+ while s3 != :failed
779
+ s2 << s3
780
+ s3 = match_regexp(/^[0-9]/)
781
+ end
782
+ else
783
+ s2 = :failed
784
+ end
785
+ if s2 != :failed
786
+ s3 = match_str("手")
787
+ if s3 != :failed
788
+ s4 = @current_pos
789
+ s5 = match_str("で")
790
+ if s5 != :failed
791
+ s6 = parse_turn
792
+ if s6 != :failed
793
+ s7 = match_str("手の")
794
+ if s7 != :failed
795
+ s8 = @current_pos
796
+ s9 = match_str("勝ち")
797
+ if s9 != :failed
798
+ @reported_pos = s8
799
+ s9 = "TORYO"
800
+ end
801
+ s8 = s9
802
+ if s8 == :failed
803
+ s8 = @current_pos
804
+ s9 = match_str("反則")
805
+ if s9 != :failed
806
+ s10 = @current_pos
807
+ s11 = match_str("勝ち")
808
+ if s11 != :failed
809
+ @reported_pos = s10
810
+ s11 = "ILLEGAL_ACTION"
811
+ end
812
+ s10 = s11
813
+ if s10 == :failed
814
+ s10 = @current_pos
815
+ s11 = match_str("負け")
816
+ if s11 != :failed
817
+ @reported_pos = s10
818
+ s11 ="ILLEGAL_MOVE"
819
+ end
820
+ s10 = s11
821
+ end
822
+ if s10 != :failed
823
+ @reported_pos = s8
824
+ s8 = s9 = s10
825
+ else
826
+ @current_pos = s8
827
+ s8 = :failed
828
+ end
829
+ else
830
+ @current_pos = s8
831
+ s8 = :failed
832
+ end
833
+ end
834
+ if s8 != :failed
835
+ @reported_pos = s4
836
+ s4 = s5 = s8
837
+ else
838
+ @current_pos = s4
839
+ s4 = :failed
840
+ end
841
+ else
842
+ @current_pos = s4
843
+ s4 = :failed
844
+ end
845
+ else
846
+ @current_pos = s4
847
+ s4 = :failed
848
+ end
849
+ else
850
+ @current_pos = s4
851
+ s4 = :failed
852
+ end
853
+ if s4 == :failed
854
+ s4 = @current_pos
855
+ s5 = match_str("で時間切れにより")
856
+ if s5 != :failed
857
+ s6 = parse_turn
858
+ if s6 != :failed
859
+ s7 = match_str("手の勝ち")
860
+ if s7 != :failed
861
+ @reported_pos = s4
862
+ s5 = "TIME_UP"
863
+ s4 = s5
864
+ else
865
+ @current_pos = s4
866
+ s4 = :failed
867
+ end
868
+ else
869
+ @current_pos = s4
870
+ s4 = :failed
871
+ end
872
+ else
873
+ @current_pos = s4
874
+ s4 = :failed
875
+ end
876
+ if s4 == :failed
877
+ s4 = @current_pos
878
+ s5 = match_str("で中断")
879
+ if s5 != :failed
880
+ @reported_pos = s4
881
+ s5 = "CHUDAN"
882
+ end
883
+ s4 = s5
884
+ if s4 == :failed
885
+ s4 = @current_pos
886
+ s5 = match_str("で持将棋")
887
+ if s5 != :failed
888
+ @reported_pos = s4
889
+ s5 = "JISHOGI"
890
+ end
891
+ s4 = s5
892
+ if s4 == :failed
893
+ s4 = @current_pos
894
+ s5 = match_str("で千日手")
895
+ if s5 != :failed
896
+ @reported_pos = s4
897
+ s5 = "SENNICHITE"
898
+ end
899
+ s4 = s5
900
+ if s4 == :failed
901
+ s4 = @current_pos
902
+ s5 = match_str("で")
903
+ s5 = nil if s5 == :failed
904
+ if s5 != :failed
905
+ s6 = match_str("詰")
906
+ if s6 != :failed
907
+ s7 = match_str("み")
908
+ if s7 == :failed
909
+ s7 = nil
910
+ end
911
+ if s7 != :failed
912
+ @reported_pos = s4
913
+ s4 = s5 = "TSUMI"
914
+ else
915
+ @current_pos = s4
916
+ s4 = :failed
917
+ end
918
+ else
919
+ @current_pos = s4
920
+ s4 = :failed
921
+ end
922
+ else
923
+ @current_pos = s4
924
+ s4 = :failed
925
+ end
926
+ if s4 == :failed
927
+ s4 = @current_pos
928
+ s5 = match_str("で不詰")
929
+ if s5 != :failed
930
+ @reported_pos = s4
931
+ s5 = "FUZUMI"
932
+ end
933
+ s4 = s5
934
+ end
935
+ end
936
+ end
937
+ end
938
+ end
939
+ end
940
+ if s4 != :failed
941
+ s5 = parse_nl
942
+ if s5 != :failed || @input[@current_pos].nil?
943
+ @reported_pos = s0
944
+ s0 = s1 = s4
945
+ else
946
+ @current_pos = s0
947
+ s0 = :failed
948
+ end
949
+ else
950
+ @current_pos = s0
951
+ s0 = :failed
952
+ end
953
+ else
954
+ @current_pos = s0
955
+ s0 = :failed
956
+ end
957
+ else
958
+ @current_pos = s0
959
+ s0 = :failed
960
+ end
961
+ else
962
+ @current_pos = s0
963
+ s0 = :failed
964
+ end
965
+ s0
966
+ end
967
+
968
+ def parse_fork
969
+ s0 = @current_pos
970
+ s1 = match_str( "変化:")
971
+ if s1 != :failed
972
+ s2 = []
973
+ s3 = match_str(" ")
974
+ while s3 != :failed
975
+ s2 << s3
976
+ s3 = match_str(" ")
977
+ end
978
+ if s2 != :failed
979
+ s3 = []
980
+ s4 = match_regexp(/^[0-9]/)
981
+ if s4 != :failed
982
+ while s4 != :failed
983
+ s3 << s4
984
+ s4 = match_regexp(/^[0-9]/)
985
+ end
986
+ else
987
+ s3 = :failed
988
+ end
989
+ if s3 != :failed
990
+ s4 = match_str("手")
991
+ if s4 != :failed
992
+ s5 = parse_nl
993
+ if s5 != :failed
994
+ s6 = parse_moves
995
+ if s6 != :failed
996
+ @reported_pos = s0
997
+ s0 = s1 = { "te" => s3.join.to_i, "moves" => s6[1..-1] }
998
+ else
999
+ @current_pos = s0
1000
+ s0 = :failed
1001
+ end
1002
+ else
1003
+ @current_pos = s0
1004
+ s0 = :failed
1005
+ end
1006
+ else
1007
+ @current_pos = s0
1008
+ s0 = :failed
1009
+ end
1010
+ else
1011
+ @current_pos = s0
1012
+ s0 = :failed
1013
+ end
1014
+ else
1015
+ @current_pos = s0
1016
+ s0 = :failed
1017
+ end
1018
+ else
1019
+ @current_pos = s0
1020
+ s0 = :failed
1021
+ end
1022
+ s0
1023
+ end
1024
+
1025
+ def parse_turn
1026
+ match_regexp(/^[先後上下]/)
1027
+ end
1028
+
1029
+ def parse_nl
1030
+ s0 = @current_pos
1031
+ s1 = []
1032
+ s2 = parse_newline
1033
+ if s2 != :failed
1034
+ while s2 != :failed
1035
+ s1 << s2
1036
+ s2 = parse_newline
1037
+ end
1038
+ else
1039
+ s1 = :failed
1040
+ end
1041
+ if s1 != :failed
1042
+ s2 = []
1043
+ s3 = parse_skipline
1044
+ while s3 != :failed
1045
+ s2 << s3
1046
+ s3 = parse_skipline
1047
+ end
1048
+ if s2 != :failed
1049
+ s0 = s1 = [s1, s2]
1050
+ else
1051
+ @current_pos = s0
1052
+ s0 = :failed
1053
+ end
1054
+ else
1055
+ @current_pos = s0
1056
+ s0 = :failed
1057
+ end
1058
+ s0
1059
+ end
1060
+
1061
+ def parse_skipline
1062
+ s0 = @current_pos
1063
+ s1 = match_str("#")
1064
+ if s1 != :failed
1065
+ s2 = []
1066
+ s3 = parse_nonl
1067
+ while s3 != :failed
1068
+ s2 << s3
1069
+ s3 = parse_nonl
1070
+ end
1071
+ if s2 != :failed
1072
+ s3 = parse_newline
1073
+ if s3 != :failed
1074
+ s0 = s1 = [s1, s2, s3]
1075
+ else
1076
+ @current_pos = s0
1077
+ s0 = :failed
1078
+ end
1079
+ else
1080
+ @current_pos = s0
1081
+ s0 = :failed
1082
+ end
1083
+ else
1084
+ @current_pos = s0
1085
+ s0 = :failed
1086
+ end
1087
+ s0
1088
+ end
1089
+
1090
+ def parse_whitespace
1091
+ s0 = match_str(" ")
1092
+ s0 = match_str("\t") if s0 == :failed
1093
+ s0
1094
+ end
1095
+
1096
+ def parse_newline
1097
+ s0 = @current_pos
1098
+ s1 = []
1099
+ s2 = parse_whitespace
1100
+ while s2 != :failed
1101
+ s1 << s2
1102
+ s2 = parse_whitespace
1103
+ end
1104
+ if s1 != :failed
1105
+ s2 = match_str("\n")
1106
+ if s2 == :failed
1107
+ s2 = @current_pos
1108
+ s3 = match_str("\r")
1109
+ if s3 != :failed
1110
+ s4 = match_str("\n")
1111
+ s4 = nil if s4 == :failed
1112
+ if s4 != :failed
1113
+ s2 = s3 = [s3, s4]
1114
+ else
1115
+ @current_pos = s2
1116
+ s2 = :failed
1117
+ end
1118
+ else
1119
+ @current_pos = s2
1120
+ s2 = :failed
1121
+ end
1122
+ end
1123
+ if s2 != :failed
1124
+ s0 = s1 = [s1, s2]
1125
+ else
1126
+ @current_pos = s0
1127
+ s0 = :failed
1128
+ end
1129
+ else
1130
+ @current_pos = s0
1131
+ s0 = :failed
1132
+ end
1133
+ s0
1134
+ end
1135
+
1136
+ def parse_nonl
1137
+ match_regexp(/^[^\r\n]/)
1138
+ end
1139
+
1140
+ protected
1141
+
1142
+ def zen2n(s)
1143
+ "0123456789".index(s)
1144
+ end
1145
+
1146
+ def kan2n(s)
1147
+ "〇一二三四五六七八九".index(s)
1148
+ end
1149
+
1150
+ def kan2n2(s)
1151
+ case s.length
1152
+ when 1
1153
+ "〇一二三四五六七八九十".index(s)
1154
+ when 2
1155
+ "〇一二三四五六七八九十".index(s[1])+10
1156
+ else
1157
+ raise "21以上の数値に対応していません"
1158
+ end
1159
+ end
1160
+
1161
+ def kind2csa(kind)
1162
+ if kind[0] == "成"
1163
+ {
1164
+ "香" => "NY",
1165
+ "桂" => "NK",
1166
+ "銀" => "NG"
1167
+ }[kind[1]]
1168
+ else
1169
+ {
1170
+ "歩" => "FU",
1171
+ "香" => "KY",
1172
+ "桂" => "KE",
1173
+ "銀" => "GI",
1174
+ "金" => "KI",
1175
+ "角" => "KA",
1176
+ "飛" => "HI",
1177
+ "玉" => "OU",
1178
+ "王" => "OU",
1179
+ "と" => "TO",
1180
+ "杏" => "NY",
1181
+ "圭" => "NK",
1182
+ "全" => "NG",
1183
+ "馬" => "UM",
1184
+ "竜" => "RY",
1185
+ "龍" => "RY"
1186
+ }[kind]
1187
+ end
1188
+ end
1189
+
1190
+ def soutai2relative(str)
1191
+ {
1192
+ "左" => "L",
1193
+ "直" => "C",
1194
+ "右" => "R",
1195
+ }[str] || ""
1196
+ end
1197
+
1198
+ def dousa2relative(str)
1199
+ {
1200
+ "上" => "U",
1201
+ "寄" => "M",
1202
+ "引" => "D",
1203
+ }[str] || ""
1204
+ end
1205
+
1206
+ def preset2str(preset)
1207
+ {
1208
+ "平手" => "HIRATE",
1209
+ "香落ち" => "KY",
1210
+ "右香落ち" => "KY_R",
1211
+ "角落ち" => "KA",
1212
+ "飛車落ち" => "HI",
1213
+ "飛香落ち" => "HIKY",
1214
+ "二枚落ち" => "2",
1215
+ "三枚落ち" => "3",
1216
+ "四枚落ち" => "4",
1217
+ "五枚落ち" => "5",
1218
+ "左五枚落ち" => "5_L",
1219
+ "六枚落ち" => "6",
1220
+ "八枚落ち" => "8",
1221
+ "十枚落ち" => "10",
1222
+ "その他" => "OTHER",
1223
+ }[preset.gsub(/\s/, "")]
1224
+ end
1225
+
1226
+ def make_hand(str)
1227
+ kinds = str.gsub(/ $/, "").split(" ")
1228
+
1229
+ ret = { "FU" => 0, "KY" => 0, "KE" => 0, "GI" => 0, "KI" => 0, "KA" => 0, "HI" => 0 }
1230
+ return ret if str.empty?
1231
+
1232
+ kinds.each do |kind|
1233
+ next if kind.empty?
1234
+ ret[kind2csa(kind[0])] = kind.length == 1 ? 1 : kan2n2(kind[1..-1])
1235
+ end
1236
+
1237
+ ret
1238
+ end
1239
+ end
1240
+ end