jkf 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,189 @@
1
+ module Jkf::Converter
2
+ module Kifuable
3
+ protected
4
+
5
+ def convert_initial(initial)
6
+ result = convert_handicap(initial["preset"])
7
+ footer = ""
8
+
9
+ data = initial["data"]
10
+ if data
11
+ result += convert_teban(data, 1)
12
+ if hands = data["hands"]
13
+ result += convert_hands(hands, 1) if hands[1]
14
+ footer += convert_hands(hands, 0) if hands[0]
15
+ end
16
+ footer += convert_teban(data, 0)
17
+
18
+ result += convert_board(data["board"]) if data["board"]
19
+ end
20
+ result + footer
21
+ end
22
+
23
+ def convert_handicap(preset)
24
+ preset != "OTHER" ? "手合割:#{preset2str(preset)}\n" : ""
25
+ end
26
+
27
+ def convert_teban(data, color)
28
+ data["color"] == color ? "#{@players[color]}手番\n" : ""
29
+ end
30
+
31
+ def convert_hands(hands, color)
32
+ "#{@players[color]}手の持駒:" + convert_motigoma(hands[color])
33
+ end
34
+
35
+ def convert_board(board)
36
+ result = " 9 8 7 6 5 4 3 2 1\n+---------------------------+\n"
37
+ 9.times do |y|
38
+ line = "|"
39
+ 9.times do |x|
40
+ line += convert_board_piece(board[8 - x][y])
41
+ end
42
+ line += "|#{n2kan(y + 1)}\n"
43
+ result += line
44
+ end
45
+ result + "+---------------------------+\n"
46
+ end
47
+
48
+ def convert_comments(comments)
49
+ comments.map { |comment| "*#{comment}\n" }.join
50
+ end
51
+
52
+ def convert_motigoma(pieces)
53
+ pieces.to_a.reverse.map do |(piece, num)|
54
+ if num > 0
55
+ str = csa2kind(piece)
56
+ if num > 1
57
+ str += n2kan(num / 10) if num / 10 > 0
58
+ num %= 10
59
+ str += n2kan(num)
60
+ end
61
+ str
62
+ end
63
+ end.compact.join(" ") + " \n"
64
+ end
65
+
66
+ def convert_board_piece(piece)
67
+ result = ""
68
+
69
+ if piece == {}
70
+ result = " ・"
71
+ else
72
+ result += piece["color"] == 0 ? " " : "v"
73
+ result += csa2kind(piece["kind"])
74
+ end
75
+
76
+ result
77
+ end
78
+
79
+ def convert_special(special, index)
80
+ result = "まで#{index + 1}手"
81
+
82
+ if special == "TORYO" || special =~ /ILLEGAL/
83
+ turn = @players[index % 2]
84
+ result += "で#{turn}手の"
85
+ result += case special
86
+ when "TORYO" then "勝ち"
87
+ when "ILLEGAL_ACTION" then "反則勝ち"
88
+ when "ILLEGAL_MOVE" then "反則負け"
89
+ end
90
+ else
91
+ turn = @players[(index + 1) % 2]
92
+ result += case special
93
+ when "TIME_UP" then "で時間切れにより#{turn}手の勝ち"
94
+ when "CHUDAN" then "で中断"
95
+ when "JISHOGI" then "で持将棋"
96
+ when "SENNICHITE" then "で千日手"
97
+ when "TSUMI" then "で詰み"
98
+ when "FUZUMI" then "で不詰"
99
+ end
100
+ end
101
+
102
+ result + "\n"
103
+ end
104
+
105
+ def convert_piece_with_pos(move)
106
+ result = if move["to"]
107
+ n2zen(move["to"]["x"]) + n2kan(move["to"]["y"])
108
+ elsif move["same"]
109
+ "同 "
110
+ else
111
+ raise "error??"
112
+ end
113
+ result += csa2kind(move["piece"])
114
+ result += "成" if move["promote"]
115
+ result
116
+ end
117
+
118
+ def convert_forks(forks, index)
119
+ result = "\n"
120
+ result = "変化:%4d手\n" % [index] # ki2の場合\nなし
121
+ forks.each do |moves|
122
+ result += convert_moves(moves, index)
123
+ end
124
+ result
125
+ end
126
+
127
+ def reset!
128
+ @forks = []
129
+ @header2 = []
130
+ end
131
+
132
+ def setup_players!(jkf)
133
+ players_flag = :sengo
134
+ jkf["header"] && jkf["header"].keys.detect { |key| key =~ /[上下]手/ } && players_flag = :uwasimo
135
+ @players = if players_flag == :uwasimo
136
+ ["下", "上"]
137
+ else
138
+ ["先", "後"]
139
+ end
140
+ end
141
+
142
+ def n2zen(n)
143
+ "0123456789"[n]
144
+ end
145
+
146
+ def n2kan(n)
147
+ "〇一二三四五六七八九"[n]
148
+ end
149
+
150
+ def csa2kind(csa)
151
+ {
152
+ "FU" => "歩",
153
+ "KY" => "香",
154
+ "KE" => "桂",
155
+ "GI" => "銀",
156
+ "KI" => "金",
157
+ "KA" => "角",
158
+ "HI" => "飛",
159
+ "OU" => "玉",
160
+ "TO" => "と",
161
+ "NY" => "成香",
162
+ "NK" => "成桂",
163
+ "NG" => "成銀",
164
+ "UM" => "馬",
165
+ "RY" => "龍"
166
+ }[csa]
167
+ end
168
+
169
+ def preset2str(preset)
170
+ {
171
+ "HIRATE" => "平手",
172
+ "KY" => "香落ち",
173
+ "KY_R" => "右香落ち",
174
+ "KA" => "角落ち",
175
+ "HI" => "飛車落ち",
176
+ "HIKY" => "飛香落ち",
177
+ "2" => "二枚落ち",
178
+ "3" => "三枚落ち",
179
+ "4" => "四枚落ち",
180
+ "5" => "五枚落ち",
181
+ "5_L" => "左五枚落ち",
182
+ "6" => "六枚落ち",
183
+ "8" => "八枚落ち",
184
+ "10" => "十枚落ち",
185
+ "OTHER" => "その他"
186
+ }[preset]
187
+ end
188
+ end
189
+ end
@@ -4,7 +4,8 @@ module Jkf
4
4
  end
