jkf 0.4.3 → 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,636 +1,619 @@
1
- # coding: utf-8
1
+ module Jkf
2
+ module Parser
3
+ # KIF Parser
4
+ class Kif < Base
5
+ include Kifuable
2
6
 
3
- module Jkf::Parser
4
- # KIF Parser
5
- class Kif < Base
6
- include Kifuable
7
+ protected
7
8
 
8
- protected
9
+ # kifu : skipline* header* initialboard? header* split? moves fork* nl?
10
+ def parse_root
11
+ @scanner << "\n" unless @scanner.string.end_with?("\n")
9
12
 
10
- # kifu : skipline* header* initialboard? header* split? moves fork* nl?
11
- def parse_root
12
- @input += "\n" unless @input.end_with?("\n")
13
-
14
- s0 = @current_pos
15
- s1 = []
16
- s2 = parse_skipline
17
- while s2 != :failed
18
- s1 << s2
13
+ s0 = @scanner.pos
14
+ s1 = []
19
15
  s2 = parse_skipline
20
- end
16
+ while s2 != :failed
17
+ s1 << s2
18
+ s2 = parse_skipline
19
+ end
21
20
 
22
- s2 = []
23
- s3 = parse_header
24
- while s3 != :failed
25
- s2 << s3
21
+ s2 = []
26
22
  s3 = parse_header
27
- end
28
- s3 = parse_initialboard
29
- s3 = nil if s3 == :failed
30
- s4 = []
31
- s5 = parse_header
32
- while s5 != :failed
33
- s4 << s5
23
+ while s3 != :failed
24
+ s2 << s3
25
+ s3 = parse_header
26
+ end
27
+ s3 = parse_initialboard
28
+ s3 = nil if s3 == :failed
29
+ s4 = []
34
30
  s5 = parse_header
35
- end
36
- parse_split
37
- s6 = parse_moves
38
- if s6 != :failed
39
- s7 = []
40
- s8 = parse_fork
41
- while s8 != :failed
42
- s7 << s8
31
+ while s5 != :failed
32
+ s4 << s5
33
+ s5 = parse_header
34
+ end
35
+ parse_split
36
+ s6 = parse_moves
37
+ if s6 == :failed
38
+ @scanner.pos = s0
39
+ s0 = :failed
40
+ else
41
+ s7 = []
43
42
  s8 = parse_fork
43
+ while s8 != :failed
44
+ s7 << s8
45
+ s8 = parse_fork
46
+ end
47
+ parse_nl
48
+ @reported_pos = s0
49
+ s0 = transform_root(s2, s3, s4, s6, s7)
44
50
  end
45
- parse_nl
46
- @reported_pos = s0
47
- s0 = transform_root(s2, s3, s4, s6, s7)
48
- else
49
- @current_pos = s0
50
- s0 = :failed
51
- end
52
51
 
53
- s0
54
- end
52
+ s0
53
+ end
55
54
 
56
- # header : [^:\r\n]+ ":" nonls nl
57
- # | turn "手番" nl
58
- # | "盤面回転" nl
59
- def parse_header
60
- s0 = @current_pos
61
- s2 = match_regexp(/^[^:\r\n]/)
62
- if s2 != :failed
63
- s1 = []
64
- while s2 != :failed
65
- s1 << s2
66
- s2 = match_regexp(/^[^:\r\n]/)
55
+ # header : [^:\r\n]+ ":" nonls nl
56
+ # | turn "手番" nl
57
+ # | "盤面回転" nl
58
+ def parse_header
59
+ s0 = @scanner.pos
60
+ s2 = match_regexp(/[^:\r\n]/)
61
+ if s2 == :failed
62
+ s1 = :failed
63
+ else
64
+ s1 = []
65
+ while s2 != :failed
66
+ s1 << s2
67
+ s2 = match_regexp(/[^:\r\n]/)
68
+ end
67
69
  end
68
- else
69
- s1 = :failed
70
- end
71
- if s1 != :failed
72
- if match_str(":") != :failed
70
+ if s1 == :failed
71
+ @scanner.pos = s0
72
+ s0 = :failed
73
+ elsif match_str(':') != :failed
73
74
  s3 = parse_nonls
74
- if parse_nl != :failed
75
+ if parse_nl == :failed
76
+ @scanner.pos = s0
77
+ s0 = :failed
78
+ else
75
79
  @reported_pos = s0
76
- s1 = { "k" => s1.join, "v" => s3.join }
80
+ s1 = { 'k' => s1.join, 'v' => s3.join }
77
81
  s0 = s1
