jkf 0.4.0 → 0.4.1

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.
@@ -2,8 +2,11 @@
2
2
 
3
3
  module Jkf::Parser
4
4
  class Kif < Base
5
+ include Kifuable
6
+
5
7
  def parse_root
6
- @input += "\n" if @input[-1] != "\n"
8
+ @input += "\n" unless @input.end_with?("\n")
9
+
7
10
  s0 = @current_pos
8
11
  s1 = []
9
12
  s2 = parse_skipline
@@ -11,108 +14,33 @@ module Jkf::Parser
11
14
  s1 << s2
12
15
  s2 = parse_skipline
13
16
  end
14
- if s1 != :failed
15
- s2 = []
17
+
18
+ s2 = []
19
+ s3 = parse_header
20
+ while s3 != :failed
21
+ s2 << s3
16
22
  s3 = parse_header
17
- while s3 != :failed
18
- s2 << s3
19
- s3 = parse_header
20
- end
21
- if s2 != :failed
22
- s3 = parse_initial_board
23
- s3 = nil if s3 == :failed
24
- if s3 != :failed
25
- s4 = []
26
- s5 = parse_header
27
- while s5 != :failed
28
- s4 << s5
29
- s5 = parse_header
30
- end
31
- if s4 != :failed
32
- s5 = parse_split
33
- s5 = nil if s5 == :failed
34
- if s5 != :failed
35
- s6 = parse_moves
36
- if s6 != :failed
37
- s7 = []
38
- s8 = parse_fork
39
- while s8 != :failed
40
- s7 << s8
41
- s8 = parse_fork
42
- end
43
- if s7 != :failed
44
- s8 = parse_nl
45
- s8 = nil if s8 == :failed
46
- if s8 != :failed
47
- @reported_pos = s0
48
- s1 = -> (headers, ini, headers2, moves, forks) {
49
- ret = { "header" => {}, "moves" => moves }
50
- headers.compact.each { |h| ret["header"][h["k"]] = h["v"] }
51
- headers2.compact.each { |h| ret["header"][h["k"]] = h["v"] }
52
- if ini
53
- ret["initial"] = ini
54
- elsif ret["header"]["手合割"]
55
- preset = preset2str(ret["header"]["手合割"])
56
- ret["initial"] = { "preset" => preset } if preset && preset != "OTHER"
57
- end
58
- if ret["initial"] && ret["initial"]["data"]
59
- if ret["header"]["手番"]
60
- ret["initial"]["data"]["color"] = ("下先".include?(ret["header"]["手番"]) ? 0 : 1)
61
- ret["header"].delete("手番")
62
- else
63
- ret["initial"]["data"]["color"] = 0
64
- end
65
- ret["initial"]["data"]["hands"] = [
66
- make_hand(ret["header"]["先手の持駒"] || ret["header"]["下手の持駒"]),
67
- make_hand(ret["header"]["後手の持駒"] || ret["header"]["上手の持駒"])
68
- ]
69
- %w(先手の持駒 下手の持駒 後手の持駒 上手の持駒).each do |key|
70
- ret["header"].delete(key)
71
- end
72
- end
73
- fork_stack = [{ "te" => 0, "moves" => moves }]
74
- forks.each do |f|
75
- now_fork = f
76
- _fork = fork_stack.pop
77
- _fork = fork_stack.pop while _fork["te"] > now_fork["te"]
78
- move = _fork["moves"][now_fork["te"] - _fork["te"]]
79
- move["forks"] ||= []
80
- move["forks"] << now_fork["moves"]
81
- fork_stack << _fork
82
- fork_stack << now_fork
83
- end
84
- reverse_color(ret['moves']) if ret["initial"] && ret["initial"]["data"] && ret["initial"]["data"]["color"] == 1
85
- ret
86
- }.call(s2, s3, s4, s6, s7)
87
- s0 = s1
88
- else
89
- @current_pos = s0
90
- s0 = :failed
91
- end
92
- else
93
- @current_pos = s0
94
- s0 = :failed
95
- end
96
- else
97
- @current_pos = s0
98
- s0 = :failed
99
- end
100
- else
101
- @current_pos = s0
102
- s0 = :failed
103
- end
104
- else
105
- @current_pos = s0
106
- s0 = :failed
107
- end
108
- else
109
- @current_pos = s0
110
- s0 = :failed
111
- end
112
- else
113
- @current_pos = s0
114
- s0 = :failed
115
- end
23
+ end
24
+ s3 = parse_initialboard
25
+ s3 = nil if s3 == :failed
26
+ s4 = []
27
+ s5 = parse_header
28
+ while s5 != :failed
29
+ s4 << s5
30
+ s5 = parse_header
31
+ end
32
+ parse_split
33
+ s6 = parse_moves
34
+ if s6 != :failed
35
+ s7 = []
36
+ s8 = parse_fork
37
+ while s8 != :failed
38
+ s7 << s8
39
+ s8 = parse_fork
40
+ end
41
+ parse_nl
42
+ @reported_pos = s0
43
+ s0 = transform_root(s2, s3, s4, s6, s7)
116
44
  else
117
45
  @current_pos = s0
118
46
  s0 = :failed
@@ -123,9 +51,9 @@ module Jkf::Parser
123
51
 
124
52
  def parse_header
125
53
  s0 = @current_pos
126
- s1 = []
127
54
  s2 = match_regexp(/^[^:\r\n]/)
128
55
  if s2 != :failed
56
+ s1 = []
129
57
  while s2 != :failed
130
58
  s1 << s2
131
59
  s2 = match_regexp(/^[^:\r\n]/)
@@ -134,24 +62,12 @@ module Jkf::Parser
134
62
  s1 = :failed
135
63
  end
136
64
  if s1 != :failed
137
- s2 = match_str(":")
138
- if s2 != :failed
139
- s3 = []
140
- s4 = parse_nonl
141
- while s4 != :failed
142
- s3 << s4
143
- s4 = parse_nonl
144
- end
145
- if s3 != :failed
146
- s4 = parse_nl
147
- if s4 != :failed
148
- @reported_pos = s0
149
- s1 = { "k" => s1.join, "v" => s3.join }
150
- s0 = s1
151
- else
152
- @current_pos = s0
153
- s0 = :failed
154
- end
65
+ if match_str(":") != :failed
66
+ s3 = parse_nonls
67
+ if parse_nl != :failed
68
+ @reported_pos = s0
69
+ s1 = { "k" => s1.join, "v" => s3.join }
70
+ s0 = s1
155
71
  else
