jkf 0.5.0 → 0.5.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.
@@ -1,422 +1,420 @@
1
- # coding: utf-8
1
+ module Jkf
2
+ module Parser
3
+ # KI2 Parser
4
+ class Ki2 < Base
5
+ include Kifuable
2
6
 
3
- module Jkf::Parser
4
- # KI2 Parser
5
- class Ki2 < Base
6
- include Kifuable
7
+ protected
7
8
 
8
- protected
9
-
10
- # kifu : header* initialboard? header* moves fork*
11
- def parse_root
12
- s0 = @current_pos
13
- s1 = []
14
- s2 = parse_header
15
- while s2 != :failed
16
- s1 << s2
9
+ # kifu : header* initialboard? header* moves fork*
10
+ def parse_root
11
+ s0 = @scanner.pos
12
+ s1 = []
17
13
  s2 = parse_header
18
- end
19
- if s1 == :failed
20
- @current_pos = s0
21
- s0 = :failed
22
- else
23
- s2 = parse_initialboard
24
- s2 = nil if s2 == :failed
25
- s3 = []
26
- s4 = parse_header
27
- while s4 != :failed
28
- s3 << s4
29
- s4 = parse_header
14
+ while s2 != :failed
15
+ s1 << s2
16
+ s2 = parse_header
30
17
  end
31
- s4 = parse_moves
32
- if s4 == :failed
33
- @current_pos = s0
18
+ if s1 == :failed
19
+ @scanner.pos = s0
34
20
  s0 = :failed
35
21
  else
36
- s5 = []
37
- s6 = parse_fork
38
- while s6 != :failed
39
- s5 << s6
22
+ s2 = parse_initialboard
23
+ s2 = nil if s2 == :failed
24
+ s3 = []
25
+ s4 = parse_header
26
+ while s4 != :failed
27
+ s3 << s4
28
+ s4 = parse_header
29
+ end
30
+ s4 = parse_moves
31
+ if s4 == :failed
32
+ @scanner.pos = s0
33
+ s0 = :failed
34
+ else
35
+ s5 = []
40
36
  s6 = parse_fork
37
+ while s6 != :failed
38
+ s5 << s6
39
+ s6 = parse_fork
40
+ end
41
+ @reported_pos = s0
42
+ s0 = transform_root(s1, s2, s3, s4, s5)
41
43
  end
42
- @reported_pos = s0
43
- s0 = transform_root(s1, s2, s3, s4, s5)
44
44
  end
45
+ s0
45
46
  end
46
- s0
47
- end
48
47
 
49
- # header : [^:\r\n]+ ":" nonls nl+ | header_teban
50
- def parse_header
51
- s0 = @current_pos
52
- s2 = match_regexp(/^[^*:\r\n]/)
53
- if s2 == :failed
54
- s1 = :failed
55
- else
56
- s1 = []
57
- while s2 != :failed
58
- s1 << s2
59
- s2 = match_regexp(/^[^:\r\n]/)
60
- end
61
- end
62
- if s1 == :failed
63
- @current_pos = s0
64
- s0 = :failed
65
- elsif match_str(":") != :failed
66
- s3 = parse_nonls
67
- s5 = parse_nl
68
- if s5 == :failed
69
- s4 = :failed
48
+ # header : [^:\r\n]+ ":" nonls nl+ | header_teban
49
+ def parse_header
50
+ s0 = @scanner.pos
51
+ s2 = match_regexp(/[^*:\r\n]/)
52
+ if s2 == :failed
53
+ s1 = :failed
70
54
  else
71
- s4 = []
72
- while s5 != :failed
73
- s4 << s5
74
- s5 = parse_nl
55
+ s1 = []
56
+ while s2 != :failed
57
+ s1 << s2
58
+ s2 = match_regexp(/[^:\r\n]/)
75
59
  end
76
60
  end
77
- if s4 == :failed
78
- @current_pos = s0
61
+ if s1 == :failed
62
+ @scanner.pos = s0
79
63
  s0 = :failed