78
- else
79
- @current_pos = s0
80
- s0 = :failed
81
82
  end
82
83
  else
83
- @current_pos = s0
84
+ @scanner.pos = s0
84
85
  s0 = :failed
85
86
  end
86
- else
87
- @current_pos = s0
88
- s0 = :failed
89
- end
90
- if s0 == :failed
91
- s0 = @current_pos
92
- s1 = parse_turn
93
- if s1 != :failed
94
- if match_str("手番") != :failed
95
- if parse_nl != :failed
96
- @reported_pos = s0
97
- s0 = { "k" => "手番", "v" => s1 }
98
- else
99
- @current_pos = s0
87
+ if s0 == :failed
88
+ s0 = @scanner.pos
89
+ s1 = parse_turn
90
+ if s1 == :failed
91
+ @scanner.pos = s0
92
+ s0 = :failed
93
+ elsif match_str('手番') != :failed
94
+ if parse_nl == :failed
95
+ @scanner.pos = s0
100
96
  s0 = :failed
97
+ else
98
+ @reported_pos = s0
99
+ s0 = { 'k' => '手番', 'v' => s1 }
101
100
  end
102
101
  else
103
- @current_pos = s0
102
+ @scanner.pos = s0
104
103
  s0 = :failed
105
104
  end
106
- else
107
- @current_pos = s0
108
- s0 = :failed
109
- end
110
- if s0 == :failed
111
- s0 = @current_pos
112
- if match_str("盤面回転") != :failed
113
- if parse_nl != :failed
105
+ if s0 == :failed
106
+ s0 = @scanner.pos
107
+ if match_str('盤面回転') == :failed
108
+ @scanner.pos = s0
109
+ s0 = :failed
110
+ elsif parse_nl != :failed
114
111
  @reported_pos = s0
115
112
  s0 = nil
116
113
  else
117
- @current_pos = s0
114
+ @scanner.pos = s0
118
115
  s0 = :failed
119
116
  end
120
- else
121
- @current_pos = s0
122
- s0 = :failed
123
117
  end
124
118
  end
125
- end
126
119
 
127
- s0
128
- end
120
+ s0
121
+ end
129
122
 
130
- # turn : [先後上下]
131
- def parse_turn
132
- match_regexp(/^[先後上下]/)
133
- end
123
+ # turn : [先後上下]
124
+ def parse_turn
125
+ match_regexp(/[先後上下]/)
126
+ end
134
127
 
135
- # split : "手数----指手--" "-------消費時間--"? nl
136
- def parse_split
137
- s0 = @current_pos
138
- s1 = match_str("手数----指手--")
139
- if s1 != :failed
140
- s2 = match_str("-------消費時間--")
141
- s2 = nil if s2 == :failed
142
- s3 = parse_nl
143
- if s3 != :failed
144
- s0 = [s1, s2, s3]
145
- else
146
- @current_pos = s0
128
+ # split : "手数----指手--" "-------消費時間--"? nl
129
+ def parse_split
130
+ s0 = @scanner.pos
131
+ s1 = match_str('手数----指手--')
132
+ if s1 == :failed
133
+ @scanner.pos = s0
147
134
  s0 = :failed
135
+ else
136
+ s2 = match_str('-------消費時間--')
137
+ s2 = nil if s2 == :failed
138
+ s3 = parse_nl
139
+ if s3 == :failed
140
+ @scanner.pos = s0
141
+ s0 = :failed
142
+ else
143
+ s0 = [s1, s2, s3]
144
+ end
148
145
  end
149
- else
150
- @current_pos = s0
151
- s0 = :failed
146
+ s0
152
147
  end
153
- s0
154
- end
155
148
 
156
- # moves : firstboard split? move* result?
157
- def parse_moves
158
- s0 = @current_pos
159
- s1 = parse_firstboard
160
- if s1 != :failed
161
- parse_split
162
- s2 = []
163
- s3 = parse_move
164
- while s3 != :failed
165
- s2 << s3
149
+ # moves : firstboard split? move* result?
150
+ def parse_moves
151
+ s0 = @scanner.pos
152
+ s1 = parse_firstboard
153
+ if s1 == :failed
154
+ @scanner.pos = s0
155
+ s0 = :failed
156
+ else
157
+ parse_split
158
+ s2 = []
166
159
  s3 = parse_move
160
+ while s3 != :failed
161
+ s2 << s3
162
+ s3 = parse_move
163
+ end
164
+ parse_result
165
+ @reported_pos = s0
166
+ s0 = s2.unshift(s1)
167
167
  end