156
72
  @current_pos = s0
157
73
  s0 = :failed
@@ -168,12 +84,10 @@ module Jkf::Parser
168
84
  s0 = @current_pos
169
85
  s1 = parse_turn
170
86
  if s1 != :failed
171
- s2 = match_str("手番")
172
- if s2 != :failed
173
- s3 = parse_nl
174
- if s3 != :failed
87
+ if match_str("手番") != :failed
88
+ if parse_nl != :failed
175
89
  @reported_pos = s0
176
- s0 = s1 = { "k" => "手番", "v" => s1 }
90
+ s0 = { "k" => "手番", "v" => s1 }
177
91
  else
178
92
  @current_pos = s0
179
93
  s0 = :failed
@@ -188,12 +102,10 @@ module Jkf::Parser
188
102
  end
189
103
  if s0 == :failed
190
104
  s0 = @current_pos
191
- s1 = match_str("盤面回転")
192
- if s1 != :failed
193
- s2 = parse_nl
194
- if s2 != :failed
105
+ if match_str("盤面回転") != :failed
106
+ if parse_nl != :failed
195
107
  @reported_pos = s0
196
- s0 = s1 = nil
108
+ s0 = nil
197
109
  else
198
110
  @current_pos = s0
199
111
  s0 = :failed
@@ -212,258 +124,15 @@ module Jkf::Parser
212
124
  match_regexp(/[先後上下]/)
213
125
  end
214
126
 
215
- def parse_initial_board
216
- s0 = s1 = @current_pos
217
- s2 = match_str(" ")
218
- if s2 != :failed
219
- s3 = []
220
- s4 = parse_nonl
221
- while s4 != :failed
222
- s3 << s4
223
- s4 = parse_nonl
224
- end
225
- if s3 != :failed
226
- s4 = parse_nl
227
- if s4 != :failed
228
- s1 = s2 = [s2, s3, s4]
229
- else
230
- @current_pos = s1
231
- s1 = :failed
232
- end
233
- else
234
- @current_pos = s1
235
- s1 = :failed
236
- end
237
- else
238
- @current_pos = s1
239
- s1 = :failed
240
- end
241
- if s1 == :failed
242
- s1 = nil
243
- end
244
- if s1 != :failed
245
- s2 = @current_pos
246
- s3 = match_str("+")
247
- if s3 != :failed
248
- s4 = []
249
- s5 = parse_nonl
250
- while s5 != :failed
251
- s4 << s5
252
- s5 = parse_nonl
253
- end
254
- if s4 != :failed
255
- s5 = parse_nl
256
- if s5 != :failed
257
- s2 = s3 = [s3, s4, s5]
258
- else
259
- @current_pos = s2
260
- s2 = :failed
261
- end
262
- else
263
- @current_pos = s2
264
- s2 = :failed
265
- end
266
- else
267
- @current_pos = s2
268
- s2 = :failed
269
- end
270
- s2 = nil if s2 == :failed
271
- if s2 != :failed
272
- s3 = []
273
- s4 = parse_ikkatsu_line
274
- if s4 != :failed
275
- while s4 != :failed
276
- s3 << s4
277
- s4 = parse_ikkatsu_line
278
- end
279
- else
280
- s3 = :failed
281
- end
282
- if s3 != :failed
283
- s4 = @current_pos
284
- s5 = match_str("+")
285
- if s5 != :failed
286
- s6 = []
287
- s7 = parse_nonl
288
- while s7 != :failed
289
- s6 << s7
290
- s7 = parse_nonl
291
- end
292
- if s6 != :failed
293
- s7 = parse_nl
294
- if s7 != :failed
295
- s4 = s5 = [s5, s6, s7]
296
- else
297
- @current_pos = s4
298
- s4 = :failed
299
- end
300
- else
301
- @current_pos = s4
302
- s4 = :failed
303
- end
304
- else
305
- @current_pos = s4
306
- s4 = :failed
307
- end
308
- s4 = nil if s4 == :failed
309
- if s4 != :failed
310
- @reported_pos = s0
311
- s1 = -> (lines) {
312
- ret = [];
313
- 9.times { |i|
314
- line = [];
315
- 9.times { |j|
316
- line << lines[j][8-i]
317
- }
318
- ret << line
319
- }
320
- { "preset" => "OTHER", "data" => { "board" => ret } }
321
- }.call(s3)
322
- s0 = s1
323
- else
324
- @current_pos = s0
325
- s0 = :failed
326
- end
327
- else
328
- @current_pos = s0
329
- s0 = :failed
330
- end
331
- else
332
- @current_pos = s0
333
- s0 = :failed
334
- end
335
- else
336
- @current_pos = s0
337
- s0 = :failed
338
- end
339
-
340
- s0
341
- end
342
-
343
- def parse_ikkatsu_line
344
- s0 = @current_pos
345
- s1 = match_str("|")
346
- if s1 != :failed
347
- s2 = []
348
- s3 = parse_masu
349
- if s3 != :failed
350
- while s3 != :failed
351
- s2 << s3
352
- s3 = parse_masu
353
- end
354
- else
355
- s2 = :failed
356
- end
357
- if s2 != :failed
358
- s3 = match_str("|")
359
- if s3 != :failed
360
- s4 = []
361
- s5 = parse_nonl
362
- if s5 != :failed
363
- while s5 != :failed
364
- s4 << s5
365
- s5 = parse_nonl
366
- end
367
- else
368
- s4 = :failed
369
- end
370
- if s4 != :failed
371
- s5 = parse_nl
372
- if s5 != :failed
373
- @reported_pos = s0
374
- s0 = s1 = s2
375
- else
376
- @current_pos = s0
377
- s0 = :failed
378
- end
379
- else
380
- @current_pos = s0
381
- s0 = :failed
382
- end
383
- else
384
- @current_pos = s0
385
- s0 = :failed
386
- end
387
- else
388
- @current_pos = s0
389
- s0 = :failed
390
- end
391
- else
392
- @current_pos = s0
393
- s0 = :failed
394
- end
395
-
396
- s0
397
- end
398
-
399
- def parse_masu
400
- s0 = @current_pos
401
- s1 = parse_teban
402
- if s1 != :failed
403
- s2 = parse_piece
404
- if s2 != :failed
405
- @reported_pos = s0
406
- s0 = s1 = { "color" => s1, "kind" => s2 }
407
- else
408
- @current_pos = s0
409
- s0 = :failed
410
- end
411
- else
412
- @current_pos = s0
413
- s0 = :failed
414
- end
415
- if s0 == :failed
416
- s0 = @current_pos
417
- s1 = match_str(" ・")
418
- if s1 != :failed
419
- @reported_pos = s0
420
- s1 = {}
421
- end
422
- s0 = s1
423
- end
424
-
425
- s0
426
- end
427
-
428
- def parse_teban
429
- s0 = @current_pos
430
- s1 = match_str(" ")
431
- if s1 == :failed
432
- s1 = match_str("+")
433
- s1 = match_str("^") if s1 == :failed
434
- end
435
- if s1 != :failed
436
- @reported_pos = s0
437
- s1 = 0
438
- end
439
- s0 = s1
440
- if s0 == :failed
441
- s0 = @current_pos
442
- s1 = match_str("v")
443
- s1 = match_str("V") if s1 == :failed
444
- if s1 != :failed
445
- @reported_pos = s0
446
- s1 = 1
447
- end
448
- s0 = s1
449
- end
450
- s0
451
- end
452
-
453
127
  def parse_split
