jkf 0.4.0 → 0.4.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.
@@ -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