168
- parse_result
169
- @reported_pos = s0
170
- s0 = s2.unshift(s1)
171
- else
172
- @current_pos = s0
173
- s0 = :failed
168
+ s0
174
169
  end
175
- s0
176
- end
177
170
 
178
- # firstboard : comment* pointer?
179
- def parse_firstboard
180
- s0 = @current_pos
181
- s1 = []
182
- s2 = parse_comment
183
- while s2 != :failed
184
- s1 << s2
171
+ # firstboard : comment* pointer?
172
+ def parse_firstboard
173
+ s0 = @scanner.pos
174
+ s1 = []
185
175
  s2 = parse_comment
186
- end
187
- parse_pointer
188
- @reported_pos = s0
189
- s0 = s1.empty? ? {} : { "comments" => s1 }
190
- s0
191
- end
192
-
193
- # move : line comment* pointer?
194
- def parse_move
195
- s0 = @current_pos
196
- s1 = parse_line
197
- if s1 != :failed
198
- s2 = []
199
- s3 = parse_comment
200
- while s3 != :failed
201
- s2 << s3
202
- s3 = parse_comment
176
+ while s2 != :failed
177
+ s1 << s2
178
+ s2 = parse_comment
203
179
  end
204
180
  parse_pointer
205
181
  @reported_pos = s0
206
- s0 = transform_move(s1, s2)
207
- else
208
- @current_pos = s0
209
- s0 = :failed
182
+ s1.empty? ? {} : { 'comments' => s1 }
210
183
  end
211
- s0
212
- end
213
184
 
214
- # line : " "* te " "* (fugou from | [^\r\n ]*) " "* time? "+"? nl
215
- def parse_line
216
- s0 = @current_pos
217
- match_spaces
218
- s2 = parse_te
219
- if s2 != :failed
220
- match_spaces
221
- s4 = @current_pos
222
- s5 = parse_fugou
223
- if s5 != :failed
224
- s6 = parse_from
225
- if s6 != :failed
226
- @reported_pos = s4
227
- s4 = transform_teban_fugou_from(s2, s5, s6)
228
- else
229
- @current_pos = s4
230
- s4 = :failed
231
- end
185
+ # move : line comment* pointer?
186
+ def parse_move
187
+ s0 = @scanner.pos
188
+ s1 = parse_line
189
+ if s1 == :failed
190
+ @scanner.pos = s0
191
+ s0 = :failed
232
192
  else
233
- @current_pos = s4
234
- s4 = :failed
235
- end
236
- if s4 == :failed
237
- s4 = @current_pos
238
- s5 = []
239
- s6 = match_regexp(/^[^\r\n ]/)
240
- while s6 != :failed
241
- s5 << s6
242
- s6 = match_regexp(/^[^\r\n ]/)
193
+ s2 = []
194
+ s3 = parse_comment
195
+ while s3 != :failed
196
+ s2 << s3
197
+ s3 = parse_comment
243
198
  end
244
- @reported_pos = s4
245
- s4 = s5.join
199
+ parse_pointer
200
+ @reported_pos = s0
201
+ s0 = transform_move(s1, s2)
246
202
  end
247
- if s4 != :failed
203
+ s0
204
+ end
205
+
206
+ # line : " "* te " "* (fugou from | [^\r\n ]*) " "* time? "+"? nl
207
+ def parse_line
208
+ s0 = @scanner.pos
209
+ match_spaces
210
+ s2 = parse_te
211
+ if s2 == :failed
212
+ @scanner.pos = s0
213
+ s0 = :failed
214
+ else
248
215
  match_spaces
249
- s6 = parse_time
250
- s6 = nil if s6 == :failed
251
- match_str("+")
252
- if parse_nl != :failed
253
- @reported_pos = s0
254
- s0 = { "move" => s4, "time" => s6 }
216
+ s4 = @scanner.pos
217
+ s5 = parse_fugou
218
+ if s5 == :failed
219
+ @scanner.pos = s4
220
+ s4 = :failed
255
221
  else
256
- @current_pos = s0
222
+ s6 = parse_from
223
+ if s6 == :failed
224
+ @scanner.pos = s4
225
+ s4 = :failed
226
+ else
227
+ @reported_pos = s4
228
+ s4 = transform_teban_fugou_from(s2, s5, s6)
229
+ end
230
+ end
231
+ if s4 == :failed
232
+ s4 = @scanner.pos
233
+ s5 = []
234
+ s6 = match_regexp(/[^\r\n ]/)
235
+ while s6 != :failed
236
+ s5 << s6
237
+ s6 = match_regexp(/[^\r\n ]/)
238
+ end
239
+ @reported_pos = s4
240
+ s4 = s5.join
241
+ end
242
+ if s4 == :failed
243
+ @scanner.pos = s0
257
244
  s0 = :failed