64
+ elsif match_str(':') != :failed
65
+ s3 = parse_nonls
66
+ s5 = parse_nl
67
+ if s5 == :failed
68
+ s4 = :failed
69
+ else
70
+ s4 = []
71
+ while s5 != :failed
72
+ s4 << s5
73
+ s5 = parse_nl
74
+ end
75
+ end
76
+ if s4 == :failed
77
+ @scanner.pos = s0
78
+ s0 = :failed
79
+ else
80
+ @reported_pos = s0
81
+ s0 = { 'k' => s1.join, 'v' => s3.join }
82
+ end
80
83
  else
81
- @reported_pos = s0
82
- s0 = { "k" => s1.join, "v" => s3.join }
84
+ @scanner.pos = s0
85
+ s0 = :failed
83
86
  end
84
- else
85
- @current_pos = s0
86
- s0 = :failed
87
+ s0 = parse_header_teban if s0 == :failed
88
+ s0
87
89
  end
88
- s0 = parse_header_teban if s0 == :failed
89
- s0
90
- end
91
90
 
92
- # header_teban : [先後上下] "手番" nl
93
- def parse_header_teban
94
- s0 = @current_pos
95
- s1 = parse_turn
96
- if s1 == :failed
97
- @current_pos = s0
98
- :failed
99
- else
100
- s2 = match_str("手番")
101
- if s2 == :failed
102
- @current_pos = s0
91
+ # header_teban : [先後上下] "手番" nl
92
+ def parse_header_teban
93
+ s0 = @scanner.pos
94
+ s1 = parse_turn
95
+ if s1 == :failed
96
+ @scanner.pos = s0
103
97
  :failed
104
98
  else
105
- s3 = parse_nl
106
- if s3 == :failed
107
- @current_pos = s0
99
+ s2 = match_str('手番')
100
+ if s2 == :failed
101
+ @scanner.pos = s0
108
102
  :failed
109
103
  else
110
- @reported_pos = s0
111
- { "k" => "手番", "v" => s1 }
104
+ s3 = parse_nl
105
+ if s3 == :failed
106
+ @scanner.pos = s0
107
+ :failed
108
+ else
109
+ @reported_pos = s0
110
+ { 'k' => '手番', 'v' => s1 }
111
+ end
112
112
  end
113
113
  end
114
114
  end
115
- end
116
115
 
117
- # moves : firstboard : move* result?
118
- def parse_moves
119
- s0 = @current_pos
120
- s1 = parse_firstboard
121
- if s1 == :failed
122
- @current_pos = s0
123
- s0 = :failed
124
- else
125
- s2 = []
126
- s3 = parse_move
127
- while s3 != :failed
128
- s2 << s3
116
+ # moves : firstboard : move* result?
117
+ def parse_moves
118
+ s0 = @scanner.pos
119
+ s1 = parse_firstboard
120
+ if s1 == :failed
121
+ @scanner.pos = s0
122
+ s0 = :failed
123
+ else
124
+ s2 = []
129
125
  s3 = parse_move
126
+ while s3 != :failed
127
+ s2 << s3
128
+ s3 = parse_move
129
+ end
130
+ s3 = parse_result
131
+ s3 = nil if s3 == :failed
132
+ @reported_pos = s0
133
+ s0 = -> (hd, tl, res) do
134
+ tl.unshift(hd)
135
+ tl << { 'special' => res } if res && !tl[tl.length - 1]['special']
136
+ tl
137
+ end.call(s1, s2, s3)
130
138
  end
131
- s3 = parse_result
132
- s3 = nil if s3 == :failed
133
- @reported_pos = s0
134
- s0 = -> (hd, tl, res) do
135
- tl.unshift(hd)
136
- tl << { "special" => res } if res && !tl[tl.length - 1]["special"]
137
- tl
138
- end.call(s1, s2, s3)
139
+ s0
139
140
  end
140
- s0
141
- end
142
141
 
143
- # firstboard : comment* pointer?
144
- def parse_firstboard
145
- s0 = @current_pos
146
- s1 = []
147
- s2 = parse_comment
148
- while s2 != :failed
149
- s1 << s2
142
+ # firstboard : comment* pointer?
143
+ def parse_firstboard
144
+ s0 = @scanner.pos
145
+ s1 = []
150
146
  s2 = parse_comment
