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,988 @@
1
+ # coding: utf-8
2
+
3
+ module Jkf::Parser
4
+ class Csa < Base
5
+ def parse_root
6
+ @input += "\n" unless @input[-1] =~ /\n|\r|,/ # FIXME
7
+ s0 = parse_csa2
8
+ s0 = parse_csa1 if s0 == :failed
9
+ s0
10
+ end
11
+
12
+ def parse_csa2
13
+ s0 = @current_pos
14
+ s1 = parse_version22
15
+ if s1 != :failed
16
+ s2 = parse_information
17
+ s2 = nil if s2 == :failed
18
+ if s2 != :failed
19
+ s3 = parse_initial_board
20
+ if s3 != :failed
21
+ s4 = parse_moves
22
+ s4 = nil if s4 == :failed
23
+ if s4 != :failed
24
+ @reported_pos = s0
25
+ s0 = s1 = -> (info, ini, ms) {
26
+ ret = { "header" => info["header"], "initial" => ini, "moves" => ms }
27
+ if info && info["players"]
28
+ ret["header"]["先手"] = info["players"][0] if info["players"][0]
29
+ ret["header"]["後手"] = info["players"][1] if info["players"][1]
30
+ end
31
+ ret
32
+ }.call(s2, s3, s4)
33
+ else
34
+ @current_pos = s0
35
+ s0 = :failed
36
+ end
37
+ else
38
+ @current_pos = s0
39
+ s0 = :failed
40
+ end
41
+ else
42
+ @current_pos = s0
43
+ s0 = :failed
44
+ end
45
+ else
46
+ @current_pos = s0
47
+ s0 = :failed
48
+ end
49
+ s0
50
+ end
51
+
52
+ def parse_version22
53
+ s0 = @current_pos
54
+ s1 = []
55
+ s2 = parse_comment
56
+ while s2 != :failed
57
+ s1 << s2
58
+ s2 = parse_comment
59
+ end
60
+ if s1 != :failed
61
+ s2 = match_str("V2.2")
62
+ if s2 != :failed
63
+ s3 = parse_nl
64
+ if s3 != :failed
65
+ s0 = s1 = [s1, s2, s3]
66
+ else
67
+ @current_pos = s0
68
+ s0 = :failed
69
+ end
70
+ else
71
+ @current_pos = s0
72
+ s0 = :failed
73
+ end
74
+ else
75
+ @current_pos = s0
76
+ s0 = :failed
77
+ end
78
+ s0
79
+ end
80
+
81
+ def parse_information
82
+ s0 = @current_pos
83
+ s1 = parse_players
84
+ s1 = nil if s1 == :failed
85
+ if s1 != :failed
86
+ s2 = parse_headers
87
+ if s2 != :failed
88
+ @reported_pos = s0
89
+ s0 = s1 = { "players" => s1, "header" => s2 }
90
+ else
91
+ @current_pos = s0
92
+ s0 = :failed
93
+ end
94
+ else
95
+ @current_pos = s0
96
+ s0 = :failed
97
+ end
98
+ s0
99
+ end
100
+
101
+ def parse_headers
102
+ s0 = @current_pos
103
+ s1 = []
104
+ s2 = parse_header
105
+ while s2 != :failed
106
+ s1 << s2
107
+ s2 = parse_header
108
+ end
109
+ if s1 != :failed
110
+ @reported_pos = s0
111
+ s1 = -> (header) {
112
+ ret = {}
113
+ header.each do |data|
114
+ ret[normalize_header_key(data["k"])] = data["v"]
115
+ end
116
+ ret
117
+ }.call(s1)
118
+ end
119
+ s0 = s1
120
+ s0
121
+ end
122
+
123
+ def parse_header
124
+ s0 = @current_pos
125
+ s1 = []
126
+ s2 = parse_comment
127
+ while s2 != :failed
128
+ s1 << s2
129
+ s2 = parse_comment
130
+ end
131
+ if s1 != :failed
132
+ s2 = match_str("$")
133
+ if s2 != :failed
134
+ s3 = []
135
+ s4 = match_regexp(/^[^:]/)
136
+ if s4 != :failed
137
+ while s4 != :failed
138
+ s3 << s4
139
+ s4 = match_regexp(/^[^:]/)
140
+ end
141
+ else
142
+ s3 = :failed
143
+ end
144
+ if s3 != :failed
145
+ s4 = match_str(":")
146
+ if s4 != :failed
147
+ s5 = []
148
+ s6 = parse_nonl
149
+ while s6 != :failed
150
+ s5 << s6
151
+ s6 = parse_nonl
152
+ end
153
+ if s5 != :failed
154
+ s6 = parse_nl
155
+ if s6 != :failed
156
+ @reported_pos = s0
157
+ s0 = s1 = { "k" => s3.join, "v" => s5.join }
158
+ else
159
+ @current_pos = s0
160
+ s0 = :failed
161
+ end
162
+ else
163
+ @current_pos = s0
164
+ s0 = :failed
165
+ end
166
+ else
167
+ @current_pos = s0
168
+ s0 = :failed
169
+ end
170
+ else
171
+ @current_pos = s0
172
+ s0 = :failed
173
+ end
174
+ else
175
+ @current_pos = s0
176
+ s0 = :failed
177
+ end
178
+ else
179
+ @current_pos = s0
180
+ s0 = :failed
181
+ end
182
+ s0
183
+ end
184
+
185
+ def parse_csa1
186
+ s0 = @current_pos
187
+ s1 = parse_players
188
+ s1 = nil if s1 == :failed
189
+ if s1 != :failed
190
+ s2 = parse_initial_board
191
+ s2 = nil if s2 == :failed
192
+ if s2 != :failed
193
+ s3 = parse_moves
194
+ if s3 != :failed
195
+ @reported_pos = s0
196
+ s0 = s1 = -> (ply, ini, ms) {
197
+ ret = { "header" => {}, "initial" => ini, "moves" => ms }
198
+ if ply
199
+ ret["header"]["先手"] = ply[0] if ply[0]
200
+ ret["header"]["後手"] = ply[1] if ply[1]
201
+ end
202
+ ret
203
+ }.call(s1, s2, s3)
204
+ else
205
+ @current_pos = s0
206
+ s0 = :failed
207
+ end
208
+ else
209
+ @current_pos = s0
210
+ s0 = :failed
211
+ end
212
+ else
213
+ @current_pos = s0
214
+ s0 = :failed
215
+ end
216
+ s0
217
+ end
218
+
219
+ def parse_players
220
+ s0 = @current_pos
221
+ s1 = []
222
+ s2 = parse_comment
223
+ while s2 != :failed
224
+ s1 << s2
225
+ s2 = parse_comment
226
+ end
227
+ if s1 != :failed
228
+ s2 = @current_pos
229
+ s3 = match_str("N+")
230
+ if s3 != :failed
231
+ s4 = []
232
+ s5 = parse_nonl
233
+ while s5 != :failed
234
+ s4 << s5
235
+ s5 = parse_nonl
236
+ end
237
+ if s4 != :failed
238
+ s5 = parse_nl
239
+ if s5 != :failed
240
+ @reported_pos = s2
241
+ s2 = s3 = s4
242
+ else
243
+ @current_pos = s2
244
+ s2 = :failed
245
+ end
246
+ else
247
+ @current_pos = s2
248
+ s2 = :failed
249
+ end
250
+ else
251
+ @current_pos = s2
252
+ s2 = :failed
253
+ end
254
+ s2 = nil if s2 == :failed
255
+ if s2 != :failed
256
+ s3 = []
257
+ s4 = parse_comment
258
+ while s4 != :failed
259
+ s3 << s4
260
+ s4 = parse_comment
261
+ end
262
+ if s3 != :failed
263
+ s4 = @current_pos
264
+ s5 = match_str("N-")
265
+ if s5 != :failed
266
+ s6 = []
267
+ s7 = parse_nonl
268
+ while s7 != :failed
269
+ s6 << s7
270
+ s7 = parse_nonl
271
+ end
272
+ if s6 != :failed
273
+ s7 = parse_nl
274
+ if s7 != :failed
275
+ @reported_pos = s4
276
+ s4 = s5 = s6
277
+ else
278
+ @current_pos = s4
279
+ s4 = :failed
280
+ end
281
+ else
282
+ @current_pos = s4
283
+ s4 = :failed
284
+ end
285
+ else
286
+ @current_pos = s4
287
+ s4 = :failed
288
+ end
289
+ s4 = nil if s4 == :failed
290
+ if s4 != :failed
291
+ @reported_pos = s0
292
+ s0 = s1 = [(s2 ? s2.join : nil), (s4 ? s4.join : nil)]
293
+ else
294
+ @current_pos = s0
295
+ s0 = :failed
296
+ end
297
+ else
298
+ @current_pos = s0
299
+ s0 = :failed
300
+ end
301
+ else
302
+ @current_pos = s0
303
+ s0 = :failed
304
+ end
305
+ else
306
+ @current_pos = s0
307
+ s0 = :failed
308
+ end
309
+ s0
310
+ end
311
+
312
+ def parse_initial_board
313
+ s0 = @current_pos
314
+ s1 = []
315
+ s2 = parse_comment
316
+ while s2 != :failed
317
+ s1 << s2
318
+ s2 = parse_comment
319
+ end
320
+ if s1 != :failed
321
+ s2 = parse_hirate
322
+ if s2 == :failed
323
+ s2 = parse_ikkatsu
324
+ if s2 == :failed
325
+ s2 = @current_pos
326
+ s3 = match_str("")
327
+ if s3 != :failed
328
+ @reported_pos = s2
329
+ s3 = "NO"
330
+ end
331
+ s2 = s3
332
+ end
333
+ end
334
+ if s2 != :failed
335
+ s3 = parse_komabetsu
336
+ if s3 != :failed
337
+ s4 = []
338
+ s5 = parse_comment
339
+ while s5 != :failed
340
+ s4 << s5
341
+ s5 = parse_comment
342
+ end
343
+ if s4 != :failed
344
+ s5 = parse_teban
345
+ if s5 != :failed
346
+ s6 = parse_nl
347
+ if s6 != :failed
348
+ @reported_pos = s0
349
+ s0 = s1 = -> (data, koma, teban) {
350
+ if data == "NO"
351
+ data = koma
352
+ else
353
+ data["data"]["hands"] = koma["data"]["hands"]
354
+ end
355
+ data["data"]["color"] = teban
356
+ data
357
+ }.call(s2, s3, s5)
358
+ else
359
+ @current_pos = s0
360
+ s0 = :failed
361
+ end
362
+ else
363
+ @current_pos = s0
364
+ s0 = :failed
365
+ end
366
+ else
367
+ @current_pos = s0
368
+ s0 = :failed
369
+ end
370
+ else
371
+ @current_pos = s0
372
+ s0 = :failed
373
+ end
374
+ else
375
+ @current_pos = s0
376
+ s0 = :failed
377
+ end
378
+ else
379
+ @current_pos = s0
380
+ s0 = :failed
381
+ end
382
+ s0
383
+ end
384
+
385
+ def parse_hirate
386
+ s0 = @current_pos
387
+ s1 = match_str("PI")
388
+ if s1 != :failed
389
+ s2 = []
390
+ s3 = parse_xy_piece
391
+ while s3 != :failed
392
+ s2 << s3
393
+ s3 = parse_xy_piece
394
+ end
395
+ if s2 != :failed
396
+ s3 = parse_nl
397
+ if s3 != :failed
398
+ @reported_pos = s0
399
+ s0 = s1 = -> (ps) {
400
+ ret = { "preset" => "OTHER", "data" => { "board" => get_hirate } }
401
+ ps.each do |piece|
402
+ ret["data"]["board"][piece["xy"]["x"]-1][piece["xy"]["y"]-1] = {}
403
+ end
404
+ ret
405
+ }.call(s2)
406
+ else
407
+ @current_pos = s0
408
+ s0 = :failed
409
+ end
410
+ else
411
+ @current_pos = s0
412
+ s0 = :failed
413
+ end
414
+ else
415
+ @current_pos = s0
416
+ s0 = :failed
417
+ end
418
+ s0
419
+ end
420
+
421
+ def parse_ikkatsu
422
+ s0 = @current_pos
423
+ s1 = []
424
+ s2 = parse_ikkatsu_line
425
+ if s2 != :failed
426
+ while s2 != :failed
427
+ s1 << s2
428
+ s2 = parse_ikkatsu_line
429
+ end
430
+ else
431
+ s1 = :failed
432
+ end
433
+ if s1 != :failed
434
+ @reported_pos = s0
435
+ s1 = -> (lines) {
436
+ board = []
437
+ 9.times { |i|
438
+ line = []
439
+ 9.times { |j|
440
+ line << lines[j][8-i]
441
+ }
442
+ board << line
443
+ }
444
+ { "preset" => "OTHER", "data" => { "board" => board } }
445
+ }.call(s1)
446
+ end
447
+ s0 = s1
448
+ s0
449
+ end
450
+
451
+ def parse_ikkatsu_line
452
+ s0 = @current_pos
453
+ s1 = match_str("P")
454
+ if s1 != :failed
455
+ s2 = match_regexp(/^[1-9]/)
456
+ if s2 != :failed
457
+ s3 = []
458
+ s4 = parse_masu
459
+ if s4 != :failed
460
+ while s4 != :failed
461
+ s3 << s4
462
+ s4 = parse_masu
463
+ end
464
+ else
465
+ s3 = :failed
466
+ end
467
+ if s3 != :failed
468
+ s4 = parse_nl
469
+ if s4 != :failed
470
+ @reported_pos = s0
471
+ s0 = s1 = s3
472
+ else
473
+ @current_pos = s0
474
+ s0 = :failed
475
+ end
476
+ else
477
+ @current_pos = s0
478
+ s0 = :failed
479
+ end
480
+ else
481
+ @current_pos = s0
482
+ s0 = :failed
483
+ end
484
+ else
485
+ @current_pos = s0
486
+ s0 = :failed
487
+ end
488
+ s0
489
+ end
490
+
491
+ def parse_masu
492
+ s0 = @current_pos
493
+ s1 = parse_teban
494
+ if s1 != :failed
495
+ s2 = parse_piece
496
+ if s2 != :failed
497
+ @reported_pos = s0
498
+ s0 = s1 = { "color" => s1, "kind" => s2 }
499
+ else
500
+ @current_pos = s0
501
+ s0 = :failed
502
+ end
503
+ else
504
+ @current_pos = s0
505
+ s0 = :failed
506
+ end
507
+ if s0 == :failed
508
+ s0 = @current_pos
509
+ s1 = match_str(" * ")
510
+ if s1 != :failed
511
+ @reported_pos = s0
512
+ s1 = {}
513
+ end
514
+ s0 = s1
515
+ end
516
+ s0
517
+ end
518
+
519
+ def parse_komabetsu
520
+ s0 = @current_pos
521
+ s1 = []
522
+ s2 = parse_komabetsu_line
523
+ while s2 != :failed
524
+ s1 << s2
525
+ s2 = parse_komabetsu_line
526
+ end
527
+ if s1 != :failed
528
+ @reported_pos = s0
529
+ s1 = -> (lines) {
530
+ board = []
531
+ hands = [
532
+ {"FU"=>0,"KY"=>0,"KE"=>0,"GI"=>0,"KI"=>0,"KA"=>0,"HI"=>0},
533
+ {"FU"=>0,"KY"=>0,"KE"=>0,"GI"=>0,"KI"=>0,"KA"=>0,"HI"=>0}
534
+ ]
535
+ all = {"FU"=>18,"KY"=>4,"KE"=>4,"GI"=>4,"KI"=>4,"KA"=>2,"HI"=>2}
536
+ 9.times { |i|
537
+ line = []
538
+ 9.times { |j|
539
+ line << {}
540
+ }
541
+ board << line
542
+ }
543
+
544
+ lines.each do |line|
545
+ line["pieces"].each do |piece|
546
+ if piece["xy"]["x"] == 0
547
+ if piece["piece"] == "AL"
548
+ hands[line["teban"]] = all
549
+ return { "preset" => "OTHER", "data" => { "board" => board, "hands" => hands } }
550
+ end
551
+ obj = hands[line["teban"]]
552
+ obj[piece["piece"]] += 1
553
+ else
554
+ board[piece["xy"]["x"]-1][piece["xy"]["y"]-1] = { "color" => line["teban"], "kind" => piece["piece"] }
555
+ end
556
+ all[piece["piece"]] -= 1 if piece["piece"] != "OU"
557
+ end
558
+ end
559
+
560
+ { "preset" => "OTHER", "data" => { "board" => board, "hands" => hands } }
561
+ }.call(s1)
562
+ end
563
+ s0 = s1
564
+ s0
565
+ end
566
+
567
+ def parse_komabetsu_line
568
+ s0 = @current_pos
569
+ s1 = match_str("P")
570
+ if s1 != :failed
571
+ s2 = parse_teban
572
+ if s2 != :failed
573
+ s3 = []
574
+ s4 = parse_xy_piece
575
+ if s4 != :failed
576
+ while s4 != :failed
577
+ s3 << s4
578
+ s4 = parse_xy_piece
579
+ end
580
+ else
581
+ s3 = :failed
582
+ end
583
+ if s3 != :failed
584
+ s4 = parse_nl
585
+ if s4 != :failed
586
+ @reported_pos = s0
587
+ s0 = s1 = { "teban" => s2, "pieces" => s3 }
588
+ else
589
+ @current_pos = s0
590
+ s0 = :failed
591
+ end
592
+ else
593
+ @current_pos = s0
594
+ s0 = :failed
595
+ end
596
+ else
597
+ @current_pos = s0
598
+ s0 = :failed
599
+ end
600
+ else
601
+ @current_pos = s0
602
+ s0 = :failed
603
+ end
604
+ s0
605
+ end
606
+
607
+ def parse_moves
608
+ s0 = @current_pos
609
+ s1 = parse_firstboard
610
+ if s1 != :failed
611
+ s2 = []
612
+ s3 = parse_move
613
+ while s3 != :failed
614
+ s2 << s3
615
+ s3 = parse_move
616
+ end
617
+ if s2 != :failed
618
+ s3 = []
619
+ s4 = parse_comment
620
+ while s4 != :failed
621
+ s3 << s4
622
+ s4 = parse_comment
623
+ end
624
+ if s3 != :failed
625
+ @reported_pos = s0
626
+ s0 = s1 = s2.unshift(s1)
627
+ else
628
+ @current_pos = s0
629
+ s0 = :failed
630
+ end
631
+ else
632
+ @current_pos = s0
633
+ s0 = :failed
634
+ end
635
+ else
636
+ @current_pos = s0
637
+ s0 = :failed
638
+ end
639
+ s0
640
+ end
641
+
642
+ def parse_firstboard
643
+ s0 = @current_pos
644
+ s1 = []
645
+ s2 = parse_comment
646
+ while s2 != :failed
647
+ s1 << s2
648
+ s2 = parse_comment
649
+ end
650
+ if s1 != :failed
651
+ @reported_pos = s0
652
+ s1 = s1.length > 0 ? { "comments" => s1 } : {}
653
+ end
654
+ s0 = s1
655
+ s0
656
+ end
657
+
658
+ def parse_move
659
+ s0 = @current_pos
660
+ s1 = parse_normal_move
661
+ s1 = parse_special_move if s1 == :failed
662
+ if s1 != :failed
663
+ s2 = parse_time
664
+ s2 = nil if s2 == :failed
665
+ if s2 != :failed
666
+ s3 = []
667
+ s4 = parse_comment
668
+ while s4 != :failed
669
+ s3 << s4
670
+ s4 = parse_comment
671
+ end
672
+ if s3 != :failed
673
+ @reported_pos = s0
674
+ s0 = s1 = -> (move, time, comments) {
675
+ ret = {}
676
+ ret["comments"] = comments if comments.length > 0
677
+ ret["time"] = time if time
678
+ if move["special"]
679
+ ret["special"] = move["special"]
680
+ else
681
+ ret["move"] = move
682
+ end
683
+ ret
684
+ }.call(s1, s2, s3)
685
+ else
686
+ @current_pos = s0
687
+ s0 = :failed
688
+ end
689
+ else
690
+ @current_pos = s0
691
+ s0 = :failed
692
+ end
693
+ else
694
+ @current_pos = s0
695
+ s0 = :failed
696
+ end
697
+ s0
698
+ end
699
+
700
+ def parse_normal_move
701
+ s0 = @current_pos
702
+ s1 = parse_teban
703
+ if s1 != :failed
704
+ s2 = parse_xy
705
+ if s2 != :failed
706
+ s3 = parse_xy
707
+ if s3 != :failed
708
+ s4 = parse_piece
709
+ if s4 != :failed
710
+ s5 = parse_nl
711
+ if s5 != :failed
712
+ @reported_pos = s0
713
+ s0 = s1 = -> (from, to, piece) {
714
+ ret = { "to" => to, "piece" => piece }
715
+ ret["from"] = from if from["x"] != 0
716
+ ret
717
+ }.call(s2, s3, s4)
718
+ else
719
+ @current_pos = s0
720
+ s0 = :failed
721
+ end
722
+ else
723
+ @current_pos = s0
724
+ s0 = :failed
725
+ end
726
+ else
727
+ @current_pos = s0
728
+ s0 = :failed
729
+ end
730
+ else
731
+ @current_pos = s0
732
+ s0 = :failed
733
+ end
734
+ else
735
+ @current_pos = s0
736
+ s0 = :failed
737
+ end
738
+ s0
739
+ end
740
+
741
+ def parse_special_move
742
+ s0 = @current_pos
743
+ s1 = match_str("%")
744
+ if s1 != :failed
745
+ s2 = []
746
+ s3 = match_regexp(/^[\-+_A-Z]/)
747
+ if s3 != :failed
748
+ while s3 != :failed
749
+ s2 << s3
750
+ s3 = match_regexp(/^[\-+_A-Z]/)
751
+ end
752
+ else
753
+ s2 = :failed
754
+ end
755
+ if s2 != :failed
756
+ s3 = parse_nl
757
+ if s3 != :failed
758
+ @reported_pos = s0
759
+ s0 = s1 = { "special" => s2.join }
760
+ else
761
+ @current_pos = s0
762
+ s0 = :failed
763
+ end
764
+ else
765
+ @current_pos = s0
766
+ s0 = :failed
767
+ end
768
+ else
769
+ @current_pos = s0
770
+ s0 = :failed
771
+ end
772
+ s0
773
+ end
774
+
775
+ def parse_teban
776
+ s0 = @current_pos
777
+ s1 = match_str("+")
778
+ if s1 != :failed
779
+ @reported_pos = s0
780
+ s1 = 0
781
+ end
782
+ s0 = s1
783
+ if s0 == :failed
784
+ s0 = @current_pos
785
+ s1 = match_str("-")
786
+ if s1 != :failed
787
+ @reported_pos = s0
788
+ s1 = 1
789
+ end
790
+ s0 = s1
791
+ end
792
+ s0
793
+ end
794
+
795
+ def parse_comment
796
+ s0 = @current_pos
797
+ s1 = match_str("'")
798
+ if s1 != :failed
799
+ s2 = []
800
+ s3 = parse_nonl
801
+ while s3 != :failed
802
+ s2 << s3
803
+ s3 = parse_nonl
804
+ end
805
+ if s2 != :failed
806
+ s3 = parse_nl
807
+ if s3 != :failed
808
+ @reported_pos = s0
809
+ s0 = s1 = s2.join
810
+ else
811
+ @current_pos = s0
812
+ s0 = :failed
813
+ end
814
+ else
815
+ @current_pos = s0
816
+ s0 = :failed
817
+ end
818
+ else
819
+ @current_pos = s0
820
+ s0 = :failed
821
+ end
822
+ s0
823
+ end
824
+
825
+ def parse_time
826
+ s0 = @current_pos
827
+ s1 = match_str("T")
828
+ if s1 != :failed
829
+ s2 = []
830
+ s3 = match_regexp(/^[0-9]/)
831
+ while s3 != :failed
832
+ s2 << s3
833
+ s3 = match_regexp(/^[0-9]/)
834
+ end
835
+ if s2 != :failed
836
+ s3 = parse_nl
837
+ if s3 != :failed
838
+ @reported_pos = s0
839
+ s0 = s1 = { "now" => sec2time(s2.join.to_i) }
840
+ else
841
+ @current_pos = s0
842
+ s0 = :failed
843
+ end
844
+ else
845
+ @current_pos = s0
846
+ s0 = :failed
847
+ end
848
+ else
849
+ @current_pos = s0
850
+ s0 = :failed
851
+ end
852
+ s0
853
+ end
854
+
855
+ def parse_xy
856
+ s0 = @current_pos
857
+ s1 = match_regexp(/^[0-9]/)
858
+ if s1 != :failed
859
+ s2 = match_regexp(/^[0-9]/)
860
+ if s2 != :failed
861
+ @reported_pos = s0
862
+ s0 = s1 = { "x" => s1.to_i, "y" => s2.to_i }
863
+ else
864
+ @current_pos = s0
865
+ s0 = :failed
866
+ end
867
+ else
868
+ @current_pos = s0
869
+ s0 = :failed
870
+ end
871
+ s0
872
+ end
873
+
874
+ def parse_piece
875
+ s0 = @current_pos
876
+ s1 = match_regexp(/^[A-Z]/)
877
+ if s1 != :failed
878
+ s2 = match_regexp(/^[A-Z]/)
879
+ if s2 != :failed
880
+ @reported_pos = s0
881
+ s0 = s1 = s1 + s2
882
+ else
883
+ @current_pos = s0
884
+ s0 = :failed
885
+ end
886
+ else
887
+ @current_pos = s0
888
+ s0 = :failed
889
+ end
890
+ s0
891
+ end
892
+
893
+ def parse_xy_piece
894
+ s0 = @current_pos
895
+ s1 = parse_xy
896
+ if s1 != :failed
897
+ s2 = parse_piece
898
+ if s2 != :failed
899
+ @reported_pos = s0
900
+ s0 = s1 = { "xy" => s1, "piece" => s2 }
901
+ else
902
+ @current_pos = s0
903
+ s0 = :failed
904
+ end
905
+ else
906
+ @current_pos = s0
907
+ s0 = :failed
908
+ end
909
+ s0
910
+ end
911
+
912
+ def parse_nl
913
+ s0 = @current_pos
914
+ s1 = match_str("\r")
915
+ s1 = nil if s1 == :failed
916
+ if s1 != :failed
917
+ s2 = match_str("\n")
918
+ if s2 != :failed
919
+ s0 = s1 = [s1, s2]
920
+ else
921
+ @current_pos = s0
922
+ s0 = :failed
923
+ end
924
+ else
925
+ @current_pos = s0
926
+ s0 = :failed
927
+ end
928
+ if s0 == :failed
929
+ s0 = @current_pos
930
+ s1 = []
931
+ s2 = match_str(" ")
932
+ while s2 != :failed
933
+ s1 << s2
934
+ s2 = match_str(" ")
935
+ end
936
+ if s1 != :failed
937
+ s2 = match_str(",")
938
+ if s2 != :failed
939
+ s0 = s1 = [s1, s2]
940
+ else
941
+ @current_pos = s0
942
+ s0 = :failed
943
+ end
944
+ else
945
+ @current_pos = s0
946
+ s0 = :failed
947
+ end
948
+ end
949
+ s0
950
+ end
951
+
952
+ def parse_nonl
953
+ match_regexp(/^[^\r\n]/)
954
+ end
955
+
956
+ protected
957
+
958
+ def sec2time(sec)
959
+ s = sec % 60
960
+ m = (sec-s) / 60
961
+ { "m" => m, "s" => s }
962
+ end
963
+
964
+ def get_hirate
965
+ [
966
+ [{"color" => 1,"kind" => "KY"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "KY"},],
967
+ [{"color" => 1,"kind" => "KE"},{"color" => 1,"kind" => "KA"},{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{"color" => 0,"kind" => "HI"},{"color" => 0,"kind" => "KE"},],
968
+ [{"color" => 1,"kind" => "GI"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "GI"},],
969
+ [{"color" => 1,"kind" => "KI"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "KI"},],
970
+ [{"color" => 1,"kind" => "OU"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "OU"},],
971
+ [{"color" => 1,"kind" => "KI"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "KI"},],
972
+ [{"color" => 1,"kind" => "GI"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "GI"},],
973
+ [{"color" => 1,"kind" => "KE"},{"color" => 1,"kind" => "HI"},{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{"color" => 0,"kind" => "KA"},{"color" => 0,"kind" => "KE"},],
974
+ [{"color" => 1,"kind" => "KY"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "KY"},],
975
+ ]
976
+ end
977
+
978
+ def normalize_header_key(key)
979
+ {
980
+ "EVENT" => "棋戦",
981
+ "SITE" => "場所",
982
+ "START_TIME" => "開始日時",
983
+ "END_TIME" => "終了日時",
984
+ "TIME_LIMIT" => "持ち時間",
985
+ }[key] || key
986
+ end
987
+ end
988
+ end