245
+ else
246
+ match_spaces
247
+ s6 = parse_time
248
+ s6 = nil if s6 == :failed
249
+ match_str('+')
250
+ if parse_nl == :failed
251
+ @scanner.pos = s0
252
+ s0 = :failed
253
+ else
254
+ @reported_pos = s0
255
+ s0 = { 'move' => s4, 'time' => s6 }
256
+ end
258
257
  end
259
- else
260
- @current_pos = s0
261
- s0 = :failed
262
258
  end
263
- else
264
- @current_pos = s0
265
- s0 = :failed
259
+ s0
266
260
  end
267
- s0
268
- end
269
261
 
270
- # te : [0-9]+
271
- def parse_te
272
- match_digits!
273
- end
262
+ # te : [0-9]+
263
+ def parse_te
264
+ match_digits!
265
+ end
274
266
 
275
- # fugou : place piece "成"?
276
- def parse_fugou
277
- s0 = @current_pos
278
- s1 = parse_place
279
- if s1 != :failed
280
- s2 = parse_piece
281
- if s2 != :failed
282
- s3 = match_str("成")
283
- s3 = nil if s3 == :failed
284
- @reported_pos = s0
285
- s0 = { "to" => s1, "piece" => s2, "promote" => !!s3 }
286
- else
287
- @current_pos = s0
267
+ # fugou : place piece "成"?
268
+ def parse_fugou
269
+ s0 = @scanner.pos
270
+ s1 = parse_place
271
+ if s1 == :failed
272
+ @scanner.pos = s0
288
273
  s0 = :failed
274
+ else
275
+ s2 = parse_piece
276
+ if s2 == :failed
277
+ @scanner.pos = s0
278
+ s0 = :failed
279
+ else
280
+ s3 = match_str('成')
281
+ s3 = nil if s3 == :failed
282
+ @reported_pos = s0
283
+ s0 = { 'to' => s1, 'piece' => s2, 'promote' => !!s3 }
284
+ end
289
285
  end
290
- else
291
- @current_pos = s0
292
- s0 = :failed
286
+ s0
293
287
  end
294
- s0
295
- end
296
288
 
297
- # place : num numkan | "同 "
298
- def parse_place
299
- s0 = @current_pos
300
- s1 = parse_num
301
- if s1 != :failed
302
- s2 = parse_numkan
303
- if s2 != :failed
304
- @reported_pos = s0
305
- s0 = { "x" => s1, "y" => s2 }
306
- else
307
- @current_pos = s0
289
+ # place : num numkan | "同 "
290
+ def parse_place
291
+ s0 = @scanner.pos
292
+ s1 = parse_num
293
+ if s1 == :failed
294
+ @scanner.pos = s0
308
295
  s0 = :failed
296
+ else
297
+ s2 = parse_numkan
298
+ if s2 == :failed
299
+ @scanner.pos = s0
300
+ s0 = :failed
301
+ else
302
+ @reported_pos = s0
303
+ s0 = { 'x' => s1, 'y' => s2 }
304
+ end
309
305
  end
310
- else
311
- @current_pos = s0
312
- s0 = :failed
306
+ if s0 == :failed
307
+ s0 = @scanner.pos
308
+ s1 = match_str('同 ')
309
+ if s1 != :failed
310
+ @reported_pos = s0
311
+ s1 = nil
312
+ end
313
+ s0 = s1
314
+ end
315
+ s0
313
316
  end
314
- if s0 == :failed
315
- s0 = @current_pos
316
- s1 = match_str("同 ")
317
+
318
+ # from : "打" | "(" [1-9] [1-9] ")"
319
+ def parse_from
320
+ s0 = @scanner.pos
321
+ s1 = match_str('打')
317
322
  if s1 != :failed
318
323
  @reported_pos = s0
319
324
  s1 = nil
320
325
  end
321
326
  s0 = s1