5
5
  end
6
6
 
7
- require 'jkf/parser/base'
8
- require 'jkf/parser/kif'
9
- require 'jkf/parser/ki2'
10
- require 'jkf/parser/csa'
7
+ require "jkf/parser/base"
8
+ require "jkf/parser/kifuable"
9
+ require "jkf/parser/kif"
10
+ require "jkf/parser/ki2"
11
+ require "jkf/parser/csa"
@@ -3,26 +3,32 @@ module Jkf::Parser
3
3
  def parse(input)
4
4
  @input = input.clone
5
5
 
6
- @current_pos = 0
7
- @reported_pos = 0
8
- @cached_pos = 0
6
+ @current_pos = 0
7
+ @reported_pos = 0
8
+ @cached_pos = 0
9
9
  @cached_pos_details = { line: 1, column: 1, seenCR: false }
10
- @max_fail_pos = 0
11
- @max_fail_expected = []
12
- @silent_fails = 0
10
+ @max_fail_pos = 0
11
+ @max_fail_expected = []
12
+ @silent_fails = 0
13
13
 
14
14
  @result = parse_root
15
15
 
16
- if @result != :failded && @current_pos == @input.length
16
+ if success? && @current_pos == @input.size
17
17
  return @result
18
18
  else
19
- fail({ type: "end", description: "end of input" }) if @result != :failed && @current_pos < input.length
19
+ fail(type: "end", description: "end of input") if failed? && @current_pos < input.size
20
20
  raise ParseError
21
21
  end
22
22
  end
23
23
 
24
24
  protected
25
25
 
26
+ def success?
27
+ @result != :failed
28
+ end
29
+
30
+ def failed?; !success?; end
31
+
26
32
  def match_regexp(reg)
27
33
  ret = nil
28
34
  if matched = reg.match(@input[@current_pos])
@@ -30,7 +36,7 @@ module Jkf::Parser
30
36
  @current_pos += ret.size
31
37
  else
32
38
  ret = :failed
33
- fail({ type: "class", value: reg.inspect, description: reg.inspect }) if @silent_fails == 0
39
+ fail(type: "class", value: reg.inspect, description: reg.inspect) if @silent_fails == 0
34
40
  end
35
41
  ret
36
42
  end
@@ -42,11 +48,48 @@ module Jkf::Parser
42
48
  @current_pos += str.size
43
49
  else
44
50
  ret = :failed
45
- fail({ type: "literal", value: str, description: "\"#{str}\"" }) if @slient_fails == 0
51
+ fail(type: "literal", value: str, description: "\"#{str}\"") if @slient_fails == 0
46
52
  end
47
53
  ret
48
54
  end
49
55
 
56
+ def match_space
57
+ match_str(" ")
58
+ end
59
+
60
+ def match_spaces
61
+ stack = []
62
+ matched = match_space
63
+ while matched != :failed
64
+ stack << matched
65
+ matched = match_space
66
+ end
67
+ stack
68
+ end
69
+
70
+ def match_digit
71
+ match_regexp(/^\d/)
72
+ end
73
+
74
+ def match_digits
75
+ stack = []
76
+ matched = match_digit
77
+ while matched != :failed
78
+ stack << matched
79
+ matched = match_digit
80
+ end
81
+ stack
82
+ end
83
+
84
+ def match_digits!
85
+ matched = match_digits
86
+ if matched.empty?
87
+ :failed
88
+ else
89
+ matched
90
+ end
91
+ end
92
+
50
93
  def fail(expected)
51
94
  return if @current_pos < @max_fail_pos
52
95
 
@@ -11,33 +11,22 @@ module Jkf::Parser
11
11
 
12
12
  def parse_csa2
13
13
  s0 = @current_pos
14
- s1 = parse_version22
15
- if s1 != :failed
16
- s2 = parse_information
17
- s2 = nil if s2 == :failed
14
+ if parse_version22 != :failed
15
+ s1 = parse_information
16
+ s1 = nil if s1 == :failed
17
+ s2 = parse_initial_board
18
18
  if s2 != :failed
19
- s3 = parse_initial_board
20
- if s3 != :failed
21
- s4 = parse_moves
22
- s4 = nil if s4 == :failed
23
- if s4 != :failed
24
- @reported_pos = s0
25
- s0 = s1 = -> (info, ini, ms) {
26
- ret = { "header" => info["header"], "initial" => ini, "moves" => ms }
27
- if info && info["players"]
28
- ret["header"]["先手"] = info["players"][0] if info["players"][0]
29
- ret["header"]["後手"] = info["players"][1] if info["players"][1]
30
- end
31
- ret
32
- }.call(s2, s3, s4)
33
- else
34
- @current_pos = s0
35
- s0 = :failed
19
+ s3 = parse_moves
20
+ s3 = nil if s3 == :failed
21
+ @reported_pos = s0
22
+ s0 = -> (info, ini, ms) do
23
+ ret = { "header" => info["header"], "initial" => ini, "moves" => ms }
24
+ if info && info["players"]
25
+ ret["header"]["先手"] = info["players"][0] if info["players"][0]
26
+ ret["header"]["後手"] = info["players"][1] if info["players"][1]
36
27
  end
37
- else
38
- @current_pos = s0
39
- s0 = :failed
40
- end
28
+ ret
29
+ end.call(s1, s2, s3)
41
30
  else
