jkf 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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