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,829 +1,814 @@
1
- # coding: utf-8
2
-
3
- module Jkf::Parser
4
- # CSA Parser
5
- class Csa < Base
6
- protected
7
-
8
- # kifu : csa2 | csa1
9
- def parse_root
10
- @input += "\n" unless @input[-1] =~ /\n|\r|,/ # FIXME
11
- s0 = parse_csa2
12
- s0 = parse_csa1 if s0 == :failed
13
- s0
14
- end
15
-
16
- # csa2 : version22 information? initialboard moves?
17
- def parse_csa2
18
- s0 = @current_pos
19
- if parse_version22 != :failed
20
- s1 = parse_information
21
- s1 = nil if s1 == :failed
22
- s2 = parse_initial_board
23
- if s2 != :failed
24
- s3 = parse_moves
25
- s3 = nil if s3 == :failed
26
- @reported_pos = s0
27
- s0 = -> (info, ini, ms) do
28
- ret = { "header" => info["header"], "initial" => ini, "moves" => ms }
29
- if info && info["players"]
30
- ret["header"]["先手"] = info["players"][0] if info["players"][0]
31
- ret["header"]["後手"] = info["players"][1] if info["players"][1]
32
- end
33
- ret
34
- end.call(s1, s2, s3)
35
- else
36
- @current_pos = s0
1
+ module Jkf
2
+ module Parser
3
+ # CSA Parser
4
+ class Csa < Base
5
+ protected
6
+
7
+ # kifu : csa2 | csa1
8
+ def parse_root
9
+ @scanner << "\n" unless @scanner.string[-1] =~ /\n|\r|,/ # FIXME
10
+ s0 = parse_csa2
11
+ s0 = parse_csa1 if s0 == :failed
12
+ s0
13
+ end
14
+
15
+ # csa2 : version22 information? initialboard moves?
16
+ def parse_csa2
17
+ s0 = @scanner.pos
18
+ if parse_version22 == :failed
19
+ @scanner.pos = s0
37
20
  s0 = :failed
21
+ else
22
+ s1 = parse_information
23
+ s1 = nil if s1 == :failed
24
+ s2 = parse_initial_board
25
+ if s2 == :failed
26
+ @scanner.pos = s0
27
+ s0 = :failed
28
+ else
29
+ s3 = parse_moves
30
+ s3 = nil if s3 == :failed
31
+ @reported_pos = s0
32
+ s0 = -> (info, ini, ms) do
33
+ ret = { 'header' => info['header'], 'initial' => ini, 'moves' => ms }
34
+ if info && info['players']
35
+ ret['header']['先手'] = info['players'][0] if info['players'][0]
36
+ ret['header']['後手'] = info['players'][1] if info['players'][1]
37
+ end
38
+ ret
39
+ end.call(s1, s2, s3)
40
+ end
38
41
  end
39
- else
40
- @current_pos = s0
41
- s0 = :failed
42
+ s0
42
43
  end
43
- s0
44
- end
45
44
 
46
- # version22 : comment* "V2.2" nl
47
- def parse_version22
48
- s0 = @current_pos
49
- s1 = parse_comments
50
- s2 = match_str("V2.2")
51
- if s2 != :failed
52
- s3 = parse_nl
53
- if s3 != :failed
54
- s0 = [s1, s2, s3]
55
- else
56
- @current_pos = s0
45
+ # version22 : comment* "V2.2" nl
46
+ def parse_version22
47
+ s0 = @scanner.pos
48
+ s1 = parse_comments
49
+ s2 = match_str('V2.2')
50
+ if s2 == :failed
51
+ @scanner.pos = s0
57
52
  s0 = :failed
53
+ else
54
+ s3 = parse_nl
55
+ if s3 == :failed
56
+ @scanner.pos = s0
57
+ s0 = :failed
58
+ else
59
+ s0 = [s1, s2, s3]
60
+ end
58
61
  end
59
- else
60
- @current_pos = s0
61
- s0 = :failed
62
+ s0
62
63
  end
63
- s0
64
- end
65
64
 
66
- # information : players? headers
67
- def parse_information
68
- s0 = @current_pos
69
- s1 = parse_players
70
- s1 = nil if s1 == :failed
71
- s2 = parse_headers
72
- if s2 != :failed
73
- @reported_pos = s0
74
- s0 = { "players" => s1, "header" => s2 }
75
- else
76
- @current_pos = s0
77
- s0 = :failed
65
+ # information : players? headers
66
+ def parse_information
67
+ s0 = @scanner.pos
68
+ s1 = parse_players
69
+ s1 = nil if s1 == :failed
70
+ s2 = parse_headers
71
+ if s2 == :failed
72
+ @scanner.pos = s0
73
+ s0 = :failed
74
+ else
75
+ @reported_pos = s0
76
+ s0 = { 'players' => s1, 'header' => s2 }
77
+ end
78
+ s0
78
79
  end
79
- s0
80
- end
81
80
 
82
- # headers : header*
83
- def parse_headers
84
- s0 = @current_pos
85
- s1 = []
86
- s2 = parse_header
87
- while s2 != :failed
88
- s1 << s2
81
+ # headers : header*
82
+ def parse_headers
83
+ s0 = @scanner.pos
84
+ s1 = []
89
85
  s2 = parse_header
90
- end
91
- @reported_pos = s0
92
- s0 = -> (header) do
93
- ret = {}
94
- header.each do |data|
95
- ret[normalize_header_key(data["k"])] = data["v"]
86
+ while s2 != :failed
87
+ s1 << s2
88
+ s2 = parse_header
96
89
  end
97
- ret
98
- end.call(s1)
99
- s0
100
- end
101
-
102
- # header : comment* "$" [^:]+ ":" nonls nl
103
- def parse_header
104
- s0 = @current_pos
105
- parse_comments
106
- if match_str("$") != :failed
107
- s4 = match_regexp(/^[^:]/)
108
- if s4 != :failed
109
- s3 = []
110
- while s4 != :failed
111
- s3 << s4
112
- s4 = match_regexp(/^[^:]/)
90
+ @reported_pos = s0
91
+ -> (header) do
92
+ ret = {}
93
+ header.each do |data|
94
+ ret[normalize_header_key(data['k'])] = data['v']
113
95
  end