42
31
  @current_pos = s0
43
32
  s0 = :failed
@@ -51,22 +40,12 @@ module Jkf::Parser
51
40
 
52
41
  def parse_version22
53
42
  s0 = @current_pos
54
- s1 = []
55
- s2 = parse_comment
56
- while s2 != :failed
57
- s1 << s2
58
- s2 = parse_comment
59
- end
60
- if s1 != :failed
61
- s2 = match_str("V2.2")
62
- if s2 != :failed
63
- s3 = parse_nl
64
- if s3 != :failed
65
- s0 = s1 = [s1, s2, s3]
66
- else
67
- @current_pos = s0
68
- s0 = :failed
69
- end
43
+ s1 = parse_comments
44
+ s2 = match_str("V2.2")
45
+ if s2 != :failed
46
+ s3 = parse_nl
47
+ if s3 != :failed
48
+ s0 = [s1, s2, s3]
70
49
  else
71
50
  @current_pos = s0
72
51
  s0 = :failed
@@ -82,15 +61,10 @@ module Jkf::Parser
82
61
  s0 = @current_pos
83
62
  s1 = parse_players
84
63
  s1 = nil if s1 == :failed
85
- if s1 != :failed
86
- s2 = parse_headers
87
- if s2 != :failed
88
- @reported_pos = s0
89
- s0 = s1 = { "players" => s1, "header" => s2 }
90
- else
91
- @current_pos = s0
92
- s0 = :failed
93
- end
64
+ s2 = parse_headers
65
+ if s2 != :failed
66
+ @reported_pos = s0
67
+ s0 = { "players" => s1, "header" => s2 }
94
68
  else
95
69
  @current_pos = s0
96
70
  s0 = :failed
@@ -106,63 +80,37 @@ module Jkf::Parser
106
80
  s1 << s2
107
81
  s2 = parse_header
108
82
  end
109
- if s1 != :failed
110
- @reported_pos = s0
111
- s1 = -> (header) {
112
- ret = {}
113
- header.each do |data|
114
- ret[normalize_header_key(data["k"])] = data["v"]
115
- end
116
- ret
117
- }.call(s1)
118
- end
119
- s0 = s1
83
+ @reported_pos = s0
84
+ s0 = -> (header) do
85
+ ret = {}
86
+ header.each do |data|
87
+ ret[normalize_header_key(data["k"])] = data["v"]
88
+ end
89
+ ret
90
+ end.call(s1)
120
91
  s0
121
92
  end
122
93
 
123
94
  def parse_header
124
95
  s0 = @current_pos
125
- s1 = []
126
- s2 = parse_comment
127
- while s2 != :failed
128
- s1 << s2
129
- s2 = parse_comment
130
- end
131
- if s1 != :failed
132
- s2 = match_str("$")
133
- if s2 != :failed
96
+ parse_comments
97
+ if match_str("$") != :failed
98
+ s4 = match_regexp(/^[^:]/)
99
+ if s4 != :failed
134
100
  s3 = []
135
- s4 = match_regexp(/^[^:]/)
136
- if s4 != :failed
137
- while s4 != :failed
138
- s3 << s4
139
- s4 = match_regexp(/^[^:]/)
140
- end
141
- else
142
- s3 = :failed
101
+ while s4 != :failed
102
+ s3 << s4
103
+ s4 = match_regexp(/^[^:]/)
143
104
  end
144
- if s3 != :failed
145
- s4 = match_str(":")
146
- if s4 != :failed
147
- s5 = []
148
- s6 = parse_nonl
149
- while s6 != :failed
150
- s5 << s6
151
- s6 = parse_nonl
152
- end
153
- if s5 != :failed
154
- s6 = parse_nl
155
- if s6 != :failed
156
- @reported_pos = s0
157
- s0 = s1 = { "k" => s3.join, "v" => s5.join }
158
- else
159
- @current_pos = s0
160
- s0 = :failed
161
- end
162
- else
163
- @current_pos = s0
164
- s0 = :failed
165
- end
105
+ else
106
+ s3 = :failed
107
+ end
108
+ if s3 != :failed
109
+ if match_str(":") != :failed
110
+ s4 = parse_nonls
111
+ if parse_nl != :failed
112
+ @reported_pos = s0
113
+ s0 = { "k" => s3.join, "v" => s4.join }
166
114
  else
167
115
  @current_pos = s0
168
116
  s0 = :failed
@@ -186,29 +134,19 @@ module Jkf::Parser
186
134
  s0 = @current_pos
187
135
  s1 = parse_players
188
136
  s1 = nil if s1 == :failed
189
- if s1 != :failed
190
- s2 = parse_initial_board
191
- s2 = nil if s2 == :failed
192
- if s2 != :failed
193
- s3 = parse_moves
194
- if s3 != :failed
195
- @reported_pos = s0
196
- s0 = s1 = -> (ply, ini, ms) {
197
- ret = { "header" => {}, "initial" => ini, "moves" => ms }
198
- if ply
199
- ret["header"]["先手"] = ply[0] if ply[0]
200
- ret["header"]["後手"] = ply[1] if ply[1]
201
- end
202
- ret
203
- }.call(s1, s2, s3)
204
- else
205
- @current_pos = s0
206
- s0 = :failed
137
+ s2 = parse_initial_board
138
+ s2 = nil if s2 == :failed
139
+ s3 = parse_moves
140
+ if s3 != :failed
141
+ @reported_pos = s0
142
+ s0 = -> (ply, ini, ms) do
143
+ ret = { "header" => {}, "initial" => ini, "moves" => ms }
144
+ if ply
145
+ ret["header"]["先手"] = ply[0] if ply[0]
146
+ ret["header"]["後手"] = ply[1] if ply[1]
207
147
  end