147
+ while s2 != :failed
148
+ s1 << s2
149
+ s2 = parse_comment
150
+ end
151
+ parse_pointer
152
+ @reported_pos = s0
153
+ s1.empty? ? {} : { 'comments' => s1 }
151
154
  end
152
- parse_pointer
153
- @reported_pos = s0
154
- s0 = s1.empty? ? {} : { "comments" => s1 }
155
- s0
156
- end
157
155
 
158
- # move : line comment* pointer? (nl | " ")*
159
- def parse_move
160
- s0 = @current_pos
161
- s1 = parse_line
162
- if s1 == :failed
163
- @current_pos = s0
164
- s0 = :failed
165
- else
166
- s2 = []
167
- s3 = parse_comment
168
- while s3 != :failed
169
- s2 << s3
156
+ # move : line comment* pointer? (nl | " ")*
157
+ def parse_move
158
+ s0 = @scanner.pos
159
+ s1 = parse_line
160
+ if s1 == :failed
161
+ @scanner.pos = s0
162
+ s0 = :failed
163
+ else
164
+ s2 = []
170
165
  s3 = parse_comment
171
- end
172
- parse_pointer
173
- s4 = []
174
- s5 = parse_nl
175
- s5 = match_space if s5 == :failed
176
- while s5 != :failed
177
- s4 << s5
166
+ while s3 != :failed
167
+ s2 << s3
168
+ s3 = parse_comment
169
+ end
170
+ parse_pointer
171
+ s4 = []
178
172
  s5 = parse_nl
179
173
  s5 = match_space if s5 == :failed
174
+ while s5 != :failed
175
+ s4 << s5
176
+ s5 = parse_nl
177
+ s5 = match_space if s5 == :failed
178
+ end
179
+ @reported_pos = s0
180
+ s0 = -> (line, c) do
181
+ ret = { 'move' => line }
182
+ ret['comments'] = c unless c.empty?
183
+ ret
184
+ end.call(s1, s2)
180
185
  end
181
- @reported_pos = s0
182
- s0 = -> (line, c) do
183
- ret = { "move" => line }
184
- ret["comments"] = c if !c.empty?
185
- ret
186
- end.call(s1, s2)
187
- end
188
186
 
189
- s0
190
- end
187
+ s0
188
+ end
191
189
 
192
- # line : [▲△] fugou (nl / " ")*
193
- def parse_line
194
- s0 = @current_pos
195
- s1 = match_regexp(/^[▲△]/)
196
- if s1 == :failed
197
- @current_pos = s0
198
- s0 = :failed
199
- else
200
- s1 = if s1 == "▲"
201
- { "color" => 0 }
202
- else
203
- { "color" => 1 }
204
- end
205
- s2 = parse_fugou
206
- if s2 == :failed
207
- @current_pos = s0
190
+ # line : [▲△] fugou (nl / " ")*
191
+ def parse_line
192
+ s0 = @scanner.pos
193
+ s1 = match_regexp(/[▲△]/)
194
+ if s1 == :failed
195
+ @scanner.pos = s0
208
196
  s0 = :failed
209
197
  else
210
- s3 = []
211
- s4 = parse_nl
212
- s4 = match_space if s4 == :failed
213
- while s4 != :failed
214
- s3 << s4
198
+ s1 = if s1 == '▲'
199
+ { 'color' => 0 }
200
+ else
201
+ { 'color' => 1 }
202
+ end
203
+ s2 = parse_fugou
204
+ if s2 == :failed
205
+ @scanner.pos = s0
206
+ s0 = :failed
207
+ else
208
+ s3 = []
215
209
  s4 = parse_nl
216
210
  s4 = match_space if s4 == :failed
211
+ while s4 != :failed
212
+ s3 << s4
213
+ s4 = parse_nl
214
+ s4 = match_space if s4 == :failed
215
+ end
216
+ @reported_pos = s0
217
+ s0 = s2.merge(s1)
217
218
  end