96
+ ret
97
+ end.call(s1)
98
+ end
99
+
100
+ # header : comment* "$" [^:]+ ":" nonls nl
101
+ def parse_header
102
+ s0 = @scanner.pos
103
+ parse_comments
104
+ if match_str('$') == :failed
105
+ @scanner.pos = s0
106
+ s0 = :failed
114
107
  else
115
- s3 = :failed
116
- end
117
- if s3 != :failed
118
- if match_str(":") != :failed
108
+ s4 = match_regexp(/[^:]/)
109
+ if s4 == :failed
110
+ s3 = :failed
111
+ else
112
+ s3 = []
113
+ while s4 != :failed
114
+ s3 << s4
115
+ s4 = match_regexp(/[^:]/)
116
+ end
117
+ end
118
+ if s3 == :failed
119
+ @scanner.pos = s0
120
+ s0 = :failed
121
+ elsif match_str(':') != :failed
119
122
  s4 = parse_nonls
120
- if parse_nl != :failed
121
- @reported_pos = s0
122
- s0 = { "k" => s3.join, "v" => s4.join }
123
- else
124
- @current_pos = s0
123
+ if parse_nl == :failed
124
+ @scanner.pos = s0
125
125
  s0 = :failed
126
+ else
127
+ @reported_pos = s0
128
+ s0 = { 'k' => s3.join, 'v' => s4.join }
126
129
  end
127
130
  else
128
- @current_pos = s0
131
+ @scanner.pos = s0
129
132
  s0 = :failed
130
133
  end
131
- else
132
- @current_pos = s0
133
- s0 = :failed
134
134
  end
135
- else
136
- @current_pos = s0
137
- s0 = :failed
135
+ s0
138
136
  end
139
- s0
140
- end
141
137
 
142
- # csa1 : players? initialboard? moves
143
- def parse_csa1
144
- s0 = @current_pos
145
- s1 = parse_players
146
- s1 = nil if s1 == :failed
147
- s2 = parse_initial_board
148
- s2 = nil if s2 == :failed
149
- s3 = parse_moves
150
- if s3 != :failed
151
- @reported_pos = s0
152
- s0 = -> (ply, ini, ms) do
153
- ret = { "header" => {}, "initial" => ini, "moves" => ms }
154
- if ply
155
- ret["header"]["先手"] = ply[0] if ply[0]
156
- ret["header"]["後手"] = ply[1] if ply[1]
157
- end
158
- ret
159
- end.call(s1, s2, s3)
160
- else
161
- @current_pos = s0
162
- s0 = :failed
138
+ # csa1 : players? initialboard? moves
139
+ def parse_csa1
140
+ s0 = @scanner.pos
141
+ s1 = parse_players
142
+ s1 = nil if s1 == :failed
143
+ s2 = parse_initial_board
144
+ s2 = nil if s2 == :failed
145
+ s3 = parse_moves
146
+ if s3 == :failed
147
+ @scanner.pos = s0
148
+ s0 = :failed
149
+ else
150
+ @reported_pos = s0
151
+ s0 = -> (ply, ini, ms) do
152
+ ret = { 'header' => {}, 'initial' => ini, 'moves' => ms }
153
+ if ply
154
+ ret['header']['先手'] = ply[0] if ply[0]
155
+ ret['header']['後手'] = ply[1] if ply[1]
156
+ end
157
+ ret
158
+ end.call(s1, s2, s3)
159
+ end
160
+ s0
163
161
  end
164
- s0
165
- end
166
162
 
167
- # players : comment* ("N+" nonls nl)? comment* ("N-" nonls nl)?
168
- def parse_players
169
- s0 = @current_pos
170
- parse_comments
171
- s2 = @current_pos
172
- if match_str("N+") != :failed
173
- s4 = parse_nonls
174
- if parse_nl != :failed
175
- @reported_pos = s2
176
- s2 = s4
177
- else
178
- @current_pos = s2
163
+ # players : comment* ("N+" nonls nl)? comment* ("N-" nonls nl)?
164
+ def parse_players
165
+ s0 = @scanner.pos
166
+ parse_comments
167
+ s2 = @scanner.pos
168
+ if match_str('N+') == :failed
169
+ @scanner.pos = s2
179
170
  s2 = :failed
180
- end
181
- else
182
- @current_pos = s2
183
- s2 = :failed
184
- end
185
- s2 = nil if s2 == :failed
186
- parse_comments
187
- s4 = @current_pos
188
- if match_str("N-") != :failed
189
- s6 = parse_nonls
190
- if parse_nl != :failed
191
- @reported_pos = s4
192
- s4 = s6
193
171
  else
194
- @current_pos = s4
172
+ s4 = parse_nonls
173
+ if parse_nl == :failed
174
+ @scanner.pos = s2
175
+ s2 = :failed
176
+ else
177
+ @reported_pos = s2
178
+ s2 = s4
179
+ end
180
+ end
181
+ s2 = nil if s2 == :failed
182
+ parse_comments
183
+ s4 = @scanner.pos
184
+ if match_str('N-') == :failed
185
+ @scanner.pos = s4
195
186
  s4 = :failed
187
+ else
188
+ s6 = parse_nonls
189
+ if parse_nl == :failed
190
+ @scanner.pos = s4
191
+ s4 = :failed
192
+ else
193
+ @reported_pos = s4
194
+ s4 = s6
195
+ end
196
196
  end
197
- else
198
- @current_pos = s4
199
- s4 = :failed
197
+ s4 = nil if s4 == :failed
198
+ @reported_pos = s0
199
+ [s2&.join, s4&.join]
200
200
  end
201
- s4 = nil if s4 == :failed
202
- @reported_pos = s0
203
- s0 = [(s2 ? s2.join : nil), (s4 ? s4.join : nil)]
204
- s0
205
- end
206
201
 