208
- else
209
- @current_pos = s0
210
- s0 = :failed
211
- end
148
+ ret
149
+ end.call(s1, s2, s3)
212
150
  else
213
151
  @current_pos = s0
214
152
  s0 = :failed
@@ -218,195 +156,112 @@ module Jkf::Parser
218
156
 
219
157
  def parse_players
220
158
  s0 = @current_pos
221
- s1 = []
222
- s2 = parse_comment
223
- while s2 != :failed
224
- s1 << s2
225
- s2 = parse_comment
226
- end
227
- if s1 != :failed
228
- s2 = @current_pos
229
- s3 = match_str("N+")
230
- if s3 != :failed
231
- s4 = []
232
- s5 = parse_nonl
233
- while s5 != :failed
234
- s4 << s5
235
- s5 = parse_nonl
236
- end
237
- if s4 != :failed
238
- s5 = parse_nl
239
- if s5 != :failed
240
- @reported_pos = s2
241
- s2 = s3 = s4
242
- else
243
- @current_pos = s2
244
- s2 = :failed
245
- end
246
- else
247
- @current_pos = s2
248
- s2 = :failed
249
- end
159
+ parse_comments
160
+ s2 = @current_pos
161
+ if match_str("N+") != :failed
162
+ s4 = parse_nonls
163
+ if parse_nl != :failed
164
+ @reported_pos = s2
165
+ s2 = s4
250
166
  else
251
167
  @current_pos = s2
252
168
  s2 = :failed
253
169
  end
254
- s2 = nil if s2 == :failed
255
- if s2 != :failed
256
- s3 = []
257
- s4 = parse_comment
258
- while s4 != :failed
259
- s3 << s4
260
- s4 = parse_comment
261
- end
262
- if s3 != :failed
263
- s4 = @current_pos
264
- s5 = match_str("N-")
265
- if s5 != :failed
266
- s6 = []
267
- s7 = parse_nonl
268
- while s7 != :failed
269
- s6 << s7
270
- s7 = parse_nonl
271
- end
272
- if s6 != :failed
273
- s7 = parse_nl
274
- if s7 != :failed
275
- @reported_pos = s4
276
- s4 = s5 = s6
277
- else
278
- @current_pos = s4
279
- s4 = :failed
280
- end
281
- else
282
- @current_pos = s4
283
- s4 = :failed
284
- end
285
- else
286
- @current_pos = s4
287
- s4 = :failed
288
- end
289
- s4 = nil if s4 == :failed
290
- if s4 != :failed
291
- @reported_pos = s0
292
- s0 = s1 = [(s2 ? s2.join : nil), (s4 ? s4.join : nil)]
293
- else
294
- @current_pos = s0
295
- s0 = :failed
296
- end
297
- else
298
- @current_pos = s0
299
- s0 = :failed
300
- end
170
+ else
171
+ @current_pos = s2
172
+ s2 = :failed
173
+ end
174
+ s2 = nil if s2 == :failed
175
+ parse_comments
176
+ s4 = @current_pos
177
+ if match_str("N-") != :failed
178
+ s6 = parse_nonls
179
+ if parse_nl != :failed
180
+ @reported_pos = s4
181
+ s4 = s6
301
182
  else
302
- @current_pos = s0
303
- s0 = :failed
183
+ @current_pos = s4
184
+ s4 = :failed
304
185
  end
305
186
  else
306
- @current_pos = s0
307
- s0 = :failed
187
+ @current_pos = s4
188
+ s4 = :failed
308
189
  end
190
+ s4 = nil if s4 == :failed
191
+ @reported_pos = s0
192
+ s0 = [(s2 ? s2.join : nil), (s4 ? s4.join : nil)]
309
193
  s0
310
194
  end
311
195
 
312
196
  def parse_initial_board
313
197
  s0 = @current_pos
314
- s1 = []
315
- s2 = parse_comment
316
- while s2 != :failed
317
- s1 << s2
318
- s2 = parse_comment
319
- end
320
- if s1 != :failed
321
- s2 = parse_hirate
198
+ parse_comments
199
+ s2 = parse_hirate
200
+ if s2 == :failed
201
+ s2 = parse_ikkatsu
322
202
  if s2 == :failed
323
- s2 = parse_ikkatsu
324
- if s2 == :failed
325
- s2 = @current_pos
326
- s3 = match_str("")
327
- if s3 != :failed
328
- @reported_pos = s2
329
- s3 = "NO"
330
- end
331
- s2 = s3
203
+ s2 = @current_pos
204
+ s3 = match_str("")
205
+ if s3 != :failed
206
+ @reported_pos = s2
207
+ s3 = "NO"
332
208
  end
209
+ s2 = s3
333
210
  end
334
- if s2 != :failed
335
- s3 = parse_komabetsu
336
- if s3 != :failed
337
- s4 = []
338
- s5 = parse_comment
339
- while s5 != :failed
340
- s4 << s5
341
- s5 = parse_comment
342
- end
343
- if s4 != :failed
344
- s5 = parse_teban
345
- if s5 != :failed
346
- s6 = parse_nl
347
- if s6 != :failed
348
- @reported_pos = s0
349
- s0 = s1 = -> (data, koma, teban) {
350
- if data == "NO"
351
- data = koma
352
- else
353
- data["data"]["hands"] = koma["data"]["hands"]
354
- end
355
- data["data"]["color"] = teban
356
- data
357
- }.call(s2, s3, s5)
211
+ end
212
+ if s2 != :failed
213
+ s3 = parse_komabetsu
214
+ if s3 != :failed
215
+ parse_comments
216
+ s5 = parse_teban
217
+ if s5 != :failed
218
+ if parse_nl != :failed
219
+ @reported_pos = s0
220
+ -> (data, koma, teban) do
221
+ if data == "NO"
222
+ data = koma
358
223
  else
359
- @current_pos = s0
360
- s0 = :failed
224
+ data["data"]["hands"] = koma["data"]["hands"]
361
225
  end