454
128
  s0 = @current_pos
455
129
  s1 = match_str("手数----指手--")
456
130
  if s1 != :failed
457
131
  s2 = match_str("-------消費時間--")
458
132
  s2 = nil if s2 == :failed
459
- if s2 != :failed
460
- s3 = parse_nl
461
- if s3 != :failed
462
- s0 = s1 = [s1, s2, s3]
463
- else
464
- @current_pos = s0
465
- s0 = :failed
466
- end
133
+ s3 = parse_nl
134
+ if s3 != :failed
135
+ s0 = [s1, s2, s3]
467
136
  else
468
137
  @current_pos = s0
469
138
  s0 = :failed
@@ -479,33 +148,16 @@ module Jkf::Parser
479
148
  s0 = @current_pos
480
149
  s1 = parse_firstboard
481
150
  if s1 != :failed
482
- s2 = parse_split
483
- s2 = nil if s2 == :failed
484
- if s2 != :failed
485
- s3 = []
486
- s4 = parse_move
487
- while s4 != :failed
488
- s3 << s4
489
- s4 = parse_move
490
- end
491
- if s3 != :failed
492
- s4 = parse_result
493
- s4 = nil if s4 == :failed
494
- if s4 != :failed
495
- @reported_pos = s0
496
- s0 = s1 = s3.unshift(s1)
497
- else
498
- @current_pos = s0
499
- s0 = :failed
500
- end
501
- else
502
- @current_pos = s0
503
- s0 = :failed
504
- end
505
- else
506
- @current_pos = s0
507
- s0 = :failed
151
+ parse_split
152
+ s2 = []
153
+ s3 = parse_move
154
+ while s3 != :failed
155
+ s2 << s3
156
+ s3 = parse_move
508
157
  end
158
+ parse_result
159
+ @reported_pos = s0
160
+ s0 = s2.unshift(s1)
509
161
  else
510
162
  @current_pos = s0
511
163
  s0 = :failed
@@ -521,22 +173,9 @@ module Jkf::Parser
521
173
  s1 << s2
522
174
  s2 = parse_comment
523
175
  end
524
- if s1 != :failed
525
- s2 = parse_pointer
526
- if s2 == :failed
527
- s2 = nil
528
- end
529
- if s2 != :failed
530
- @reported_pos = s0
531
- s0 = s1 = s1.length == 0 ? {} : { "comments" => s1 }
532
- else
533
- @current_pos = s0
534
- s0 = :failed
535
- end
536
- else
537
- @current_pos = s0
538
- s0 = :failed
539
- end
176
+ parse_pointer
177
+ @reported_pos = s0
178
+ s0 = s1.empty? ? {} : { "comments" => s1 }
540
179
  s0
541
180
  end
542
181
 
@@ -550,160 +189,56 @@ module Jkf::Parser
550
189
  s2 << s3
551
190
  s3 = parse_comment
552
191
  end
553
- if s2 != :failed
554
- s3 = parse_pointer
555
- s3 = nil if s3 == :failed
556
- if s3 != :failed
557
- @reported_pos = s0
558
- s1 = -> (line, c) {
559
- ret = {}
560
- ret["comments"] = c if c.length > 0
561
- if line["move"].is_a? Hash
562
- ret["move"] = line["move"]
563
- else
564
- ret["special"] = special2csa(line["move"])
565
- end
566
- ret["time"] = line["time"] if line["time"]
567
- ret
568
- }.call(s1, s2)
569
- s0 = s1
570
- else
571
- @current_pos = s0
572
- s0 = :failed
573
- end
574
- else
575
- @current_pos = s0
576
- s0 = :failed
577
- end
578
- else
579
- @current_pos = s0
580
- s0 = :failed
581
- end
582
- s0
583
- end
584
-
585
- def parse_pointer
586
- s0 = @current_pos
587
- s1 = match_str("&")
588
- if s1 != :failed
589
- s2 = []
590
- s3 = parse_nonl
591
- while s3 != :failed
592
- s2 << s3
593
- s3 = parse_nonl
594
- end
595
- if s2 != :failed
596
- s3 = parse_nl
597
- if s3 != :failed
598
- s0 = s1 = [s1, s2, s3]
599
- else
600
- @current_pos = s0
601
- s0 = :failed
602
- end
603
- else
604
- @current_pos = s0
605
- s0 = :failed
606
- end
192
+ parse_pointer
193
+ @reported_pos = s0
194
+ s0 = transform_move(s1, s2)
607
195
  else