218
- @reported_pos = s0
219
- s0 = s2.merge(s1)
220
219
  end
220
+ s0
221
221
  end
222
- s0
223
- end
224
222
 
225
- # fugou : place piece soutai? dousa? ("成" | "不成")? "打"?
226
- def parse_fugou
227
- s0 = @current_pos
228
- s1 = parse_place
229
- if s1 == :failed
230
- @current_pos = s0
231
- :failed
232
- else
233
- s2 = parse_piece
234
- if s2 == :failed
235
- @current_pos = s0
223
+ # fugou : place piece soutai? dousa? ("成" | "不成")? "打"?
224
+ def parse_fugou
225
+ s0 = @scanner.pos
226
+ s1 = parse_place
227
+ if s1 == :failed
228
+ @scanner.pos = s0
236
229
  :failed
237
230
  else
238
- s3 = parse_soutai
239
- s3 = nil if s3 == :failed
240
- s4 = parse_dousa
241
- s4 = nil if s4 == :failed
242
- s5 = match_str("成")
243
- s5 = match_str("不成") if s5 == :failed
244
- s5 = nil if s5 == :failed
245
- s6 = match_str("打")
246
- s6 = nil if s6 == :failed
247
- @reported_pos = s0
248
- transform_fugou(s1, s2, s3, s4, s5, s6)
231
+ s2 = parse_piece
232
+ if s2 == :failed
233
+ @scanner.pos = s0
234
+ :failed
235
+ else
236
+ s3 = parse_soutai
237
+ s3 = nil if s3 == :failed
238
+ s4 = parse_dousa
239
+ s4 = nil if s4 == :failed
240
+ s5 = match_str('成')
241
+ s5 = match_str('不成') if s5 == :failed
242
+ s5 = nil if s5 == :failed
243
+ s6 = match_str('打')
244
+ s6 = nil if s6 == :failed
245
+ @reported_pos = s0
246
+ transform_fugou(s1, s2, s3, s4, s5, s6)
247
+ end
249
248
  end
250
249
  end
251
- end
252
250
 
253
- # place : num numkan
254
- def parse_place
255
- s0 = @current_pos
256
- s1 = parse_num
257
- if s1 == :failed
258
- @current_pos = s0
259
- s0 = :failed
260
- else
261
- s2 = parse_numkan
262
- if s2 == :failed
263
- @current_pos = s0
251
+ # place : num numkan
252
+ def parse_place
253
+ s0 = @scanner.pos
254
+ s1 = parse_num
255
+ if s1 == :failed
256
+ @scanner.pos = s0
264
257
  s0 = :failed
265
258
  else
266
- @reported_pos = s0
267
- s0 = { "x" => s1, "y" => s2 }
259
+ s2 = parse_numkan
260
+ if s2 == :failed
261
+ @scanner.pos = s0
262
+ s0 = :failed
263
+ else
264
+ @reported_pos = s0
265
+ s0 = { 'x' => s1, 'y' => s2 }
266
+ end
268
267
  end
269
- end
270
- if s0 == :failed
271
- s0 = @current_pos
272
- if match_regexp("同") == :failed
273
- @current_pos = s0
274
- s0 = :failed
275
- else
276
- match_str(" ")
277
- @reported_pos = s0
278
- s0 = { "same" => true }
268
+ if s0 == :failed
269
+ s0 = @scanner.pos
270
+ if match_regexp('同') == :failed
271
+ @scanner.pos = s0
272
+ s0 = :failed
273
+ else
274
+ match_str(' ')
275
+ @reported_pos = s0
276
+ s0 = { 'same' => true }
277
+ end
279
278
  end
279
+ s0
280
280
  end
281
- s0
282
- end
283
281
 
284
- # soutai : [左直右]
285
- def parse_soutai
286
- match_regexp(/^[左直右]/)
287
- end
282
+ # soutai : [左直右]
283
+ def parse_soutai
284
+ match_regexp(/[左直右]/)
285
+ end
288
286
 