362
- else
363
- @current_pos = s0
364
- s0 = :failed
365
- end
226
+ data["data"]["color"] = teban
227
+ data
228
+ end.call(s2, s3, s5)
366
229
  else
367
230
  @current_pos = s0
368
- s0 = :failed
231
+ :failed
369
232
  end
370
233
  else
371
234
  @current_pos = s0
372
- s0 = :failed
235
+ :failed
373
236
  end
374
237
  else
375
238
  @current_pos = s0
376
- s0 = :failed
239
+ :failed
377
240
  end
378
241
  else
379
242
  @current_pos = s0
380
- s0 = :failed
243
+ :failed
381
244
  end
382
- s0
383
245
  end
384
246
 
385
247
  def parse_hirate
386
248
  s0 = @current_pos
387
- s1 = match_str("PI")
388
- if s1 != :failed
249
+ if match_str("PI") != :failed
389
250
  s2 = []
390
251
  s3 = parse_xy_piece
391
252
  while s3 != :failed
392
253
  s2 << s3
393
254
  s3 = parse_xy_piece
394
255
  end
395
- if s2 != :failed
396
- s3 = parse_nl
397
- if s3 != :failed
398
- @reported_pos = s0
399
- s0 = s1 = -> (ps) {
400
- ret = { "preset" => "OTHER", "data" => { "board" => get_hirate } }
401
- ps.each do |piece|
402
- ret["data"]["board"][piece["xy"]["x"]-1][piece["xy"]["y"]-1] = {}
403
- end
404
- ret
405
- }.call(s2)
406
- else
407
- @current_pos = s0
408
- s0 = :failed
409
- end
256
+ if parse_nl != :failed
257
+ @reported_pos = s0
258
+ s0 = -> (ps) do
259
+ ret = { "preset" => "OTHER", "data" => { "board" => get_hirate } }
260
+ ps.each do |piece|
261
+ ret["data"]["board"][piece["xy"]["x"] - 1][piece["xy"]["y"] - 1] = {}
262
+ end
263
+ ret
264
+ end.call(s2)
410
265
  else
411
266
  @current_pos = s0
412
267
  s0 = :failed
@@ -420,9 +275,9 @@ module Jkf::Parser
420
275
 
421
276
  def parse_ikkatsu
422
277
  s0 = @current_pos
423
- s1 = []
424
278
  s2 = parse_ikkatsu_line
425
279
  if s2 != :failed
280
+ s1 = []
426
281
  while s2 != :failed
427
282
  s1 << s2
428
283
  s2 = parse_ikkatsu_line
@@ -432,17 +287,17 @@ module Jkf::Parser
432
287
  end
433
288
  if s1 != :failed
434
289
  @reported_pos = s0
435
- s1 = -> (lines) {
290
+ s1 = -> (lines) do
436
291
  board = []
437
- 9.times { |i|
292
+ 9.times do |i|
438
293
  line = []
439
- 9.times { |j|
440
- line << lines[j][8-i]
441
- }
294
+ 9.times do |j|
295
+ line << lines[j][8 - i]
296
+ end
442
297
  board << line
443
- }
298
+ end
444
299
  { "preset" => "OTHER", "data" => { "board" => board } }
445
- }.call(s1)
300
+ end.call(s1)
446
301
  end
447
302
  s0 = s1
448
303
  s0
@@ -450,13 +305,11 @@ module Jkf::Parser
450
305
 
451
306
  def parse_ikkatsu_line
452
307
  s0 = @current_pos
453
- s1 = match_str("P")
454
- if s1 != :failed
455
- s2 = match_regexp(/^[1-9]/)
456
- if s2 != :failed
457
- s3 = []
308
+ if match_str("P") != :failed
309
+ if match_regexp(/^[1-9]/) != :failed
458
310
  s4 = parse_masu
459
311
  if s4 != :failed
312
+ s3 = []
460
313
  while s4 != :failed
461
314
  s3 << s4
462
315
  s4 = parse_masu
@@ -468,7 +321,7 @@ module Jkf::Parser
468
321
  s4 = parse_nl
469
322
  if s4 != :failed
470
323
  @reported_pos = s0
471
- s0 = s1 = s3
324
+ s0 = s3
472
325
  else
473
326
  @current_pos = s0
474
327
  s0 = :failed
@@ -495,7 +348,7 @@ module Jkf::Parser
495
348
  s2 = parse_piece
496
349
  if s2 != :failed
497
350
  @reported_pos = s0
498
- s0 = s1 = { "color" => s1, "kind" => s2 }
351
+ s0 = { "color" => s1, "kind" => s2 }
499
352
  else
500
353
  @current_pos = s0
501
354
  s0 = :failed
@@ -506,8 +359,7 @@ module Jkf::Parser
506
359
  end
507
360
  if s0 == :failed
508
361
  s0 = @current_pos
509
- s1 = match_str(" * ")
510
- if s1 != :failed
362
+ if match_str(" * ") != :failed
511
363
  @reported_pos = s0
512
364
  s1 = {}
513
365
  end
@@ -524,55 +376,18 @@ module Jkf::Parser
524
376
  s1 << s2
525
377
  s2 = parse_komabetsu_line
526
378
  end