207
- # initialboard : comment* (hirate | ikkatsu | "") komabetsu comment* teban nl
208
- def parse_initial_board
209
- s0 = @current_pos
210
- parse_comments
211
- s2 = parse_hirate
212
- if s2 == :failed
213
- s2 = parse_ikkatsu
202
+ # initialboard : comment* (hirate | ikkatsu | "") komabetsu comment* teban nl
203
+ def parse_initial_board
204
+ s0 = @scanner.pos
205
+ parse_comments
206
+ s2 = parse_hirate
214
207
  if s2 == :failed
215
- s2 = @current_pos
216
- s3 = match_str("")
217
- if s3 != :failed
218
- @reported_pos = s2
219
- s3 = "NO"
208
+ s2 = parse_ikkatsu
209
+ if s2 == :failed
210
+ s2 = @scanner.pos
211
+ s3 = match_str('')
212
+ if s3 != :failed
213
+ @reported_pos = s2
214
+ s3 = 'NO'
215
+ end
216
+ s2 = s3
220
217
  end
221
- s2 = s3
222
218
  end
223
- end
224
- if s2 != :failed
225
- s3 = parse_komabetsu
226
- if s3 != :failed
227
- parse_comments
228
- s5 = parse_teban
229
- if s5 != :failed
230
- if parse_nl != :failed
219
+ if s2 == :failed
220
+ @scanner.pos = s0
221
+ :failed
222
+ else
223
+ s3 = parse_komabetsu
224
+ if s3 == :failed
225
+ @scanner.pos = s0
226
+ :failed
227
+ else
228
+ parse_comments
229
+ s5 = parse_teban
230
+ if s5 == :failed
231
+ @scanner.pos = s0
232
+ :failed
233
+ elsif parse_nl != :failed
231
234
  @reported_pos = s0
232
235
  -> (data, koma, teban) do
233
- if data == "NO"
236
+ if data == 'NO'
234
237
  data = koma
235
238
  else
236
- data["data"]["hands"] = koma["data"]["hands"]
239
+ data['data']['hands'] = koma['data']['hands']
237
240
  end
238
- data["data"]["color"] = teban
241
+ data['data']['color'] = teban
239
242
  data
240
243
  end.call(s2, s3, s5)
241
244
  else
242
- @current_pos = s0
245
+ @scanner.pos = s0
243
246
  :failed
244
247
  end
245
- else
246
- @current_pos = s0
247
- :failed
248
248
  end
249
- else
250
- @current_pos = s0
251
- :failed
252
249
  end
253
- else
254
- @current_pos = s0
255
- :failed
256
250
  end
257
- end
258
251
 
259
- # hirate : "PI" xypiece* nl
260
- def parse_hirate
261
- s0 = @current_pos
262
- if match_str("PI") != :failed
263
- s2 = []
264
- s3 = parse_xy_piece
265
- while s3 != :failed
266
- s2 << s3
267
- s3 = parse_xy_piece
268
- end
269
- if parse_nl != :failed
270
- @reported_pos = s0
271
- s0 = -> (ps) do
272
- ret = { "preset" => "OTHER", "data" => { "board" => get_hirate } }
273
- ps.each do |piece|
274
- ret["data"]["board"][piece["xy"]["x"] - 1][piece["xy"]["y"] - 1] = {}
275
- end
276
- ret
277
- end.call(s2)
278
- else
279
- @current_pos = s0
252
+ # hirate : "PI" xypiece* nl
253
+ def parse_hirate
254
+ s0 = @scanner.pos
255
+ if match_str('PI') == :failed
256
+ @scanner.pos = s0
280
257
  s0 = :failed
258
+ else
259
+ s2 = []
260
+ s3 = parse_xy_piece
261
+ while s3 != :failed
262
+ s2 << s3
263
+ s3 = parse_xy_piece
264
+ end
265
+ if parse_nl == :failed
266
+ @scanner.pos = s0
267
+ s0 = :failed
268
+ else
269
+ @reported_pos = s0
270
+ s0 = -> (ps) do
271
+ ret = { 'preset' => 'OTHER', 'data' => { 'board' => hirate } }
272
+ ps.each do |piece|
273
+ ret['data']['board'][piece['xy']['x'] - 1][piece['xy']['y'] - 1] = {}
274
+ end
275
+ ret
276
+ end.call(s2)
277
+ end
281
278
  end
282
- else
283
- @current_pos = s0
284
- s0 = :failed
279
+ s0
285
280
  end
286
- s0
287
- end
288
281
 
289
- # ikkatsu : ikkatsuline+
290
- def parse_ikkatsu
291
- s0 = @current_pos
292
- s2 = parse_ikkatsu_line
293
- if s2 != :failed
294
- s1 = []
295
- while s2 != :failed
296
- s1 << s2
297
- s2 = parse_ikkatsu_line
282
+ # ikkatsu : ikkatsuline+
283
+ def parse_ikkatsu
284
+ s0 = @scanner.pos
285
+ s2 = parse_ikkatsu_line
286
+ if s2 == :failed
287
+ s1 = :failed
288
+ else
289
+ s1 = []
290
+ while s2 != :failed
291
+ s1 << s2
292
+ s2 = parse_ikkatsu_line
293
+ end
298
294
  end
299
- else
300
- s1 = :failed
301
- end
302
- if s1 != :failed
303
- @reported_pos = s0
304
- s1 = -> (lines) do
305
- board = []
306
- 9.times do |i|
307
- line = []
308
- 9.times do |j|
309
- line << lines[j][8 - i]
295
+ if s1 != :failed
296
+ @reported_pos = s0
297
+ s1 = -> (lines) do
298
+ board = []
299
+ 9.times do |i|
300
+ line = []
301
+ 9.times do |j|
302
+ line << lines[j][8 - i]
303
+ end
304
+ board << line
310
305
  end
311
- board << line
312
- end
313
- { "preset" => "OTHER", "data" => { "board" => board } }
314
- end.call(s1)
306
+ { 'preset' => 'OTHER', 'data' => { 'board' => board } }
307
+ end.call(s1)
308
+ end
309
+ s1
315
310
  end
316
- s0 = s1
317
- s0
318
- end
319
311
 
