jkf 0.4.3 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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