527
- if s1 != :failed
528
- @reported_pos = s0
529
- s1 = -> (lines) {
530
- board = []
531
- hands = [
532
- {"FU"=>0,"KY"=>0,"KE"=>0,"GI"=>0,"KI"=>0,"KA"=>0,"HI"=>0},
533
- {"FU"=>0,"KY"=>0,"KE"=>0,"GI"=>0,"KI"=>0,"KA"=>0,"HI"=>0}
534
- ]
535
- all = {"FU"=>18,"KY"=>4,"KE"=>4,"GI"=>4,"KI"=>4,"KA"=>2,"HI"=>2}
536
- 9.times { |i|
537
- line = []
538
- 9.times { |j|
539
- line << {}
540
- }
541
- board << line
542
- }
543
-
544
- lines.each do |line|
545
- line["pieces"].each do |piece|
546
- if piece["xy"]["x"] == 0
547
- if piece["piece"] == "AL"
548
- hands[line["teban"]] = all
549
- return { "preset" => "OTHER", "data" => { "board" => board, "hands" => hands } }
550
- end
551
- obj = hands[line["teban"]]
552
- obj[piece["piece"]] += 1
553
- else
554
- board[piece["xy"]["x"]-1][piece["xy"]["y"]-1] = { "color" => line["teban"], "kind" => piece["piece"] }
555
- end
556
- all[piece["piece"]] -= 1 if piece["piece"] != "OU"
557
- end
558
- end
559
-
560
- { "preset" => "OTHER", "data" => { "board" => board, "hands" => hands } }
561
- }.call(s1)
562
- end
563
- s0 = s1
564
- s0
379
+ @reported_pos = s0
380
+ transform_komabetsu_lines(s1)
565
381
  end
566
382
 
567
383
  def parse_komabetsu_line
568
384
  s0 = @current_pos
569
- s1 = match_str("P")
570
- if s1 != :failed
385
+ if match_str("P") != :failed
571
386
  s2 = parse_teban
572
387
  if s2 != :failed
573
- s3 = []
574
388
  s4 = parse_xy_piece
575
389
  if s4 != :failed
390
+ s3 = []
576
391
  while s4 != :failed
577
392
  s3 << s4
578
393
  s4 = parse_xy_piece
@@ -581,10 +396,9 @@ module Jkf::Parser
581
396
  s3 = :failed
582
397
  end
583
398
  if s3 != :failed
584
- s4 = parse_nl
585
- if s4 != :failed
399
+ if parse_nl != :failed
586
400
  @reported_pos = s0
587
- s0 = s1 = { "teban" => s2, "pieces" => s3 }
401
+ s0 = { "teban" => s2, "pieces" => s3 }
588
402
  else
589
403
  @current_pos = s0
590
404
  s0 = :failed
@@ -614,24 +428,9 @@ module Jkf::Parser
614
428
  s2 << s3
615
429
  s3 = parse_move
616
430
  end
617
- if s2 != :failed
618
- s3 = []
619
- s4 = parse_comment
620
- while s4 != :failed
621
- s3 << s4
622
- s4 = parse_comment
623
- end
624
- if s3 != :failed
625
- @reported_pos = s0
626
- s0 = s1 = s2.unshift(s1)
627
- else
628
- @current_pos = s0
629
- s0 = :failed
630
- end
631
- else
632
- @current_pos = s0
633
- s0 = :failed
634
- end
431
+ parse_comments
432
+ @reported_pos = s0
433
+ s0 = s2.unshift(s1)
635
434
  else
636
435
  @current_pos = s0
637
436
  s0 = :failed
@@ -641,18 +440,9 @@ module Jkf::Parser
641
440
 
642
441
  def parse_firstboard
643
442
  s0 = @current_pos
644
- s1 = []
645
- s2 = parse_comment
646
- while s2 != :failed
647
- s1 << s2
648
- s2 = parse_comment
649
- end
650
- if s1 != :failed
651
- @reported_pos = s0
652
- s1 = s1.length > 0 ? { "comments" => s1 } : {}
653
- end
654
- s0 = s1
655
- s0
443
+ s1 = parse_comments
444
+ @reported_pos = s0
445
+ s1.empty? ? {} : { "comments" => s1 }
656
446
  end
657
447
 
658
448
  def parse_move
@@ -662,34 +452,19 @@ module Jkf::Parser
662
452
  if s1 != :failed
663
453
  s2 = parse_time
664
454
  s2 = nil if s2 == :failed
665
- if s2 != :failed
666
- s3 = []
667
- s4 = parse_comment
668
- while s4 != :failed
669
- s3 << s4
670
- s4 = parse_comment
671
- end
672
- if s3 != :failed
673
- @reported_pos = s0
674
- s0 = s1 = -> (move, time, comments) {
675
- ret = {}
676
- ret["comments"] = comments if comments.length > 0
677
- ret["time"] = time if time
678
- if move["special"]
679
- ret["special"] = move["special"]
680
- else
681
- ret["move"] = move
682
- end
683
- ret
684
- }.call(s1, s2, s3)
455
+ s3 = parse_comments
456
+ @reported_pos = s0
457
+ s0 = -> (move, time, comments) do
458
+ ret = {}
459
+ ret["comments"] = comments if !comments.empty?
460
+ ret["time"] = time if time
461
+ if move["special"]
462
+ ret["special"] = move["special"]
685
463
  else
686
- @current_pos = s0
687
- s0 = :failed
464
+ ret["move"] = move
688
465
  end
689
- else
690
- @current_pos = s0
691
- s0 = :failed
692
- end
466
+ ret
467
+ end.call(s1, s2, s3)
693
468
  else
694
469
  @current_pos = s0
695
470
  s0 = :failed
@@ -707,14 +482,13 @@ module Jkf::Parser
707
482
  if s3 != :failed
708
483
  s4 = parse_piece
709
484
  if s4 != :failed
710
- s5 = parse_nl
711
- if s5 != :failed
485
+ if parse_nl != :failed
712
486
  @reported_pos = s0
713
- s0 = s1 = -> (color, from, to, piece) {
487
+ s0 = -> (color, from, to, piece) do
714
488
  ret = { "color" => color, "to" => to, "piece" => piece }
715
489
  ret["from"] = from if from["x"] != 0
716
490
  ret
717
- }.call(s1, s2, s3, s4)
491
+ end.call(s1, s2, s3, s4)
718
492
  else