322
- end
323
- s0
324
- end
325
-
326
- # from : "打" | "(" [1-9] [1-9] ")"
327
- def parse_from
328
- s0 = @current_pos
329
- s1 = match_str("打")
330
- if s1 != :failed
331
- @reported_pos = s0
332
- s1 = nil
333
- end
334
- s0 = s1
335
- if s0 == :failed
336
- s0 = @current_pos
337
- if match_str("(") != :failed
338
- s2 = match_regexp(/^[1-9]/)
339
- if s2 != :failed
340
- s3 = match_regexp(/^[1-9]/)
341
- if s3 != :failed
342
- if match_str(")") != :failed
327
+ if s0 == :failed
328
+ s0 = @scanner.pos
329
+ if match_str('(') == :failed
330
+ @scanner.pos = s0
331
+ s0 = :failed
332
+ else
333
+ s2 = match_regexp(/[1-9]/)
334
+ if s2 == :failed
335
+ @scanner.pos = s0
336
+ s0 = :failed
337
+ else
338
+ s3 = match_regexp(/[1-9]/)
339
+ if s3 == :failed
340
+ @scanner.pos = s0
341
+ s0 = :failed
342
+ elsif match_str(')') != :failed
343
343
  @reported_pos = s0
344
- s0 = { "x" => s2.to_i, "y" => s3.to_i }
344
+ s0 = { 'x' => s2.to_i, 'y' => s3.to_i }
345
345
  else
346
- @current_pos = s0
346
+ @scanner.pos = s0
347
347
  s0 = :failed
348
348
  end
349
- else
350
- @current_pos = s0
351
- s0 = :failed
352
349
  end
353
- else
354
- @current_pos = s0
355
- s0 = :failed
356
350
  end
357
- else
358
- @current_pos = s0
359
- s0 = :failed
360
351
  end
352
+ s0
361
353
  end
362
- s0
363
- end
364
354
 
365
- # time : "(" " "* ms " "* "/" " "* (hms | ms) " "* ")"
366
- def parse_time
367
- s0 = @current_pos
368
- if match_str("(") != :failed
369
- match_spaces
370
- s3 = parse_ms
371
- if s3 != :failed
355
+ # time : "(" " "* ms " "* "/" " "* (hms | ms) " "* ")"
356
+ def parse_time
357
+ s0 = @scanner.pos
358
+ if match_str('(') == :failed
359
+ @scanner.pos = s0
360
+ s0 = :failed
361
+ else
372
362
  match_spaces
373
- if match_str("/") != :failed
363
+ s3 = parse_ms
364
+ if s3 == :failed
365
+ @scanner.pos = s0
366
+ s0 = :failed
367
+ else
374
368
  match_spaces
375
- s5 = parse_hms
376
- s5 = parse_ms(with_hour: true) if s5 == :failed
377
- if s5 != :failed
369
+ if match_str('/') == :failed
370
+ @scanner.pos = s0
371
+ s0 = :failed
372
+ else
378
373
  match_spaces
379
- if match_str(")") != :failed
380
- @reported_pos = s0
381
- s0 = { "now" => s3, "total" => s5 }
382
- else
383
- @current_pos = s0
374
+ s5 = parse_hms
375
+ s5 = parse_ms(with_hour: true) if s5 == :failed
376
+ if s5 == :failed
377
+ @scanner.pos = s0
384
378
  s0 = :failed
379
+ else
380
+ match_spaces
381
+ if match_str(')') == :failed
382
+ @scanner.pos = s0
383
+ s0 = :failed
384
+ else
385
+ @reported_pos = s0
386
+ s0 = { 'now' => s3, 'total' => s5 }
387
+ end
385
388
  end
386
- else
387
- @current_pos = s0
388
- s0 = :failed
389
389
  end
390
- else
391
- @current_pos = s0
392
- s0 = :failed
393
390
  end
394
- else
395
- @current_pos = s0
396
- s0 = :failed
397
391
  end
398
- else
399
- @current_pos = s0
400
- s0 = :failed
392
+ s0
401
393
  end
402
- s0
403
- end
404
394
 
405
- # hms : [0-9]+ ":" [0-9]+ ":" [0-9]+
406
- def parse_hms
407
- s0 = @current_pos
408
- s1 = match_digits!
395
+ # hms : [0-9]+ ":" [0-9]+ ":" [0-9]+
396
+ def parse_hms
397
+ s0 = @scanner.pos
398
+ s1 = match_digits!
409
399
 
410
- if s1 != :failed
411
- if match_str(":") != :failed
400
+ if s1 == :failed
401
+ @scanner.pos = s0
402
+ s0 = :failed
403
+ elsif match_str(':') != :failed
412
404
  s3 = match_digits!
413
- if s3 != :failed
414
- if match_str(":") != :failed
415
- s5 = match_digits!
416
- if s5 != :failed
417
- @reported_pos = s0
418
- s0 = { "h" => s1.join.to_i, "m" => s3.join.to_i, "s" => s5.join.to_i }
419
- else
420
- @current_pos = s0
421
- s0 = :failed
422
- end
423
- else
424
- @current_pos = s0
405
+ if s3 == :failed
406
+ @scanner.pos = s0
407
+ s0 = :failed
408
+ elsif match_str(':') != :failed
409
+ s5 = match_digits!
410
+ if s5 == :failed
411
+ @scanner.pos = s0
425
412
  s0 = :failed