289
- # dousa : [上寄引]
290
- def parse_dousa
291
- match_regexp(/^[上寄引]/)
292
- end
287
+ # dousa : [上寄引]
288
+ def parse_dousa
289
+ match_regexp(/[上寄引]/)
290
+ end
293
291
 
294
- # "*" nonls nl
295
- def parse_comment
296
- s0 = @current_pos
297
- if match_str("*") == :failed
298
- @current_pos = s0
299
- s0 = :failed
300
- else
301
- s2 = parse_nonls
302
- if parse_nl == :failed
303
- @current_pos = s0
292
+ # "*" nonls nl
293
+ def parse_comment
294
+ s0 = @scanner.pos
295
+ if match_str('*') == :failed
296
+ @scanner.pos = s0
304
297
  s0 = :failed
305
298
  else
306
- @reported_pos = s0
307
- s0 = s2.join
299
+ s2 = parse_nonls
300
+ if parse_nl == :failed
301
+ @scanner.pos = s0
302
+ s0 = :failed
303
+ else
304
+ @reported_pos = s0
305
+ s0 = s2.join
306
+ end
308
307
  end
308
+ s0
309
309
  end
310
- s0
311
- end
312
310
 
313
- # fork : "変化:" " "* [0-9]+ "手" nl moves
314
- def parse_fork
315
- s0 = @current_pos
316
- if match_str("変化:") == :failed
317
- @current_pos = s0
318
- s0 = :failed
319
- else
320
- match_spaces
321
- s3 = match_digits!
322
- if s3 == :failed
323
- @current_pos = s0
311
+ # fork : "変化:" " "* [0-9]+ "手" nl moves
312
+ def parse_fork
313
+ s0 = @scanner.pos
314
+ if match_str('変化:') == :failed
315
+ @scanner.pos = s0
324
316
  s0 = :failed
325
- elsif match_str("手") != :failed
326
- if parse_nl == :failed
327
- @current_pos = s0
317
+ else
318
+ match_spaces
319
+ s3 = match_digits!
320
+ if s3 == :failed
321
+ @scanner.pos = s0
328
322
  s0 = :failed
329
- else
330
- s6 = parse_moves
331
- if s6 == :failed
332
- @current_pos = s0
323
+ elsif match_str('手') != :failed
324
+ if parse_nl == :failed
325
+ @scanner.pos = s0
333
326
  s0 = :failed
334
327
  else
335
- @reported_pos = s0
336
- s0 = { "te" => s3.join.to_i, "moves" => s6[1..-1] }
328
+ s6 = parse_moves
329
+ if s6 == :failed
330
+ @scanner.pos = s0
331
+ s0 = :failed
332
+ else
333
+ @reported_pos = s0
334
+ s0 = { 'te' => s3.join.to_i, 'moves' => s6[1..-1] }
335
+ end
337
336
  end
337
+ else
338
+ @scanner.pos = s0
339
+ s0 = :failed
338
340
  end
339
- else
340
- @current_pos = s0
341
- s0 = :failed
342
341
  end
342
+ s0
343
343
  end
344
- s0
345
- end
346
344
 
347
- # turn : [先後上下]
348
- def parse_turn
349
- match_regexp(/^[先後上下]/)
350
- end
345
+ # turn : [先後上下]
346
+ def parse_turn
347
+ match_regexp(/[先後上下]/)
348
+ end
351
349
 
352
- # transform to jkf
353
- def transform_root(headers, ini, headers2, moves, forks)
354
- ret = { "header" => {}, "moves" => moves }
355
- headers.compact.each { |h| ret["header"][h["k"]] = h["v"] }
356
- headers2.compact.each { |h| ret["header"][h["k"]] = h["v"] }
357
- if ini
358
- ret["initial"] = ini
359
- elsif ret["header"]["手合割"]
360
- preset = preset2str(ret["header"]["手合割"])
361
- ret["initial"] = { "preset" => preset } if preset != "OTHER"
350
+ # transform to jkf
351
+ def transform_root(headers, ini, headers2, moves, forks)
352
+ ret = { 'header' => {}, 'moves' => moves }
353
+ headers.compact.each { |h| ret['header'][h['k']] = h['v'] }
354
+ headers2.compact.each { |h| ret['header'][h['k']] = h['v'] }
355
+ if ini
356
+ ret['initial'] = ini
357
+ elsif ret['header']['手合割']
358
+ preset = preset2str(ret['header']['手合割'])
359
+ ret['initial'] = { 'preset' => preset } if preset != 'OTHER'
360
+ end
361
+ transform_root_header_data(ret) if ret['initial'] && ret['initial']['data']
362
+ transform_root_forks(forks, moves)
363
+ ret
362
364
  end