719
493
  @current_pos = s0
720
494
  s0 = :failed
@@ -742,9 +516,9 @@ module Jkf::Parser
742
516
  s0 = @current_pos
743
517
  s1 = match_str("%")
744
518
  if s1 != :failed
745
- s2 = []
746
519
  s3 = match_regexp(/^[\-+_A-Z]/)
747
520
  if s3 != :failed
521
+ s2 = []
748
522
  while s3 != :failed
749
523
  s2 << s3
750
524
  s3 = match_regexp(/^[\-+_A-Z]/)
@@ -753,10 +527,9 @@ module Jkf::Parser
753
527
  s2 = :failed
754
528
  end
755
529
  if s2 != :failed
756
- s3 = parse_nl
757
- if s3 != :failed
530
+ if parse_nl != :failed
758
531
  @reported_pos = s0
759
- s0 = s1 = { "special" => s2.join }
532
+ s0 = { "special" => s2.join }
760
533
  else
761
534
  @current_pos = s0
762
535
  s0 = :failed
@@ -794,53 +567,38 @@ module Jkf::Parser
794
567
 
795
568
  def parse_comment
796
569
  s0 = @current_pos
797
- s1 = match_str("'")
798
- if s1 != :failed
799
- s2 = []
800
- s3 = parse_nonl
801
- while s3 != :failed
802
- s2 << s3
803
- s3 = parse_nonl
804
- end
805
- if s2 != :failed
806
- s3 = parse_nl
807
- if s3 != :failed
808
- @reported_pos = s0
809
- s0 = s1 = s2.join
810
- else
811
- @current_pos = s0
812
- s0 = :failed
813
- end
570
+ if match_str("'") != :failed
571
+ s2 = parse_nonls
572
+ if parse_nl != :failed
573
+ @reported_pos = s0
574
+ s2.join
814
575
  else
815
576
  @current_pos = s0
816
- s0 = :failed
577
+ :failed
817
578
  end
818
579
  else
819
580
  @current_pos = s0
820
- s0 = :failed
581
+ :failed
821
582
  end
822
- s0
583
+ end
584
+
585
+ def parse_comments
586
+ stack = []
587
+ matched = parse_comment
588
+ while matched != :failed
589
+ stack << matched
590
+ matched = parse_comment
591
+ end
592
+ stack
823
593
  end
824
594
 
825
595
  def parse_time
826
596
  s0 = @current_pos
827
- s1 = match_str("T")
828
- if s1 != :failed
829
- s2 = []
830
- s3 = match_regexp(/^[0-9]/)
831
- while s3 != :failed
832
- s2 << s3
833
- s3 = match_regexp(/^[0-9]/)
834
- end
835
- if s2 != :failed
836
- s3 = parse_nl
837
- if s3 != :failed
838
- @reported_pos = s0
839
- s0 = s1 = { "now" => sec2time(s2.join.to_i) }
840
- else
841
- @current_pos = s0
842
- s0 = :failed
843
- end
597
+ if match_str("T") != :failed
598
+ s2 = match_digits
599
+ if parse_nl != :failed
600
+ @reported_pos = s0
601
+ s0 = { "now" => sec2time(s2.join.to_i) }
844
602
  else
845
603
  @current_pos = s0
846
604
  s0 = :failed
@@ -854,12 +612,12 @@ module Jkf::Parser
854
612
 
855
613
  def parse_xy
856
614
  s0 = @current_pos
857
- s1 = match_regexp(/^[0-9]/)
615
+ s1 = match_digit
858
616
  if s1 != :failed
859
- s2 = match_regexp(/^[0-9]/)
617
+ s2 = match_digit
860
618
  if s2 != :failed
861
619
  @reported_pos = s0
862
- s0 = s1 = { "x" => s1.to_i, "y" => s2.to_i }
620
+ s0 = { "x" => s1.to_i, "y" => s2.to_i }
863
621
  else
864
622
  @current_pos = s0
865
623
  s0 = :failed
@@ -878,7 +636,7 @@ module Jkf::Parser
878
636
  s2 = match_regexp(/^[A-Z]/)
879
637
  if s2 != :failed
880
638
  @reported_pos = s0
881
- s0 = s1 = s1 + s2
639
+ s0 = s1 + s2
882
640
  else
883
641
  @current_pos = s0
884
642
  s0 = :failed
@@ -897,7 +655,7 @@ module Jkf::Parser
897
655
  s2 = parse_piece
898
656
  if s2 != :failed
899
657
  @reported_pos = s0
900
- s0 = s1 = { "xy" => s1, "piece" => s2 }
658
+ s0 = { "xy" => s1, "piece" => s2 }
901
659
  else
902
660
  @current_pos = s0
903
661
  s0 = :failed
@@ -913,34 +671,19 @@ module Jkf::Parser
913
671
  s0 = @current_pos
914
672
  s1 = match_str("\r")
915
673
  s1 = nil if s1 == :failed
916
- if s1 != :failed
917
- s2 = match_str("\n")
918
- if s2 != :failed
919
- s0 = s1 = [s1, s2]
920
- else
921
- @current_pos = s0
922
- s0 = :failed
923
- end
674
+ s2 = match_str("\n")
675
+ if s2 != :failed
676
+ s0 = [s1, s2]
924
677
  else
925
678
  @current_pos = s0
926
679
  s0 = :failed
927
680
  end
928
681
  if s0 == :failed
929
682
  s0 = @current_pos
930
- s1 = []
931
- s2 = match_str(" ")
932
- while s2 != :failed
933
- s1 << s2
934
- s2 = match_str(" ")
935
- end
936
- if s1 != :failed
937
- s2 = match_str(",")
938
- if s2 != :failed
939
- s0 = s1 = [s1, s2]
940
- else
941
- @current_pos = s0
942
- s0 = :failed
943
- end
683
+ s1 = match_spaces
684
+ s2 = match_str(",")
685
+ if s2 != :failed
686
+ s0 = [s1, s2]
944
687
  else