320
- # ikkatsuline : "P" [1-9] masu+ nl
321
- def parse_ikkatsu_line
322
- s0 = @current_pos
323
- if match_str("P") != :failed
324
- if match_digit != :failed
312
+ # ikkatsuline : "P" [1-9] masu+ nl
313
+ def parse_ikkatsu_line
314
+ s0 = @scanner.pos
315
+ if match_str('P') == :failed
316
+ @scanner.pos = s0
317
+ s0 = :failed
318
+ elsif match_digit != :failed
325
319
  s4 = parse_masu
326
- if s4 != :failed
320
+ if s4 == :failed
321
+ s3 = :failed
322
+ else
327
323
  s3 = []
328
324
  while s4 != :failed
329
325
  s3 << s4
330
326
  s4 = parse_masu
331
327
  end
332
- else
333
- s3 = :failed
334
328
  end
335
- if s3 != :failed
329
+ if s3 == :failed
330
+ @scanner.pos = s0
331
+ s0 = :failed
332
+ else
336
333
  s4 = parse_nl
337
- if s4 != :failed
334
+ if s4 == :failed
335
+ @scanner.pos = s0
336
+ s0 = :failed
337
+ else
338
338
  @reported_pos = s0
339
339
  s0 = s3
340
- else
341
- @current_pos = s0
342
- s0 = :failed
343
340
  end
344
- else
345
- @current_pos = s0
346
- s0 = :failed
347
341
  end
348
342
  else
349
- @current_pos = s0
343
+ @scanner.pos = s0
350
344
  s0 = :failed
351
345
  end
352
- else
353
- @current_pos = s0
354
- s0 = :failed
346
+ s0
355
347
  end
356
- s0
357
- end
358
348
 
359
- # masu : teban piece | " * "
360
- def parse_masu
361
- s0 = @current_pos
362
- s1 = parse_teban
363
- if s1 != :failed
364
- s2 = parse_piece
365
- if s2 != :failed
366
- @reported_pos = s0
367
- s0 = { "color" => s1, "kind" => s2 }
368
- else
369
- @current_pos = s0
349
+ # masu : teban piece | " * "
350
+ def parse_masu
351
+ s0 = @scanner.pos
352
+ s1 = parse_teban
353
+ if s1 == :failed
354
+ @scanner.pos = s0
370
355
  s0 = :failed
356
+ else
357
+ s2 = parse_piece
358
+ if s2 == :failed
359
+ @scanner.pos = s0
360
+ s0 = :failed
361
+ else
362
+ @reported_pos = s0
363
+ s0 = { 'color' => s1, 'kind' => s2 }
364
+ end
371
365
  end
372
- else
373
- @current_pos = s0
374
- s0 = :failed
375
- end
376
- if s0 == :failed
377
- s0 = @current_pos
378
- if match_str(" * ") != :failed
379
- @reported_pos = s0
380
- s1 = {}
366
+ if s0 == :failed
367
+ s0 = @scanner.pos
368
+ if match_str(' * ') != :failed
369
+ @reported_pos = s0
370
+ s1 = {}
371
+ end
372
+ s0 = s1
381
373
  end
382
- s0 = s1
374
+ s0
383
375
  end
384
- s0
385
- end
386
376
 
387
- # komabetsu : komabetsuline*
388
- def parse_komabetsu
389
- s0 = @current_pos
390
- s1 = []
391
- s2 = parse_komabetsu_line
392
- while s2 != :failed
393
- s1 << s2
377
+ # komabetsu : komabetsuline*
378
+ def parse_komabetsu
379
+ s0 = @scanner.pos
380
+ s1 = []
394
381
  s2 = parse_komabetsu_line
382
+ while s2 != :failed
383
+ s1 << s2
384
+ s2 = parse_komabetsu_line
385
+ end
386
+ @reported_pos = s0
387
+ transform_komabetsu_lines(s1)
395
388
  end
396
- @reported_pos = s0
397
- transform_komabetsu_lines(s1)
398
- end
399
389
 
400
- # komabetsuline : "P" teban xypiece+ nl
401
- def parse_komabetsu_line
402
- s0 = @current_pos
403
- if match_str("P") != :failed
404
- s2 = parse_teban
405
- if s2 != :failed
406
- s4 = parse_xy_piece
407
- if s4 != :failed
408
- s3 = []
409
- while s4 != :failed
410
- s3 << s4
411
- s4 = parse_xy_piece
412
- end
390
+ # komabetsuline : "P" teban xypiece+ nl
391
+ def parse_komabetsu_line
392
+ s0 = @scanner.pos
393
+ if match_str('P') == :failed
394
+ @scanner.pos = s0
395
+ s0 = :failed
396
+ else
397
+ s2 = parse_teban
398
+ if s2 == :failed
399
+ @scanner.pos = s0
400
+ s0 = :failed
413
401
  else
414
- s3 = :failed
415
- end
416
- if s3 != :failed
417
- if parse_nl != :failed
402
+ s4 = parse_xy_piece
403
+ if s4 == :failed
404
+ s3 = :failed
405
+ else
406
+ s3 = []
407
+ while s4 != :failed
408
+ s3 << s4
409
+ s4 = parse_xy_piece
410
+ end
411
+ end
412
+ if s3 == :failed
413
+ @scanner.pos = s0
414
+ s0 = :failed
415
+ elsif parse_nl != :failed
418
416
  @reported_pos = s0
419
- s0 = { "teban" => s2, "pieces" => s3 }
417
+ s0 = { 'teban' => s2, 'pieces' => s3 }
420
418
  else
421
- @current_pos = s0
419
+ @scanner.pos = s0
422
420
  s0 = :failed
423
421
  end
424
- else
425
- @current_pos = s0
426
- s0 = :failed
427
422
  end
428
- else
429
- @current_pos = s0
430
- s0 = :failed
431
423
  end
432
- else
433
- @current_pos = s0
434
- s0 = :failed
424
+ s0
435
425
  end
436
- s0
437
- end
438
426
 
439
- # moves : firstboard move* comment*
440
- def parse_moves
441
- s0 = @current_pos
442
- s1 = parse_firstboard
443
- if s1 != :failed
444
- s2 = []
445
- s3 = parse_move
446
- while s3 != :failed
447
- s2 << s3
427
+ # moves : firstboard move* comment*
428
+ def parse_moves
429
+ s0 = @scanner.pos
430
+ s1 = parse_firstboard
431
+ if s1 == :failed
432
+ @scanner.pos = s0
433
+ s0 = :failed
434
+ else
435
+ s2 = []
448
436
  s3 = parse_move
