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,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