608
- @current_pos = s0
609
- s0 = :failed
610
- end
611
- s0
612
- end
613
-
614
- def parse_line
615
- s0 = @current_pos
616
- s1 = []
617
- s2 = match_str(" ")
618
- while s2 != :failed
619
- s1 << s2
620
- s2 = match_str(" ")
621
- end
622
- if s1 != :failed
623
- s2 = parse_te
624
- if s2 != :failed
625
- s3 = []
626
- s4 = match_str(" ")
627
- while s4 != :failed
628
- s3 << s4
629
- s4 = match_str(" ")
630
- end
631
- if s3 != :failed
632
- s4 = @current_pos
633
- s5 = parse_fugou
634
- if s5 != :failed
635
- s6 = parse_from
636
- if s6 != :failed
637
- @reported_pos = s4
638
- s5 = -> (teban, fugou, from) {
639
- ret = { "color" => teban2color(teban.join), "piece" => fugou["piece"] }
640
- if fugou["to"]
641
- ret["to"] = fugou["to"]
642
- else
643
- ret["same"] = true
644
- end
645
- ret["promote"] = true if fugou["promote"]
646
- ret["from"] = from if from
647
- ret
648
- }.call(s2, s5, s6)
649
- s4 = s5
650
- else
651
- @current_pos = s4
652
- s4 = :failed
653
- end
654
- else
655
- @current_pos = s4
656
- s4 = :failed
657
- end
658
- if s4 == :failed
659
- s4 = @current_pos
660
- s5 = []
661
- s6 = match_regexp(/^[^\r\n ]/)
662
- while s6 != :failed
663
- s5 << s6
664
- s6 = match_regexp(/^[^\r\n ]/)
665
- end
666
- @reported_pos = s4
667
- s4 = s5 = s5.join
668
- end
669
- if s4 != :failed
670
- s5 = []
671
- s6 = match_str(" ")
672
- while s6 != :failed
673
- s5 << s6
674
- s6 = match_str(" ")
675
- end
676
- if s5 != :failed
677
- s6 = parse_time
678
- s6 = nil if s6 == :failed
679
- if s6 != :failed
680
- s7 = match_str("+")
681
- s7 = nil if s7 == :failed
682
- if s7 != :failed
683
- s8 = parse_nl
684
- if s8 != :failed
685
- @reported_pos = s0
686
- s0 = s1 = { "move" => s4, "time" => s6 }
687
- else
688
- @current_pos = s0
689
- s0 = :failed
690
- end
691
- else
692
- @current_pos = s0
693
- s0 = :failed
694
- end
695
- else
696
- @current_pos = s0
697
- s0 = :failed
698
- end
699
- else
700
- @current_pos = s0
701
- s0 = :failed
702
- end
703
- else
704
- @current_pos = s0
705
- s0 = :failed
706
- end
196
+ @current_pos = s0
197
+ s0 = :failed
198
+ end
199
+ s0
200
+ end
201
+
202
+ def parse_line
203
+ s0 = @current_pos
204
+ match_spaces
205
+ s2 = parse_te
206
+ if s2 != :failed
207
+ match_spaces
208
+ s4 = @current_pos
209
+ s5 = parse_fugou
210
+ if s5 != :failed
211
+ s6 = parse_from
212
+ if s6 != :failed
213
+ @reported_pos = s4
214
+ s4 = transform_teban_fugou_from(s2, s5, s6)
215
+ else
216
+ @current_pos = s4
217
+ s4 = :failed
218
+ end
219
+ else
220
+ @current_pos = s4
221
+ s4 = :failed
222
+ end
223
+ if s4 == :failed
224
+ s4 = @current_pos
225
+ s5 = []
226
+ s6 = match_regexp(/^[^\r\n ]/)
227
+ while s6 != :failed
228
+ s5 << s6
229
+ s6 = match_regexp(/^[^\r\n ]/)
230
+ end
231
+ @reported_pos = s4
232
+ s4 = s5.join
233
+ end
234
+ if s4 != :failed
235
+ match_spaces
236
+ s6 = parse_time
237
+ s6 = nil if s6 == :failed
238
+ match_str("+")
239
+ if parse_nl != :failed
240
+ @reported_pos = s0
241
+ s0 = { "move" => s4, "time" => s6 }
707
242
  else
708
243
  @current_pos = s0
709
244
  s0 = :failed
@@ -720,17 +255,7 @@ module Jkf::Parser
720
255
  end
721
256
 
722
257
  def parse_te
723
- s0 = []
724
- s1 = match_regexp(/^[0-9]/)
725
- if s1 != :failed
726
- while s1 != :failed
727
- s0 << s1
728
- s1 = match_regexp(/^[0-9]/)
729
- end
730
- else
731
- s0 = :failed
732
- end
733
- s0
258
+ match_digits!
734
259
  end
735
260
 
736
261
  def parse_fugou
@@ -741,13 +266,8 @@ module Jkf::Parser
741
266
  if s2 != :failed
742
267
  s3 = match_str("成")
743
268
  s3 = nil if s3 == :failed
744
- if s3 != :failed
745
- @reported_pos = s0
746
- s0 = s1 = { "to" => s1, "piece" => s2, "promote" => !!s3 }
747
- else
748
- @current_pos = s0
749
- s0 = :failed
750
- end
269
+ @reported_pos = s0
270
+ s0 = { "to" => s1, "piece" => s2, "promote" => !!s3 }
751
271
  else
752
272
  @current_pos = s0
753
273
  s0 = :failed
@@ -766,7 +286,7 @@ module Jkf::Parser
766
286
  s2 = parse_numkan
767
287
  if s2 != :failed
768
288
  @reported_pos = s0
769
- s0 = s1 = { "x" => s1, "y" => s2 }
289
+ s0 = { "x" => s1, "y" => s2 }
770
290
  else
771
291
  @current_pos = s0
772
292
  s0 = :failed
@@ -787,46 +307,6 @@ module Jkf::Parser
787
307
  s0
788
308
  end
789
309
 