437
+ while s3 != :failed
438
+ s2 << s3
439
+ s3 = parse_move
440
+ end
441
+ parse_comments
442
+ @reported_pos = s0
443
+ s0 = s2.unshift(s1)
449
444
  end
450
- parse_comments
451
- @reported_pos = s0
452
- s0 = s2.unshift(s1)
453
- else
454
- @current_pos = s0
455
- s0 = :failed
445
+ s0
456
446
  end
457
- s0
458
- end
459
447
 
460
- # firstboard : comment*
461
- def parse_firstboard
462
- s0 = @current_pos
463
- s1 = parse_comments
464
- @reported_pos = s0
465
- s1.empty? ? {} : { "comments" => s1 }
466
- end
467
-
468
- # move : (normalmove | specialmove) time? comment*
469
- def parse_move
470
- s0 = @current_pos
471
- s1 = parse_normal_move
472
- s1 = parse_special_move if s1 == :failed
473
- if s1 != :failed
474
- s2 = parse_time
475
- s2 = nil if s2 == :failed
476
- s3 = parse_comments
448
+ # firstboard : comment*
449
+ def parse_firstboard
450
+ s0 = @scanner.pos
451
+ s1 = parse_comments
477
452
  @reported_pos = s0
478
- s0 = -> (move, time, comments) do
479
- ret = {}
480
- ret["comments"] = comments if !comments.empty?
481
- ret["time"] = time if time
482
- if move["special"]
483
- ret["special"] = move["special"]
484
- else
485
- ret["move"] = move
486
- end
487
- ret
488
- end.call(s1, s2, s3)
489
- else
490
- @current_pos = s0
491
- s0 = :failed
453
+ s1.empty? ? {} : { 'comments' => s1 }
454
+ end
455
+
456
+ # move : (normalmove | specialmove) time? comment*
457
+ def parse_move
458
+ s0 = @scanner.pos
459
+ s1 = parse_normal_move
460
+ s1 = parse_special_move if s1 == :failed
461
+ if s1 == :failed
462
+ @scanner.pos = s0
463
+ s0 = :failed
464
+ else
465
+ s2 = parse_time
466
+ s2 = nil if s2 == :failed
467
+ s3 = parse_comments
468
+ @reported_pos = s0
469
+ s0 = -> (move, time, comments) do
470
+ ret = {}
471
+ ret['comments'] = comments unless comments.empty?
472
+ ret['time'] = time if time
473
+ if move['special']
474
+ ret['special'] = move['special']
475
+ else
476
+ ret['move'] = move
477
+ end
478
+ ret
479
+ end.call(s1, s2, s3)
480
+ end
481
+ s0
492
482
  end
493
- s0
494
- end
495
483
 
496
- # normalmove : teban xy xy piece nl
497
- def parse_normal_move
498
- s0 = @current_pos
499
- s1 = parse_teban
500
- if s1 != :failed
501
- s2 = parse_xy
502
- if s2 != :failed
503
- s3 = parse_xy
504
- if s3 != :failed
505
- s4 = parse_piece
506
- if s4 != :failed
507
- if parse_nl != :failed
484
+ # normalmove : teban xy xy piece nl
485
+ def parse_normal_move
486
+ s0 = @scanner.pos
487
+ s1 = parse_teban
488
+ if s1 == :failed
489
+ @scanner.pos = s0
490
+ s0 = :failed
491
+ else
492
+ s2 = parse_xy
493
+ if s2 == :failed
494
+ @scanner.pos = s0
495
+ s0 = :failed
496
+ else
497
+ s3 = parse_xy
498
+ if s3 == :failed
499
+ @scanner.pos = s0
500
+ s0 = :failed
501
+ else
502
+ s4 = parse_piece
503
+ if s4 == :failed
504
+ @scanner.pos = s0
505
+ s0 = :failed
506
+ elsif parse_nl != :failed
508
507
  @reported_pos = s0
509
508
  s0 = -> (color, from, to, piece) do
510
- ret = { "color" => color, "to" => to, "piece" => piece }
511
- ret["from"] = from if from["x"] != 0
509
+ ret = { 'color' => color, 'to' => to, 'piece' => piece }
510
+ ret['from'] = from if from['x'] != 0
512
511
  ret
513
512
  end.call(s1, s2, s3, s4)
514
513
  else
515
- @current_pos = s0
514
+ @scanner.pos = s0
516
515
  s0 = :failed
517
516
  end
518
- else
519
- @current_pos = s0
520
- s0 = :failed
521
517
  end
522
- else
523
- @current_pos = s0
524
- s0 = :failed
525
518
  end
526
- else
527
- @current_pos = s0
528
- s0 = :failed
529
519
  end
530
- else
531
- @current_pos = s0
532
- s0 = :failed
520
+ s0
533
521
  end
534
- s0
535
- end
536
522
 
537
- # specialmove : "%" [-+_A-Z]+ nl
538
- def parse_special_move
539
- s0 = @current_pos
540
- s1 = match_str("%")
541
- if s1 != :failed
542
- s3 = match_regexp(/^[\-+_A-Z]/)
543
- if s3 != :failed
544
- s2 = []
545
- while s3 != :failed
546
- s2 << s3
547
- s3 = match_regexp(/^[\-+_A-Z]/)
548
- end
523
+ # specialmove : "%" [-+_A-Z]+ nl
524
+ def parse_special_move
525
+ s0 = @scanner.pos
526
+ s1 = match_str('%')
527
+ if s1 == :failed
528
+ @scanner.pos = s0
529
+ s0 = :failed
549
530
  else
550
- s2 = :failed
551
- end
552
- if s2 != :failed
553
- if parse_nl != :failed
531
+ s3 = match_regexp(/[-+_A-Z]/)
532
+ if s3 == :failed
533
+ s2 = :failed
534
+ else
535
+ s2 = []
536
+ while s3 != :failed
537
+ s2 << s3
538
+ s3 = match_regexp(/[-+_A-Z]/)
539
+ end
540
+ end
541
+ if s2 == :failed
542
+ @scanner.pos = s0
543
+ s0 = :failed
544
+ elsif parse_nl != :failed
554
545
  @reported_pos = s0