413
+ else
414
+ @reported_pos = s0
415
+ s0 = { 'h' => s1.join.to_i, 'm' => s3.join.to_i, 's' => s5.join.to_i }
426
416
  end
427
417
  else
428
- @current_pos = s0
418
+ @scanner.pos = s0
429
419
  s0 = :failed
430
420
  end
431
421
  else
432
- @current_pos = s0
422
+ @scanner.pos = s0
433
423
  s0 = :failed
434
424
  end
435
- else
436
- @current_pos = s0
437
- s0 = :failed
425
+ s0
438
426
  end
439
- s0
440
- end
441
427
 
442
- # ms : [0-9]+ ":" [0-9]+
443
- def parse_ms(with_hour: false)
444
- s0 = @current_pos
445
- s1 = match_digits!
446
- if s1 != :failed
447
- if match_str(":") != :failed
428
+ # ms : [0-9]+ ":" [0-9]+
429
+ def parse_ms(with_hour: false)
430
+ s0 = @scanner.pos
431
+ s1 = match_digits!
432
+ if s1 == :failed
433
+ @scanner.pos = s0
434
+ s0 = :failed
435
+ elsif match_str(':') != :failed
448
436
  s3 = match_digits!
449
- if s3 != :failed
437
+ if s3 == :failed
438
+ @scanner.pos = s0
439
+ s0 = :failed
440
+ else
450
441
  @reported_pos = s0
451
442
  m = s1.join.to_i
452
443
  s = s3.join.to_i
453
444
  if with_hour
454
445
  h = m / 60
455
446
  m = m % 60
456
- s0 = { "h" => h, "m" => m, "s" => s }
447
+ s0 = { 'h' => h, 'm' => m, 's' => s }
457
448
  else
458
- s0 = { "m" => m, "s" => s }
449
+ s0 = { 'm' => m, 's' => s }
459
450
  end
460
- else
461
- @current_pos = s0
462
- s0 = :failed
463
451
  end
464
452
  else
465
- @current_pos = s0
453
+ @scanner.pos = s0
466
454
  s0 = :failed
467
455
  end
468
- else
469
- @current_pos = s0
470
- s0 = :failed
456
+ s0
471
457
  end
472
- s0
473
- end
474
458
 
475
- # comment : "*" nonls nl | "&" nonls nl
476
- def parse_comment
477
- s0 = @current_pos
478
- if match_str("*") != :failed
479
- s2 = parse_nonls
480
- if parse_nl != :failed
481
- @reported_pos = s0
482
- s0 = s2.join
483
- else
484
- @current_pos = s0
459
+ # comment : "*" nonls nl | "&" nonls nl
460
+ def parse_comment
461
+ s0 = @scanner.pos
462
+ if match_str('*') == :failed
463
+ @scanner.pos = s0
485
464
  s0 = :failed
486
- end
487
- else
488
- @current_pos = s0
489
- s0 = :failed
490
- end
491
- if s0 == :failed
492
- s0 = @current_pos
493
- s1 = match_str("&")
494
- if s1 != :failed
465
+ else
495
466
  s2 = parse_nonls
496
- if parse_nl != :failed
497
- @reported_pos = s0
498
- s0 = "&" + s2.join
467
+ if parse_nl == :failed
468
+ @scanner.pos = s0
469
+ s0 = :failed
499
470
  else
500
- @current_pos = s0
471
+ @reported_pos = s0
472
+ s0 = s2.join
473
+ end
474
+ end
475
+ if s0 == :failed
476
+ s0 = @scanner.pos
477
+ s1 = match_str('&')
478
+ if s1 == :failed
479
+ @scanner.pos = s0
501
480
  s0 = :failed
481
+ else
482
+ s2 = parse_nonls
483
+ if parse_nl == :failed
484
+ @scanner.pos = s0
485
+ s0 = :failed
486
+ else
487
+ @reported_pos = s0
488
+ s0 = '&' + s2.join
489
+ end
502
490
  end
503
- else
504
- @current_pos = s0
505
- s0 = :failed
506
491
  end
492
+ s0
507
493
  end
508
- s0
509
- end
510
494
 