790
- def parse_num
791
- s0 = @current_pos
792
- s1 = match_regexp(/^[123456789]/)
793
- if s1 != :failed
794
- @reported_pos = s0
795
- s1 = zen2n(s1)
796
- end
797
- s1
798
- end
799
-
800
- def parse_numkan
801
- s0 = @current_pos
802
- s1 = match_regexp(/^[一二三四五六七八九]/)
803
- if s1 != :failed
804
- @reported_pos = s0
805
- s1 = kan2n(s1)
806
- end
807
- s1
808
- end
809
-
810
- def parse_piece
811
- s0 = @current_pos
812
- s1 = match_str("成")
813
- s1 = "" if s1 == :failed
814
- if s1 != :failed
815
- s2 = match_regexp(/^[歩香桂銀金角飛王玉と杏圭全馬竜龍]/)
816
- if s2 != :failed
817
- @reported_pos = s0
818
- s0 = s1 = kind2csa(s1+s2)
819
- else
820
- @current_pos = s0
821
- s0 = :failed
822
- end
823
- else
824
- @current_pos = s0
825
- s0 = :failed
826
- end
827
- s0
828
- end
829
-
830
310
  def parse_from
831
311
  s0 = @current_pos
832
312
  s1 = match_str("打")
@@ -837,16 +317,14 @@ module Jkf::Parser
837
317
  s0 = s1
838
318
  if s0 == :failed
839
319
  s0 = @current_pos
840
- s1 = match_str("(")
841
- if s1 != :failed
320
+ if match_str("(") != :failed
842
321
  s2 = match_regexp(/^[1-9]/)
843
322
  if s2 != :failed
844
323
  s3 = match_regexp(/^[1-9]/)
845
324
  if s3 != :failed
846
- s4 = match_str(")")
847
- if s4 != :failed
325
+ if match_str(")") != :failed
848
326
  @reported_pos = s0
849
- s0 = s1 = { "x" => s2.to_i, "y" => s3.to_i }
327
+ s0 = { "x" => s2.to_i, "y" => s3.to_i }
850
328
  else
851
329
  @current_pos = s0
852
330
  s0 = :failed
@@ -869,30 +347,17 @@ module Jkf::Parser
869
347
 
870
348
  def parse_time
871
349
  s0 = @current_pos
872
- s1 = match_str("(")
873
- if s1 != :failed
874
- s2 = []
875
- s3 = match_str(" ")
876
- while s3 != :failed
877
- s2 << s3
878
- s3 = match_str(" ")
879
- end
880
- if s2 != :failed
881
- s3 = parse_ms
882
- if s3 != :failed
883
- s4 = match_str("/")
884
- if s4 != :failed
885
- s5 = parse_hms
886
- s5 = parse_ms(with_hour: true) if s5 == :failed
887
- if s5 != :failed
888
- s6 = match_str(")")
889
- if s6 != :failed
890
- @reported_pos = s0
891
- s0 = s1 = { "now" => s3, "total" => s5 }
892
- else
893
- @current_pos = s0
894
- s0 = :failed
895
- end
350
+ if match_str("(") != :failed
351
+ match_spaces
352
+ s3 = parse_ms
353
+ if s3 != :failed
354
+ if match_str("/") != :failed
355
+ s5 = parse_hms
356
+ s5 = parse_ms(with_hour: true) if s5 == :failed
357
+ if s5 != :failed
358
+ if match_str(")") != :failed
359
+ @reported_pos = s0
360
+ s0 = { "now" => s3, "total" => s5 }
896
361
  else
897
362
  @current_pos = s0
898
363
  s0 = :failed
@@ -918,46 +383,17 @@ module Jkf::Parser
918
383
 
919
384
  def parse_hms
920
385
  s0 = @current_pos
921
- s1 = []
922
- s2 = match_regexp(/^[0-9]/)
923
- if s2 != :failed
924
- while s2 != :failed
925
- s1 << s2
926
- s2 = match_regexp(/^[0-9]/)
927
- end
928
- else
929
- s1 = :failed
930
- end
386
+ s1 = match_digits!
931
387
 
932
388
  if s1 != :failed
933
- s2 = match_str(":")
934
- if s2 != :failed
935
- s3 = []
936
- s4 = match_regexp(/^[0-9]/)
937
- if s4 != :failed
938
- while s4 != :failed
939
- s3 << s4
940
- s4 = match_regexp(/^[0-9]/)
941
- end
942
- else
943
- s3 = :failed
944
- end
389
+ if match_str(":") != :failed
390
+ s3 = match_digits!
945
391
  if s3 != :failed
946
- s4 = match_str(":")
947
- if s4 != :failed
948
- s5 = []
949
- s6 = match_regexp(/^[0-9]/)
950
- if s6 != :failed
951
- while s6 != :failed
952
- s5 << s6
953
- s6 = match_regexp(/^[0-9]/)
954
- end
955
- else
956
- s5 = :failed
957
- end
392
+ if match_str(":") != :failed
393
+ s5 = match_digits!
958
394
  if s5 != :failed
959
395
  @reported_pos = s0
960
- s0 = s1 = { "h" => s1.join.to_i, "m" => s3.join.to_i, "s" => s5.join.to_i }
396
+ s0 = { "h" => s1.join.to_i, "m" => s3.join.to_i, "s" => s5.join.to_i }
961
397
  else
962
398
  @current_pos = s0
963
399
  s0 = :failed
@@ -983,29 +419,10 @@ module Jkf::Parser
983
419
 
984
420
  def parse_ms(with_hour: false)
985
421
  s0 = @current_pos
986
- s1 = []
987
- s2 = match_regexp(/^[0-9]/)
988
- if s2 != :failed
989
- while s2 != :failed
990
- s1 << s2
991
- s2 = match_regexp(/^[0-9]/)
992
- end
993
- else
994
- s1 = :failed
995
- end
422
+ s1 = match_digits!
996
423
  if s1 != :failed
997
- s2 = match_str(":")
998
- if s2 != :failed
999
- s3 = []
1000
- s4 = match_regexp(/^[0-9]/)
1001
- if s4 != :failed
1002
- while s4 != :failed
1003
- s3 << s4
1004
- s4 = match_regexp(/^[0-9]/)
1005
- end
1006
- else
1007
- s3 = :failed
1008
- end
424
+ if match_str(":") != :failed
425
+ s3 = match_digits!
1009
426
  if s3 != :failed