555
- s0 = { "special" => s2.join }
546
+ s0 = { 'special' => s2.join }
556
547
  else
557
- @current_pos = s0
548
+ @scanner.pos = s0
558
549
  s0 = :failed
559
550
  end
560
- else
561
- @current_pos = s0
562
- s0 = :failed
563
551
  end
564
- else
565
- @current_pos = s0
566
- s0 = :failed
552
+ s0
567
553
  end
568
- s0
569
- end
570
554
 
571
- # teban : "+" | "-"
572
- def parse_teban
573
- s0 = @current_pos
574
- s1 = match_str("+")
575
- if s1 != :failed
576
- @reported_pos = s0
577
- s1 = 0
578
- end
579
- s0 = s1
580
- if s0 == :failed
581
- s0 = @current_pos
582
- s1 = match_str("-")
555
+ # teban : "+" | "-"
556
+ def parse_teban
557
+ s0 = @scanner.pos
558
+ s1 = match_str('+')
583
559
  if s1 != :failed
584
560
  @reported_pos = s0
585
- s1 = 1
561
+ s1 = 0
586
562
  end
587
563
  s0 = s1
564
+ if s0 == :failed
565
+ s0 = @scanner.pos
566
+ s1 = match_str('-')
567
+ if s1 != :failed
568
+ @reported_pos = s0
569
+ s1 = 1
570
+ end
571
+ s0 = s1
572
+ end
573
+ s0
588
574
  end
589
- s0
590
- end
591
575
 
592
- # comment : "'" nonls nl
593
- def parse_comment
594
- s0 = @current_pos
595
- if match_str("'") != :failed
596
- s2 = parse_nonls
597
- if parse_nl != :failed
598
- @reported_pos = s0
599
- s2.join
600
- else
601
- @current_pos = s0
576
+ # comment : "'" nonls nl
577
+ def parse_comment
578
+ s0 = @scanner.pos
579
+ if match_str("'") == :failed
580
+ @scanner.pos = s0
602
581
  :failed
582
+ else
583
+ s2 = parse_nonls
584
+ if parse_nl == :failed
585
+ @scanner.pos = s0
586
+ :failed
587
+ else
588
+ @reported_pos = s0
589
+ s2.join
590
+ end
603
591
  end
604
- else
605
- @current_pos = s0
606
- :failed
607
592
  end
608
- end
609
593
 
610
- # comments : comment*
611
- def parse_comments
612
- stack = []
613
- matched = parse_comment
614
- while matched != :failed
615
- stack << matched
594
+ # comments : comment*
595
+ def parse_comments
596
+ stack = []
616
597
  matched = parse_comment
598
+ while matched != :failed
599
+ stack << matched
600
+ matched = parse_comment
601
+ end
602
+ stack
617
603
  end
618
- stack
619
- end
620
604
 
621
- # time : "T" [0-9]* nl
622
- def parse_time
623
- s0 = @current_pos
624
- if match_str("T") != :failed
625
- s2 = match_digits
626
- if parse_nl != :failed
627
- @reported_pos = s0
628
- s0 = { "now" => sec2time(s2.join.to_i) }
629
- else
630
- @current_pos = s0
605
+ # time : "T" [0-9]* nl
606
+ def parse_time
607
+ s0 = @scanner.pos
608
+ if match_str('T') == :failed
609
+ @scanner.pos = s0
631
610
  s0 = :failed
611
+ else
612
+ s2 = match_digits
613
+ if parse_nl == :failed
614
+ @scanner.pos = s0
615
+ s0 = :failed
616
+ else
617
+ @reported_pos = s0
618
+ s0 = { 'now' => sec2time(s2.join.to_i) }
619
+ end
632
620
  end
633
- else
634
- @current_pos = s0
635
- s0 = :failed
621
+ s0
636
622
  end
637
- s0
638
- end
639
623
 
640
- # xy : [0-9] [0-9]
641
- def parse_xy
642
- s0 = @current_pos
643
- s1 = match_digit
644
- if s1 != :failed
645
- s2 = match_digit
646
- if s2 != :failed
647
- @reported_pos = s0
648
- s0 = { "x" => s1.to_i, "y" => s2.to_i }
649
- else
650
- @current_pos = s0
624
+ # xy : [0-9] [0-9]
625
+ def parse_xy
626
+ s0 = @scanner.pos
627
+ s1 = match_digit
628
+ if s1 == :failed
629
+ @scanner.pos = s0
651
630
  s0 = :failed
631
+ else
632
+ s2 = match_digit
633
+ if s2 == :failed
634
+ @scanner.pos = s0
635
+ s0 = :failed
636
+ else
637
+ @reported_pos = s0
638
+ s0 = { 'x' => s1.to_i, 'y' => s2.to_i }
639
+ end
652
640
  end
653
- else
654
- @current_pos = s0
655
- s0 = :failed
641
+ s0
656
642
  end
657
- s0
658
- end
659
643
 
660
- # piece : [A-Z] [A-Z]
661
- def parse_piece
662
- s0 = @current_pos
663
- s1 = match_regexp(/^[A-Z]/)
664
- if s1 != :failed
665
- s2 = match_regexp(/^[A-Z]/)
666
- if s2 != :failed
667
- @reported_pos = s0
668
- s0 = s1 + s2
669
- else
670
- @current_pos = s0
644
+ # piece : [A-Z] [A-Z]
645
+ def parse_piece
646
+ s0 = @scanner.pos
647
+ s1 = match_regexp(/[A-Z]/)
648
+ if s1 == :failed
649
+ @scanner.pos = s0
671
650
  s0 = :failed
651
+ else
652
+ s2 = match_regexp(/[A-Z]/)
653
+ if s2 == :failed
654
+ @scanner.pos = s0
655
+ s0 = :failed
656
+ else
657
+ @reported_pos = s0
658
+ s0 = s1 + s2
659
+ end
672
660
  end
673
- else
674
- @current_pos = s0
675
- s0 = :failed
661
+ s0
676
662
  end