511
- # fork : "変化:" " "* [0-9]+ "手" nl moves
512
- def parse_fork
513
- s0 = @current_pos
514
- if match_str("変化:") != :failed
515
- match_spaces
516
- s3 = parse_te
517
- if s3 != :failed
518
- if match_str("手") != :failed
519
- if parse_nl != :failed
495
+ # fork : "変化:" " "* [0-9]+ "手" nl moves
496
+ def parse_fork
497
+ s0 = @scanner.pos
498
+ if match_str('変化:') == :failed
499
+ @scanner.pos = s0
500
+ s0 = :failed
501
+ else
502
+ match_spaces
503
+ s3 = parse_te
504
+ if s3 == :failed
505
+ @scanner.pos = s0
506
+ s0 = :failed
507
+ elsif match_str('手') != :failed
508
+ if parse_nl == :failed
509
+ @scanner.pos = s0
510
+ s0 = :failed
511
+ else
520
512
  s6 = parse_moves
521
- if s6 != :failed
522
- @reported_pos = s0
523
- s0 = { "te" => s3.join.to_i, "moves" => s6[1..-1] }
524
- else
525
- @current_pos = s0
513
+ if s6 == :failed
514
+ @scanner.pos = s0
526
515
  s0 = :failed
516
+ else
517
+ @reported_pos = s0
518
+ s0 = { 'te' => s3.join.to_i, 'moves' => s6[1..-1] }
527
519
  end
528
- else
529
- @current_pos = s0
530
- s0 = :failed
531
520
  end
532
521
  else
533
- @current_pos = s0
522
+ @scanner.pos = s0
534
523
  s0 = :failed
535
524
  end
536
- else
537
- @current_pos = s0
538
- s0 = :failed
539
525
  end
540
- else
541
- @current_pos = s0
542
- s0 = :failed
526
+ s0
543
527
  end
544
- s0
545
- end
546
528
 
547
- # transfrom to jkf
548
- def transform_root(headers, ini, headers2, moves, forks)
549
- ret = { "header" => {}, "moves" => moves }
550
- headers.compact.each { |h| ret["header"][h["k"]] = h["v"] }
551
- headers2.compact.each { |h| ret["header"][h["k"]] = h["v"] }
552
- if ini
553
- ret["initial"] = ini
554
- elsif ret["header"]["手合割"]
555
- preset = preset2str(ret["header"]["手合割"])
556
- ret["initial"] = { "preset" => preset } if preset && preset != "OTHER"
529
+ # transfrom to jkf
530
+ def transform_root(headers, ini, headers2, moves, forks)
531
+ ret = { 'header' => {}, 'moves' => moves }
532
+ headers.compact.each { |h| ret['header'][h['k']] = h['v'] }
533
+ headers2.compact.each { |h| ret['header'][h['k']] = h['v'] }
534
+ if ini
535
+ ret['initial'] = ini
536
+ elsif ret['header']['手合割']
537
+ preset = preset2str(ret['header']['手合割'])
538
+ ret['initial'] = { 'preset' => preset } if preset && preset != 'OTHER'
539
+ end
540
+ transform_root_header_data(ret) if ret['initial'] && ret['initial']['data']
541
+ transform_root_forks(forks, moves)
542
+ if ret['initial'] && ret['initial']['data'] && ret['initial']['data']['color'] == 1
543
+ reverse_color(ret['moves'])
544
+ end
545
+ ret
557
546
  end
558
- transform_root_header_data(ret) if ret["initial"] && ret["initial"]["data"]
559
- transform_root_forks(forks, moves)
560
- if ret["initial"] && ret["initial"]["data"] && ret["initial"]["data"]["color"] == 1
561
- reverse_color(ret["moves"])
547
+
548
+ # transform move to jkf
549
+ def transform_move(line, c)
550
+ ret = {}
551
+ ret['comments'] = c unless c.empty?
552
+ if line['move'].is_a? Hash
553
+ ret['move'] = line['move']
554
+ else
555
+ ret['special'] = special2csa(line['move'])
556
+ end
557
+ ret['time'] = line['time'] if line['time']
558
+ ret
562
559
  end
563
- ret
564
- end
565
560
 
566
- # transform move to jkf
567
- def transform_move(line, c)
568
- ret = {}
569
- ret["comments"] = c if !c.empty?
570
- if line["move"].is_a? Hash
571
- ret["move"] = line["move"]
572
- else
573
- ret["special"] = special2csa(line["move"])
561
+ # transform teban-fugou-from to jkf
562
+ def transform_teban_fugou_from(teban, fugou, from)
563
+ ret = { 'color' => teban2color(teban.join), 'piece' => fugou['piece'] }
564
+ if fugou['to']
565
+ ret['to'] = fugou['to']
566
+ else
567
+ ret['same'] = true
568
+ end
569
+ ret['promote'] = true if fugou['promote']
570
+ ret['from'] = from if from
571
+ ret
574
572
  end