363
- transform_root_header_data(ret) if ret["initial"] && ret["initial"]["data"]
364
- transform_root_forks(forks, moves)
365
- ret
366
- end
367
365
 
368
- # transfrom fugou to jkf
369
- def transform_fugou(pl, pi, sou, dou, pro, da)
370
- ret = { "piece" => pi }
371
- if pl["same"]
372
- ret["same"] = true
373
- else
374
- ret["to"] = pl
366
+ # transfrom fugou to jkf
367
+ def transform_fugou(pl, pi, sou, dou, pro, da)
368
+ ret = { 'piece' => pi }
369
+ if pl['same']
370
+ ret['same'] = true
371
+ else
372
+ ret['to'] = pl
373
+ end
374
+ ret['promote'] = (pro == '成') if pro
375
+ if da
376
+ ret['relative'] = 'H'
377
+ else
378
+ rel = soutai2relative(sou) + dousa2relative(dou)
379
+ ret['relative'] = rel unless rel.empty?
380
+ end
381
+ ret
375
382
  end
376
- ret["promote"] = (pro == "成") if pro
377
- if da
378
- ret["relative"] = "H"
379
- else
380
- rel = soutai2relative(sou) + dousa2relative(dou)
381
- ret["relative"] = rel unless rel.empty?
383
+
384
+ # relative string to jkf
385
+ def soutai2relative(str)
386
+ {
387
+ '左' => 'L',
388
+ '直' => 'C',
389
+ '右' => 'R'
390
+ }[str] || ''
382
391
  end
383
- ret
384
- end
385
392
 
386
- # relative string to jkf
387
- def soutai2relative(str)
388
- {
389
- "左" => "L",
390
- "直" => "C",
391
- "右" => "R"
392
- }[str] || ""
393
- end
393
+ # movement string to jkf
394
+ def dousa2relative(str)
395
+ {
396
+ '上' => 'U',
397
+ '寄' => 'M',
398
+ '引' => 'D'
399
+ }[str] || ''
400
+ end
394
401
 
395
- # movement string to jkf
396
- def dousa2relative(str)
397
- {
398
- "上" => "U",
399
- "寄" => "M",
400
- "引" => "D"
401
- }[str] || ""
402
- end
402
+ # generate motigoma
403
+ def make_hand(str)
404
+ ret = { 'FU' => 0, 'KY' => 0, 'KE' => 0, 'GI' => 0, 'KI' => 0, 'KA' => 0, 'HI' => 0 }
405
+ return ret if str.empty?
403
406
 
404
- # generate motigoma
405
- def make_hand(str)
406
- ret = { "FU" => 0, "KY" => 0, "KE" => 0, "GI" => 0, "KI" => 0, "KA" => 0, "HI" => 0 }
407
- return ret if str.empty?
407
+ str.gsub(/ $/, '').split(' ').each do |kind|
408
+ next if kind.empty?
409
+ ret[kind2csa(kind[0])] = kind.length == 1 ? 1 : kan2n2(kind[1..-1])
410
+ end
408
411
 
409
- str.gsub(/ $/, "").split(" ").each do |kind|
410
- next if kind.empty?
411
- ret[kind2csa(kind[0])] = kind.length == 1 ? 1 : kan2n2(kind[1..-1])
412
+ ret
412
413
  end
413
414
 
414
- ret
415
- end
416
-
417
- # check eos
418
- def eos?
419
- @input[@current_pos].nil?
415
+ def eos?
416
+ @scanner.eos?
417
+ end
420
418
  end
421
419
  end
422
420
  end