677
- s0
678
- end
679
663
 
680
- # xypiece : xy piece
681
- def parse_xy_piece
682
- s0 = @current_pos
683
- s1 = parse_xy
684
- if s1 != :failed
685
- s2 = parse_piece
686
- if s2 != :failed
687
- @reported_pos = s0
688
- s0 = { "xy" => s1, "piece" => s2 }
689
- else
690
- @current_pos = s0
664
+ # xypiece : xy piece
665
+ def parse_xy_piece
666
+ s0 = @scanner.pos
667
+ s1 = parse_xy
668
+ if s1 == :failed
669
+ @scanner.pos = s0
691
670
  s0 = :failed
671
+ else
672
+ s2 = parse_piece
673
+ if s2 == :failed
674
+ @scanner.pos = s0
675
+ s0 = :failed
676
+ else
677
+ @reported_pos = s0
678
+ s0 = { 'xy' => s1, 'piece' => s2 }
679
+ end
692
680
  end
693
- else
694
- @current_pos = s0
695
- s0 = :failed
681
+ s0
696
682
  end
697
- s0
698
- end
699
683
 
700
- # nl : ("\r"? "\n") | " "* ","
701
- def parse_nl
702
- s0 = @current_pos
703
- s1 = match_str("\r")
704
- s1 = nil if s1 == :failed
705
- s2 = match_str("\n")
706
- if s2 != :failed
707
- s0 = [s1, s2]
708
- else
709
- @current_pos = s0
710
- s0 = :failed
711
- end
712
- if s0 == :failed
713
- s0 = @current_pos
714
- s1 = match_spaces
715
- s2 = match_str(",")
716
- if s2 != :failed
717
- s0 = [s1, s2]
718
- else
719
- @current_pos = s0
684
+ # nl : ("\r"? "\n") | " "* ","
685
+ def parse_nl
686
+ s0 = @scanner.pos
687
+ s1 = match_str("\r")
688
+ s1 = nil if s1 == :failed
689
+ s2 = match_str("\n")
690
+ if s2 == :failed
691
+ @scanner.pos = s0
720
692
  s0 = :failed
693
+ else
694
+ s0 = [s1, s2]
695
+ end
696
+ if s0 == :failed
697
+ s0 = @scanner.pos
698
+ s1 = match_spaces
699
+ s2 = match_str(',')
700
+ if s2 == :failed
701
+ @scanner.pos = s0
702
+ s0 = :failed
703
+ else
704
+ s0 = [s1, s2]
705
+ end
721
706
  end
707
+ s0
722
708
  end
723
- s0
724
- end
725
-
726
- # nonl : [^\r\n]
727
- def parse_nonl
728
- match_regexp(/^[^\r\n]/)
729
- end
730
709
 
731
- # nonls : nonl*
732
- def parse_nonls
733
- stack = []
734
- matched = parse_nonl
735
- while matched != :failed
736
- stack << matched
737
- matched = parse_nonl
710
+ # nonl : [^\r\n]
711
+ def parse_nonl
712
+ match_regexp(/[^\r\n]/)
738
713
  end
739
- stack
740
- end
741
714
 
742
- # lines to jkf
743
- def transform_komabetsu_lines(lines)
744
- board = generate_empty_board
745
- hands = [
746
- { "FU" => 0, "KY" => 0, "KE" => 0, "GI" => 0, "KI" => 0, "KA" => 0, "HI" => 0 },
747
- { "FU" => 0, "KY" => 0, "KE" => 0, "GI" => 0, "KI" => 0, "KA" => 0, "HI" => 0 }
748
- ]
749
- all = { "FU" => 18, "KY" => 4, "KE" => 4, "GI" => 4, "KI" => 4, "KA" => 2, "HI" => 2 }
750
-
751
- lines.each do |line|
752
- line["pieces"].each do |piece|
753
- xy = piece["xy"]
754
- if xy["x"] == 0
755
- if piece["piece"] == "AL"
756
- hands[line["teban"]] = all
757
- return { "preset" => "OTHER", "data" => { "board" => board, "hands" => hands } }
715
+ # nonls : nonl*
716
+ def parse_nonls
717
+ stack = []
718
+ matched = parse_nonl
719
+ while matched != :failed
720
+ stack << matched
721
+ matched = parse_nonl
722
+ end
723
+ stack
724
+ end
725
+
726
+ # lines to jkf
727
+ def transform_komabetsu_lines(lines)
728
+ board = generate_empty_board
729
+ hands = [
730
+ { 'FU' => 0, 'KY' => 0, 'KE' => 0, 'GI' => 0, 'KI' => 0, 'KA' => 0, 'HI' => 0 },
731
+ { 'FU' => 0, 'KY' => 0, 'KE' => 0, 'GI' => 0, 'KI' => 0, 'KA' => 0, 'HI' => 0 }
732
+ ]
733
+ all = { 'FU' => 18, 'KY' => 4, 'KE' => 4, 'GI' => 4, 'KI' => 4, 'KA' => 2, 'HI' => 2 }
734
+
735
+ lines.each do |line|
736
+ line['pieces'].each do |piece|
737
+ xy = piece['xy']
738
+ if xy['x'] == 0
739
+ if piece['piece'] == 'AL'
740
+ hands[line['teban']] = all
741
+ return { 'preset' => 'OTHER', 'data' => { 'board' => board, 'hands' => hands } }
742
+ end
743
+ obj = hands[line['teban']]
744
+ obj[piece['piece']] += 1
745
+ else
746
+ board[xy['x'] - 1][xy['y'] - 1] = { 'color' => line['teban'],
747
+ 'kind' => piece['piece'] }
758
748
  end
759
- obj = hands[line["teban"]]
760
- obj[piece["piece"]] += 1
761
- else
762
- board[xy["x"] - 1][xy["y"] - 1] = { "color" => line["teban"],
763
- "kind" => piece["piece"] }
749
+ all[piece['piece']] -= 1 if piece['piece'] != 'OU'
764
750
  end
765
- all[piece["piece"]] -= 1 if piece["piece"] != "OU"
766
751
  end
767
- end
768
752
 