1010
427
  @reported_pos = s0
1011
428
  m = s1.join.to_i
@@ -1013,9 +430,9 @@ module Jkf::Parser
1013
430
  if with_hour
1014
431
  h = m / 60
1015
432
  m = m % 60
1016
- s0 = s1 = { "h" => h, "m" => m, "s" => s }
433
+ s0 = { "h" => h, "m" => m, "s" => s }
1017
434
  else
1018
- s0 = s1 = { "m" => m, "s" => s }
435
+ s0 = { "m" => m, "s" => s }
1019
436
  end
1020
437
  else
1021
438
  @current_pos = s0
@@ -1034,24 +451,11 @@ module Jkf::Parser
1034
451
 
1035
452
  def parse_comment
1036
453
  s0 = @current_pos
1037
- s1 = match_str("*")
1038
- if s1 != :failed
1039
- s2 = []
1040
- s3 = parse_nonl
1041
- while s3 != :failed
1042
- s2 << s3
1043
- s3 = parse_nonl
1044
- end
1045
- if s2 != :failed
1046
- s3 = parse_nl
1047
- if s3 != :failed
1048
- @reported_pos = s0
1049
- s1 = s2.join
1050
- s0 = s1
1051
- else
1052
- @current_pos = s0
1053
- s0 = :failed
1054
- end
454
+ if match_str("*") != :failed
455
+ s2 = parse_nonls
456
+ if parse_nl != :failed
457
+ @reported_pos = s0
458
+ s0 = s2.join
1055
459
  else
1056
460
  @current_pos = s0
1057
461
  s0 = :failed
@@ -1064,22 +468,10 @@ module Jkf::Parser
1064
468
  s0 = @current_pos
1065
469
  s1 = match_str("&")
1066
470
  if s1 != :failed
1067
- s2 = []
1068
- s3 = parse_nonl
1069
- while s3 != :failed
1070
- s2 << s3
1071
- s3 = parse_nonl
1072
- end
1073
-
1074
- if s2 != :failed
1075
- s3 = parse_nl
1076
- if s3 != :failed
1077
- @reported_pos = s0
1078
- s0 = s1 = "&" + s2.join
1079
- else
1080
- @current_pos = s0
1081
- s0 = :failed
1082
- end
471
+ s2 = parse_nonls
472
+ if parse_nl != :failed
473
+ @reported_pos = s0
474
+ s0 = "&" + s2.join
1083
475
  else
1084
476
  @current_pos = s0
1085
477
  s0 = :failed
@@ -1092,226 +484,18 @@ module Jkf::Parser
1092
484
  s0
1093
485
  end
1094
486
 
1095
- def parse_result
487
+ def parse_fork
1096
488
  s0 = @current_pos
1097
- s1 = match_str("まで")
1098
-
1099
- if s1 != :failed
1100
- s2 = []
1101
- s3 = match_regexp(/^[0-9]/)
489
+ if match_str("変化:") != :failed
490
+ match_spaces
491
+ s3 = parse_te
1102
492
  if s3 != :failed
1103
- while s3 != :failed
1104
- s2 << s3
1105
- s3 = match_regexp(/^[0-9]/)
1106
- end
1107
- else
1108
- s2 = :failed
1109
- end
1110
- if s2 != :failed
1111
- s3 = match_str("手")
1112
- if s3 != :failed
1113
- s4 = @current_pos
1114
- s5 = match_str("で")
1115
- if s5 != :failed
1116
- s6 = parse_turn
493
+ if match_str("手") != :failed
494
+ if parse_nl != :failed
495
+ s6 = parse_moves
1117
496
  if s6 != :failed
1118
- s7 = match_str("手の")
1119
- if s7 != :failed
1120
- s8 = @current_pos
1121
- s9 = match_str("勝ち")
1122
- if s9 != :failed
1123
- @reported_pos = s8
1124
- s9 = "TORYO"
1125
- end
1126
- s8 = s9
1127
- if s8 == :failed
1128
- s8 = @current_pos
1129
- s9 = match_str("反則")
1130
- if s9 != :failed
1131
- s10 = @current_pos
1132
- s11 = match_str("勝ち")
1133
- if s11 != :failed
1134
- @reported_pos = s10
1135
- s11 = "ILLEGAL_ACTION"
1136
- end
1137
- s10 = s11
1138
- if s10 == :failed
1139
- s10 = @current_pos
1140
- s11 = match_str("負け")
1141
- if s11 != :failed
1142
- @reported_pos = s10
1143
- s11 = "ILLEGAL_MOVE"
1144
- end
1145
- s10 = s11
1146
- end
1147
- if s10 != :failed
1148
- @reported_pos = s8
1149
- s8 = s9 = s10
1150
- else
1151
- @current_pos = s8
1152
- s8 = :failed
1153
- end
1154
- else
1155
- @current_pos = s8
1156
- s8 = :failed
1157
- end
1158
- end
1159
- if s8 != :failed
1160
- @reported_pos = s4
1161
- s4 = s5 = s8
1162
- else
1163
- @current_pos = s4
1164
- s4 = :failed
1165
- end
1166
- else
1167
- @current_pos = s4
1168
- s4 = :failed
1169
- end
1170
- else
1171
- @current_pos = s4
1172
- s4 = :failed
1173
- end
1174
- else
1175
- @current_pos = s4
1176
- s4 = :failed
1177
- end
1178
- if s4 == :failed
1179
- s4 = @current_pos
1180
- s5 = match_str("で時間切れにより")
1181
- if s5 != :failed
1182
- s6 = parse_turn
1183
- if s6 != :failed
1184
- s7 = match_str("手の勝ち")
1185
- if s7 != :failed
1186
- @reported_pos = s4
1187
- s4 = s5 = "TIME_UP"
1188
- else
1189
- @current_pos = s4
1190
- s4 = :failed
1191
- end
1192
- else
1193
- @current_pos = s4
1194
- s4 = :failed
1195
- end
1196
- else
1197
- @current_pos = s4
1198
- s4 = :failed
1199
- end
1200
- if s4 == :failed
1201
- s4 = @current_pos
1202
- s5 = match_str("で中断")
1203
- if s5 != :failed
1204
- @reported_pos = s4
1205
- s5 = "CHUDAN"
1206
- end
1207
- s4 = s5
1208
- if s4 == :failed
1209
- s4 = @current_pos
1210
- s5 = match_str("で持将棋")
1211
- if s5 != :failed
1212
- @reported_pos = s4
1213
- s5 = "JISHOGI"
1214
- end
1215
- s4 = s5
1216
- if s4 == :failed
1217
- s4 = @current_pos
1218
- s5 = match_str("で千日手")
1219
- if s5 != :failed
1220
- @reported_pos = s4
1221
- s5 = "SENNICHITE"
1222
- end
1223
- s4 = s5
1224
- if s4 == :failed
1225
- s4 = @current_pos
1226
- s5 = match_str("で")
1227
- s5 = nil if s5 == :failed
1228
- if s5 != :failed
1229
- s6 = match_str("詰")
1230
- if s6 != :failed
1231
- s7 = match_str("み")
1232
- s7 = nil if s7 == :failed
1233
- if s7 != :failed
1234
- @reported_pos = s4
1235
- s4 = s5 = "TSUMI"
1236
- else
1237
- @current_pos = s4
1238
- s4 = :failed
1239
- end
1240
- else
1241
- @current_pos = s4
1242
- s4 = :failed
1243
- end
1244
- else
1245
- @current_pos = s4
1246
- s4 = :failed
1247
- end
1248
- if s4 == :failed
1249
- s4 = @current_pos
1250
- s5 = match_str("で不詰")
1251
- if s5 != :failed
1252
- @reported_pos = s4
1253
- s5 = "FUZUMI"
1254
- end
1255
- s4 = s5
1256
- end
1257
- end
1258
- end
1259
- end
1260
- end
1261
- end
1262
- if s4 != :failed
1263
- s5 = parse_nl
1264
- if s5 != :failed
1265
497
  @reported_pos = s0
