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