769
- { "preset" => "OTHER", "data" => { "board" => board, "hands" => hands } }
770
- end
753
+ { 'preset' => 'OTHER', 'data' => { 'board' => board, 'hands' => hands } }
754
+ end
771
755
 
772
- # return empty board jkf
773
- def generate_empty_board
774
- board = []
775
- 9.times do |_i|
776
- line = []
777
- 9.times do |_j|
778
- line << {}
756
+ # return empty board jkf
757
+ def generate_empty_board
758
+ board = []
759
+ 9.times do |_i|
760
+ line = []
761
+ 9.times do |_j|
762
+ line << {}
763
+ end
764
+ board << line
779
765
  end
780
- board << line
766
+ board
767
+ end
768
+
769
+ # sec to time(m, s)
770
+ def sec2time(sec)
771
+ s = sec % 60
772
+ m = (sec - s) / 60
773
+ { 'm' => m, 's' => s }
774
+ end
775
+
776
+ # return hirate board jkf
777
+ def hirate
778
+ [
779
+ [{ 'color' => 1, 'kind' => 'KY' }, {}, { 'color' => 1, 'kind' => 'FU' }, {}, {}, {},
780
+ { 'color' => 0, 'kind' => 'FU' }, {}, { 'color' => 0, 'kind' => 'KY' }],
781
+ [{ 'color' => 1, 'kind' => 'KE' }, { 'color' => 1, 'kind' => 'KA' },
782
+ { 'color' => 1, 'kind' => 'FU' }, {}, {}, {}, { 'color' => 0, 'kind' => 'FU' },
783
+ { 'color' => 0, 'kind' => 'HI' }, { 'color' => 0, 'kind' => 'KE' }],
784
+ [{ 'color' => 1, 'kind' => 'GI' }, {}, { 'color' => 1, 'kind' => 'FU' }, {}, {}, {},
785
+ { 'color' => 0, 'kind' => 'FU' }, {}, { 'color' => 0, 'kind' => 'GI' }],
786
+ [{ 'color' => 1, 'kind' => 'KI' }, {}, { 'color' => 1, 'kind' => 'FU' }, {}, {}, {},
787
+ { 'color' => 0, 'kind' => 'FU' }, {}, { 'color' => 0, 'kind' => 'KI' }],
788
+ [{ 'color' => 1, 'kind' => 'OU' }, {}, { 'color' => 1, 'kind' => 'FU' }, {}, {}, {},
789
+ { 'color' => 0, 'kind' => 'FU' }, {}, { 'color' => 0, 'kind' => 'OU' }],
790
+ [{ 'color' => 1, 'kind' => 'KI' }, {}, { 'color' => 1, 'kind' => 'FU' }, {}, {}, {},
791
+ { 'color' => 0, 'kind' => 'FU' }, {}, { 'color' => 0, 'kind' => 'KI' }],
792
+ [{ 'color' => 1, 'kind' => 'GI' }, {}, { 'color' => 1, 'kind' => 'FU' }, {}, {}, {},
793
+ { 'color' => 0, 'kind' => 'FU' }, {}, { 'color' => 0, 'kind' => 'GI' }],
794
+ [{ 'color' => 1, 'kind' => 'KE' }, { 'color' => 1, 'kind' => 'HI' },
795
+ { 'color' => 1, 'kind' => 'FU' }, {}, {}, {}, { 'color' => 0, 'kind' => 'FU' },
796
+ { 'color' => 0, 'kind' => 'KA' }, { 'color' => 0, 'kind' => 'KE' }],
797
+ [{ 'color' => 1, 'kind' => 'KY' }, {}, { 'color' => 1, 'kind' => 'FU' }, {}, {}, {},
798
+ { 'color' => 0, 'kind' => 'FU' }, {}, { 'color' => 0, 'kind' => 'KY' }]
799
+ ]
800
+ end
801
+
802
+ # normalize header key
803
+ def normalize_header_key(key)
804
+ {
805
+ 'EVENT' => '棋戦',
806
+ 'SITE' => '場所',
807
+ 'START_TIME' => '開始日時',
808
+ 'END_TIME' => '終了日時',
809
+ 'TIME_LIMIT' => '持ち時間'
810
+ }[key] || key
781
811
  end
782
- board
783
- end
784
-
785
- # sec to time(m, s)
786
- def sec2time(sec)
787
- s = sec % 60
788
- m = (sec - s) / 60
789
- { "m" => m, "s" => s }
790
- end
791
-
792
- # return hirate board jkf
793
- def get_hirate
794
- [
795
- [{ "color" => 1, "kind" => "KY" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
796
- { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "KY" }],
797
- [{ "color" => 1, "kind" => "KE" }, { "color" => 1, "kind" => "KA" },
798
- { "color" => 1, "kind" => "FU" }, {}, {}, {}, { "color" => 0, "kind" => "FU" },
799
- { "color" => 0, "kind" => "HI" }, { "color" => 0, "kind" => "KE" }],
800
- [{ "color" => 1, "kind" => "GI" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
801
- { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "GI" }],
802
- [{ "color" => 1, "kind" => "KI" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
803
- { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "KI" }],
804
- [{ "color" => 1, "kind" => "OU" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
805
- { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "OU" }],
806
- [{ "color" => 1, "kind" => "KI" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
807
- { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "KI" }],
808
- [{ "color" => 1, "kind" => "GI" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
809
- { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "GI" }],
810
- [{ "color" => 1, "kind" => "KE" }, { "color" => 1, "kind" => "HI" },
811
- { "color" => 1, "kind" => "FU" }, {}, {}, {}, { "color" => 0, "kind" => "FU" },
812
- { "color" => 0, "kind" => "KA" }, { "color" => 0, "kind" => "KE" }],
813
- [{ "color" => 1, "kind" => "KY" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
814
- { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "KY" }]
815
- ]
816
- end
817
-
818
- # normalize header key
819
- def normalize_header_key(key)
820
- {
821
- "EVENT" => "棋戦",
822
- "SITE" => "場所",
823
- "START_TIME" => "開始日時",
824
- "END_TIME" => "終了日時",
825
- "TIME_LIMIT" => "持ち時間"
826
- }[key] || key
827
812
  end
828
813
  end
829
814
  end