575
- ret["time"] = line["time"] if line["time"]
576
- ret
577
- end
578
573
 
579
- # transform teban-fugou-from to jkf
580
- def transform_teban_fugou_from(teban, fugou, from)
581
- ret = { "color" => teban2color(teban.join), "piece" => fugou["piece"] }
582
- if fugou["to"]
583
- ret["to"] = fugou["to"]
584
- else
585
- ret["same"] = true
574
+ # special string to csa
575
+ def special2csa(str)
576
+ {
577
+ '中断' => 'CHUDAN',
578
+ '投了' => 'TORYO',
579
+ '持将棋' => 'JISHOGI',
580
+ '千日手' => 'SENNICHITE',
581
+ '詰み' => 'TSUMI',
582
+ '不詰' => 'FUZUMI',
583
+ '切れ負け' => 'TIME_UP',
584
+ '反則勝ち' => 'ILLEGAL_ACTION', # 直前の手が反則(先頭に+か-で反則した側の情報を含める必要が有る)
585
+ '反則負け' => 'ILLEGAL_MOVE' # ここで手番側が反則,反則の内容はコメントで表現
586
+ }[str] || (raise ParseError)
586
587
  end
587
- ret["promote"] = true if fugou["promote"]
588
- ret["from"] = from if from
589
- ret
590
- end
591
588
 
592
- # special string to csa
593
- def special2csa(str)
594
- {
595
- "中断" => "CHUDAN",
596
- "投了" => "TORYO",
597
- "持将棋" => "JISHOGI",
598
- "千日手" => "SENNICHITE",
599
- "詰み" => "TSUMI",
600
- "不詰" => "FUZUMI",
601
- "切れ負け" => "TIME_UP",
602
- "反則勝ち" => "ILLEGAL_ACTION", # 直前の手が反則(先頭に+か-で反則した側の情報を含める必要が有る)
603
- "反則負け" => "ILLEGAL_MOVE" # ここで手番側が反則,反則の内容はコメントで表現
604
- }[str] || (raise ParseError)
605
- end
589
+ # teban to color
590
+ def teban2color(teban)
591
+ teban = teban.to_i unless teban.is_a? Integer
592
+ (teban + 1) % 2
593
+ end
606
594
 
607
- # teban to color
608
- def teban2color(teban)
609
- teban = teban.to_i unless teban.is_a? Fixnum
610
- (teban + 1) % 2
611
- end
595
+ # generate motigoma
596
+ def make_hand(str)
597
+ # Kifu for iPhoneは半角スペース区切り
598
+ ret = { 'FU' => 0, 'KY' => 0, 'KE' => 0, 'GI' => 0, 'KI' => 0, 'KA' => 0, 'HI' => 0 }
599
+ return ret if str.empty?
612
600
 
613
- # generate motigoma
614
- def make_hand(str)
615
- # Kifu for iPhoneは半角スペース区切り
616
- ret = { "FU" => 0, "KY" => 0, "KE" => 0, "GI" => 0, "KI" => 0, "KA" => 0, "HI" => 0 }
617
- return ret if str.empty?
601
+ str.split(/[  ]/).each do |kind|
602
+ next if kind.empty?
603
+ ret[kind2csa(kind[0])] = kind.length == 1 ? 1 : kan2n2(kind[1..-1])
604
+ end
618
605
 
619
- str.split(/[  ]/).each do |kind|
620
- next if kind.empty?
621
- ret[kind2csa(kind[0])] = kind.length == 1 ? 1 : kan2n2(kind[1..-1])
606
+ ret
622
607
  end
623
608
 
624
- ret
625
- end
626
-
627
- # exchange sente gote
628
- def reverse_color(moves)
629
- moves.each do |move|
630
- if move["move"] && move["move"]["color"]
631
- move["move"]["color"] = (move["move"]["color"] + 1) % 2
609
+ # exchange sente gote
610
+ def reverse_color(moves)
611
+ moves.each do |move|
612
+ if move['move'] && move['move']['color']
613
+ move['move']['color'] = (move['move']['color'] + 1) % 2
614
+ end
615
+ move['forks']&.each { |fork| reverse_color(fork) }
632
616
  end
633
- move["forks"].each { |_fork| reverse_color(_fork) } if move["forks"]
634
617
  end
635
618
  end
636
619
  end