1266
- s0 = s1 = s4
1267
- else
1268
- @current_pos = s0
1269
- s0 = :failed
1270
- end
1271
- else
1272
- @current_pos = s0
1273
- s0 = :failed
1274
- end
1275
- else
1276
- @current_pos = s0
1277
- s0 = :failed
1278
- end
1279
- else
1280
- @current_pos = s0
1281
- s0 = :failed
1282
- end
1283
- else
1284
- @current_pos = s0
1285
- s0 = :failed
1286
- end
1287
- s0
1288
- end
1289
-
1290
- def parse_fork
1291
- s0 = @current_pos
1292
- s1 = match_str("変化:")
1293
- if s1 != :failed
1294
- s2 = []
1295
- s3 = match_str(" ")
1296
- while s3 != :failed
1297
- s2 << s3
1298
- s3 = match_str(" ")
1299
- end
1300
- if s2 != :failed
1301
- s3 = parse_te
1302
- if s3 != :failed
1303
- s4 = match_str("手")
1304
- if s4 != :failed
1305
- s5 = parse_nl
1306
- if s5 != :failed
1307
- s6 = parse_moves
1308
- if s6 != :failed
1309
- @reported_pos = s0
1310
- s0 = s1 = { "te" => s3.join.to_i, "moves" => s6[1..-1] }
1311
- else
1312
- @current_pos = s0
1313
- s0 = :failed
1314
- end
498
+ s0 = { "te" => s3.join.to_i, "moves" => s6[1..-1] }
1315
499
  else
1316
500
  @current_pos = s0
1317
501
  s0 = :failed
@@ -1335,164 +519,48 @@ module Jkf::Parser
1335
519
  s0
1336
520
  end
1337
521
 
1338
- def parse_nl
1339
- s0 = @current_pos
1340
- s1 = []
1341
- s2 = parse_newline
1342
- if s2 != :failed
1343
- while (s2 != :failed)
1344
- s1 << s2
1345
- s2 = parse_newline
1346
- end
1347
- else
1348
- s1 = :failed
1349
- end
1350
- if s1 != :failed
1351
- s2 = []
1352
- s3 = parse_skipline
1353
- while s3 != :failed
1354
- s2 << s3
1355
- s3 = parse_skipline
1356
- end
1357
- if s2 != :failed
1358
- s0 = s1 = [s1, s2]
1359
- else
1360
- @current_pos = s0
1361
- s0 = :failed
1362
- end
1363
- else
1364
- @current_pos = s0
1365
- s0 = :failed
1366
- end
1367
-
1368
- s0
1369
- end
1370
-
1371
- def parse_skipline
1372
- s0 = @current_pos
1373
- s1 = match_str("#")
1374
- if s1 != :failed
1375
- s2 = []
1376
- s3 = parse_nonl
1377
- while s3 != :failed
1378
- s2 << s3
1379
- s3 = parse_nonl
1380
- end
1381
- if s2 != :failed
1382
- s3 = parse_newline
1383
- if s3 != :failed
1384
- s0 = s1 = [s1, s2, s3]
1385
- else
1386
- @current_pos = s0
1387
- s0 = :failed
1388
- end
1389
- else
1390
- @current_pos = s0
1391
- s0 = :failed
1392
- end
1393
- else
1394
- @current_pos = s0
1395
- s0 = :failed
1396
- end
1397
- s0
1398
- end
1399
-
1400
- def parse_whitespace
1401
- match_regexp(/^[ \t]/)
1402
- end
1403
-
1404
- def parse_newline
1405
- s0 = @current_pos
1406
- s1 = []
1407
- s2 = parse_whitespace
1408
- while s2 != :failed
1409
- s1 << s2
1410
- s2 = parse_whitespace
1411
- end
1412
- if s1 != :failed
1413
- s2 = match_str("\n")
1414
- if s2 == :failed
1415
- s2 = @current_pos
1416
- s3 = match_str("\r")
1417
- if s3 != :failed
1418
- s4 = match_str("\n")
1419
- s4 = nil if s4 == :failed
1420
- if s4 != :failed
1421
- s2 = s3 = [s3, s4]
1422
- else
1423
- @current_pos = s2
1424
- s2 = :failed
1425
- end
1426
- else
1427
- @current_pos = s2
1428
- s2 = :failed
1429
- end
1430
- end
1431
- if s2 != :failed
1432
- s0 = s1 = [s1, s2]
1433
- else
1434
- @current_pos = s0
1435
- s0 = :failed
1436
- end
1437
- else
1438
- @current_pos = s0
1439
- s0 = :failed
1440
- end
1441
- s0
1442
- end
1443
-
1444
- def parse_nonl
1445
- match_regexp(/^[^\r\n]/)
1446
- end
1447
-
1448
522
  protected