945
688
  @current_pos = s0
946
689
  s0 = :failed
@@ -953,35 +696,97 @@ module Jkf::Parser
953
696
  match_regexp(/^[^\r\n]/)
954
697
  end
955
698
 
699
+ def parse_nonls
700
+ stack = []
701
+ matched = parse_nonl
702
+ while matched != :failed
703
+ stack << matched
704
+ matched = parse_nonl
705
+ end
706
+ stack
707
+ end
708
+
956
709
  protected
957
710
 
711
+ def transform_komabetsu_lines(lines)
712
+ board = generate_empty_board
713
+ hands = [
714
+ { "FU" => 0, "KY" => 0, "KE" => 0, "GI" => 0, "KI" => 0, "KA" => 0, "HI" => 0 },
715
+ { "FU" => 0, "KY" => 0, "KE" => 0, "GI" => 0, "KI" => 0, "KA" => 0, "HI" => 0 }
716
+ ]
717
+ all = { "FU" => 18, "KY" => 4, "KE" => 4, "GI" => 4, "KI" => 4, "KA" => 2, "HI" => 2 }
718
+
719
+ lines.each do |line|
720
+ line["pieces"].each do |piece|
721
+ xy = piece["xy"]
722
+ if xy["x"] == 0
723
+ if piece["piece"] == "AL"
724
+ hands[line["teban"]] = all
725
+ return { "preset" => "OTHER", "data" => { "board" => board, "hands" => hands } }
726
+ end
727
+ obj = hands[line["teban"]]
728
+ obj[piece["piece"]] += 1
729
+ else
730
+ board[xy["x"] - 1][xy["y"] - 1] = { "color" => line["teban"],
731
+ "kind" => piece["piece"] }
732
+ end
733
+ all[piece["piece"]] -= 1 if piece["piece"] != "OU"
734
+ end
735
+ end
736
+
737
+ { "preset" => "OTHER", "data" => { "board" => board, "hands" => hands } }
738
+ end
739
+
740
+ def generate_empty_board
741
+ board = []
742
+ 9.times do |_i|
743
+ line = []
744
+ 9.times do |_j|
745
+ line << {}
746
+ end
747
+ board << line
748
+ end
749
+ board
750
+ end
751
+
958
752
  def sec2time(sec)
959
753
  s = sec % 60
960
- m = (sec-s) / 60
754
+ m = (sec - s) / 60
961
755
  { "m" => m, "s" => s }
962
756
  end
963
757
 
964
758
  def get_hirate
965
759
  [
966
- [{"color" => 1,"kind" => "KY"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "KY"},],
967
- [{"color" => 1,"kind" => "KE"},{"color" => 1,"kind" => "KA"},{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{"color" => 0,"kind" => "HI"},{"color" => 0,"kind" => "KE"},],
968
- [{"color" => 1,"kind" => "GI"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "GI"},],
969
- [{"color" => 1,"kind" => "KI"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "KI"},],
970
- [{"color" => 1,"kind" => "OU"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "OU"},],
971
- [{"color" => 1,"kind" => "KI"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "KI"},],
972
- [{"color" => 1,"kind" => "GI"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "GI"},],
973
- [{"color" => 1,"kind" => "KE"},{"color" => 1,"kind" => "HI"},{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{"color" => 0,"kind" => "KA"},{"color" => 0,"kind" => "KE"},],
974
- [{"color" => 1,"kind" => "KY"},{ },{"color" => 1,"kind" => "FU"},{},{},{},{"color" => 0,"kind" => "FU"},{ },{"color" => 0,"kind" => "KY"},],
760
+ [{ "color" => 1, "kind" => "KY" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
761
+ { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "KY" }],
762
+ [{ "color" => 1, "kind" => "KE" }, { "color" => 1, "kind" => "KA" },
763
+ { "color" => 1, "kind" => "FU" }, {}, {}, {}, { "color" => 0, "kind" => "FU" },
764
+ { "color" => 0, "kind" => "HI" }, { "color" => 0, "kind" => "KE" }],
765
+ [{ "color" => 1, "kind" => "GI" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
766
+ { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "GI" }],
767
+ [{ "color" => 1, "kind" => "KI" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
768
+ { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "KI" }],
769
+ [{ "color" => 1, "kind" => "OU" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
770
+ { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "OU" }],
771
+ [{ "color" => 1, "kind" => "KI" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
772
+ { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "KI" }],
773
+ [{ "color" => 1, "kind" => "GI" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
774
+ { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "GI" }],
775
+ [{ "color" => 1, "kind" => "KE" }, { "color" => 1, "kind" => "HI" },
776
+ { "color" => 1, "kind" => "FU" }, {}, {}, {}, { "color" => 0, "kind" => "FU" },
777
+ { "color" => 0, "kind" => "KA" }, { "color" => 0, "kind" => "KE" }],
778
+ [{ "color" => 1, "kind" => "KY" }, {}, { "color" => 1, "kind" => "FU" }, {}, {}, {},
779
+ { "color" => 0, "kind" => "FU" }, {}, { "color" => 0, "kind" => "KY" }]
975
780
  ]
976
781
  end
977
782
 
978
783
  def normalize_header_key(key)
979
784
  {
980
- "EVENT" => "棋戦",
981
- "SITE" => "場所",
785
+ "EVENT" => "棋戦",
786
+ "SITE" => "場所",
982
787
  "START_TIME" => "開始日時",
983
- "END_TIME" => "終了日時",
984
- "TIME_LIMIT" => "持ち時間",
788
+ "END_TIME" => "終了日時",
789
+ "TIME_LIMIT" => "持ち時間"
985
790
  }[key] || key
986
791
  end
987
792
  end