1449
523
 
1450
- def zen2n(s)
1451
- "0123456789".index(s)
1452
- end
1453
-
1454
- def kan2n(s)
1455
- "〇一二三四五六七八九".index(s)
524
+ def transform_root(headers, ini, headers2, moves, forks)
525
+ ret = { "header" => {}, "moves" => moves }
526
+ headers.compact.each { |h| ret["header"][h["k"]] = h["v"] }
527
+ headers2.compact.each { |h| ret["header"][h["k"]] = h["v"] }
528
+ if ini
529
+ ret["initial"] = ini
530
+ elsif ret["header"]["手合割"]
531
+ preset = preset2str(ret["header"]["手合割"])
532
+ ret["initial"] = { "preset" => preset } if preset && preset != "OTHER"
533
+ end
534
+ transform_root_header_data(ret) if ret["initial"] && ret["initial"]["data"]
535
+ transform_root_forks(forks, moves)
536
+ if ret["initial"] && ret["initial"]["data"] && ret["initial"]["data"]["color"] == 1
537
+ reverse_color(ret["moves"])
538
+ end
539
+ ret
1456
540
  end
1457
541
 
1458
- def kan2n2(s)
1459
- case s.length
1460
- when 1
1461
- "〇一二三四五六七八九十".index(s)
1462
- when 2
1463
- "〇一二三四五六七八九十".index(s[1])+10
542
+ def transform_move(line, c)
543
+ ret = {}
544
+ ret["comments"] = c if !c.empty?
545
+ if line["move"].is_a? Hash
546
+ ret["move"] = line["move"]
1464
547
  else
1465
- raise "21以上の数値に対応していません"
548
+ ret["special"] = special2csa(line["move"])
1466
549
  end
550
+ ret["time"] = line["time"] if line["time"]
551
+ ret
1467
552
  end
1468
553
 
1469
- def kind2csa(kind)
1470
- if kind[0] == ""
1471
- {
1472
- "" => "NY",
1473
- "桂" => "NK",
1474
- "銀" => "NG"
1475
- }[kind[1]]
554
+ def transform_teban_fugou_from(teban, fugou, from)
555
+ ret = { "color" => teban2color(teban.join), "piece" => fugou["piece"] }
556
+ if fugou["to"]
557
+ ret["to"] = fugou["to"]
1476
558
  else
1477
- {
1478
- "歩" => "FU",
1479
- "香" => "KY",
1480
- "桂" => "KE",
1481
- "銀" => "GI",
1482
- "金" => "KI",
1483
- "角" => "KA",
1484
- "飛" => "HI",
1485
- "玉" => "OU",
1486
- "王" => "OU",
1487
- "と" => "TO",
1488
- "杏" => "NY",
1489
- "圭" => "NK",
1490
- "全" => "NG",
1491
- "馬" => "UM",
1492
- "竜" => "RY",
1493
- "龍" => "RY"
1494
- }[kind]
559
+ ret["same"] = true
1495
560
  end
561
+ ret["promote"] = true if fugou["promote"]
562
+ ret["from"] = from if from
563
+ ret
1496
564
  end
1497
565
 
1498
566
  def special2csa(str)
@@ -1509,38 +577,17 @@ module Jkf::Parser
1509
577
  }[str] || (raise ParseError)
1510
578
  end
1511
579
 
1512
- def preset2str(preset)
1513
- {
1514
- "平手" => "HIRATE",
1515
- "香落ち" => "KY",
1516
- "右香落ち" => "KY_R",
1517
- "角落ち" => "KA",
1518
- "飛車落ち" => "HI",
1519
- "飛香落ち" => "HIKY",
1520
- "二枚落ち" => "2",
1521
- "三枚落ち" => "3",
1522
- "四枚落ち" => "4",
1523
- "五枚落ち" => "5",
1524
- "左五枚落ち" => "5_L",
1525
- "六枚落ち" => "6",
1526
- "八枚落ち" => "8",
1527
- "十枚落ち" => "10",
1528
- "その他" => "OTHER",
1529
- }[preset.gsub(/\s/, "")]
1530
- end
1531
-
1532
580
  def teban2color(teban)
1533
581
  teban = teban.to_i unless teban.is_a? Fixnum
1534
- (teban+1) % 2
582
+ (teban + 1) % 2
1535
583
  end
1536
584
 
1537
585
  def make_hand(str)
1538
586
  # Kifu for iPhoneは半角スペース区切り
1539
- kinds = str.split(/[  ]/)
1540
587
  ret = { "FU" => 0, "KY" => 0, "KE" => 0, "GI" => 0, "KI" => 0, "KA" => 0, "HI" => 0 }
1541
588
  return ret if str.empty?
1542
589
 
1543
- kinds.each do |kind|
590
+ str.split(/[  ]/).each do |kind|
1544
591
  next if kind.empty?
1545
592
  ret[kind2csa(kind[0])] = kind.length == 1 ? 1 : kan2n2(kind[1..-1])
1546
593
  end
@@ -1550,8 +597,10 @@ module Jkf::Parser
1550
597
 
1551
598
  def reverse_color(moves)
1552
599
  moves.each do |move|
1553
- move['move']['color'] = (move['move']['color'] + 1) % 2 if move['move'] && move['move']['color']
1554
- move['forks'].each { |_fork| reverse_color(_fork) } if move['forks']
600
+ if move["move"] && move["move"]["color"]
601
+ move["move"]["color"] = (move["move"]["color"] + 1) % 2
602
+ end
603
+ move["forks"].each { |_fork| reverse_color(_fork) } if move["forks"]
1555
604
  end
1556
605
  end
1557
606
  end