jkf 0.2.2

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,271 @@
1
+ module Jkf::Converter
2
+ class Kif
3
+ def convert(jkf)
4
+ hash = if jkf.is_a?(Hash)
5
+ jkf
6
+ else
7
+ JSON.parse(jkf)
8
+ end
9
+ @forks = []
10
+
11
+ result = ''
12
+ result += convert_header(hash['header']) if hash['header']
13
+ result += convert_initial(hash['initial']) if hash['initial']
14
+ result += "手数----指手---------消費時間--\n"
15
+ result += convert_moves(hash['moves'])
16
+ if @forks.size > 0
17
+ result += "\n"
18
+ result += @forks.join("\n")
19
+ end
20
+
21
+ result
22
+ end
23
+
24
+ protected
25
+
26
+ def convert_header(header)
27
+ header.map { |(key, value)| "#{key}:#{value}\n" }.join
28
+ end
29
+
30
+ def convert_initial(initial)
31
+ result = ''
32
+ result += "手合割:#{preset2str(initial["preset"])}\n" if initial["preset"] != "OTHER"
33
+
34
+ data = initial["data"]
35
+
36
+ if data
37
+ if data['color'] == 0
38
+ result += "先手番\n"
39
+ elsif data['color'] == 1
40
+ result += "後手番\n"
41
+ end
42
+
43
+ if data['hands']
44
+ if data['hands'][0]
45
+ result += '先手の持駒:'
46
+ result += convert_motigoma(data['hands'][0])
47
+ end
48
+ if data['hands'][1]
49
+ result += '後手の持駒:'
50
+ result += convert_motigoma(data['hands'][1])
51
+ end
52
+ end
53
+
54
+ if data['board']
55
+ result += " 9 8 7 6 5 4 3 2 1\n"
56
+ result += "+---------------------------+\n"
57
+ 9.times { |y|
58
+ line = "|"
59
+ 9.times { |x|
60
+ line += convert_board_piece(data['board'][8-x][y])
61
+ }
62
+ line += "|#{n2kan(y+1)}\n"
63
+ result += line
64
+ }
65
+ result += "+---------------------------+\n"
66
+ end
67
+ end
68
+
69
+ result
70
+ end
71
+
72
+ def convert_moves(moves, idx=0)
73
+ result = ''
74
+ moves.each_with_index { |move, i|
75
+ if move['special']
76
+ result_move = "%4d "%(i+idx)
77
+ result_move += ljust(special2kan(move['special']), 13)
78
+ result_move += convert_time(move['time']) if move['time']
79
+ result_move += "+" if move['forks']
80
+ result_move += "\n"
81
+ result += result_move
82
+ # first_board+speical分を引く(-2)
83
+ result += convert_special(move['special'], i-2+idx) if move['special']
84
+ else
85
+ if move['move']
86
+ result_move = "%4d "%(i+idx)
87
+ result_move += convert_move(move['move'])
88
+ result_move += convert_time(move['time']) if move['time']
89
+ result_move += "+" if move['forks']
90
+ result_move += "\n"
91
+ result += result_move
92
+ end
93
+
94
+ if move['comments']
95
+ result += convert_comments(move['comments'])
96
+ end
97
+
98
+ @forks.unshift convert_forks(move['forks'], i+idx) if move['forks']
99
+ end
100
+ }
101
+ result
102
+ end
103
+
104
+ def convert_move(move)
105
+ result = if move['to']
106
+ n2zen(move['to']['x']) + n2kan(move['to']['y'])
107
+ elsif move['same']
108
+ '同 '
109
+ else
110
+ raise "error??"
111
+ end
112
+ result += csa2kind(move['piece'])
113
+ result += '成' if move['promote']
114
+ result += if move['from']
115
+ "(#{move['from']['x']}#{move['from']['y']})"
116
+ else
117
+ '打'
118
+ end
119
+ result = ljust(result,13)
120
+ result
121
+ end
122
+
123
+ def convert_time(time)
124
+ "(%2d:%02d/%02d:%02d:%02d)"%[
125
+ time['now']['m'],
126
+ time['now']['s'],
127
+ time['total']['h'],
128
+ time['total']['m'],
129
+ time['total']['s'],
130
+ ]
131
+ end
132
+
133
+ def convert_special(special, index)
134
+ result = "まで#{index+1}手"
135
+
136
+ if special == 'TORYO' || special =~ /ILLEGAL/
137
+ turn = index % 2 == 0 ? '後' : '先'
138
+ result += "で#{turn}手の"
139
+ result += case special
140
+ when "TORYO" then "勝ち"
141
+ when "ILLEGAL_ACTION" then "反則勝ち"
142
+ when "ILLEGAL_MOVE" then "反則負け"
143
+ end
144
+ else
145
+ turn = index % 2 == 0 ? '先' : '後'
146
+ result += case special
147
+ when "TIME_UP" then "で時間切れにより#{turn}手の勝ち"
148
+ when "CHUDAN" then "で中断"
149
+ when "JISHOGI" then "で持将棋"
150
+ when "SENNICHITE" then "で千日手"
151
+ when "TSUMI" then "で詰み"
152
+ when "FUZUMI" then "で不詰"
153
+ end
154
+ end
155
+
156
+ result += "\n"
157
+ result
158
+ end
159
+
160
+ def convert_comments(comments)
161
+ comments.map { |comment| "*#{comment}\n" }.join
162
+ end
163
+
164
+ def convert_forks(forks, index)
165
+ result = "\n"
166
+ result = "変化:%4d手\n"%[index]
167
+ forks.each do |moves|
168
+ result += convert_moves(moves, index)
169
+ end
170
+ result
171
+ end
172
+
173
+ def convert_board_piece(piece)
174
+ result = ''
175
+
176
+ if piece == {}
177
+ result = ' ・'
178
+ else
179
+ result += piece['color'] == 0 ? ' ' : 'v'
180
+ result += csa2kind(piece['kind'])
181
+ end
182
+
183
+ result
184
+ end
185
+
186
+ def convert_motigoma(pieces)
187
+ pieces.map do |piece, num|
188
+ if num > 0
189
+ str = csa2kind(piece)
190
+ if num > 1
191
+ str += n2kan(num/10) if num / 10 > 0
192
+ num %= 10
193
+ str += n2kan(num)
194
+ end
195
+ str
196
+ else
197
+ nil
198
+ end
199
+ end.compact.join(' ') + " \n"
200
+ end
201
+
202
+ protected
203
+
204
+ def n2zen(n)
205
+ "0123456789"[n]
206
+ end
207
+
208
+ def n2kan(n)
209
+ "〇一二三四五六七八九"[n]
210
+ end
211
+
212
+ def csa2kind(csa)
213
+ {
214
+ "FU" => "歩",
215
+ "KY" => "香",
216
+ "KE" => "桂",
217
+ "GI" => "銀",
218
+ "KI" => "金",
219
+ "KA" => "角",
220
+ "HI" => "飛",
221
+ "OU" => "玉",
222
+ "TO" => "と",
223
+ "NY" => "成香",
224
+ "NK" => "成桂",
225
+ "NG" => "成銀",
226
+ "UM" => "馬",
227
+ "RY" => "龍",
228
+ }[csa]
229
+ end
230
+
231
+ def preset2str(preset)
232
+ {
233
+ "HIRATE" => "平手",
234
+ "KY" => "香落ち",
235
+ "KY_R" => "右香落ち",
236
+ "KA" => "角落ち",
237
+ "HI" => "飛車落ち",
238
+ "HIKY" => "飛香落ち",
239
+ "2" => "二枚落ち",
240
+ "3" => "三枚落ち",
241
+ "4" => "四枚落ち",
242
+ "5" => "五枚落ち",
243
+ "5_L" => "左五枚落ち",
244
+ "6" => "六枚落ち",
245
+ "8" => "八枚落ち",
246
+ "10" => "十枚落ち",
247
+ "OTHER" => "その他"
248
+ }[preset]
249
+ end
250
+
251
+ def special2kan(special)
252
+ case special
253
+ when "CHUDAN" then "中断"
254
+ when "TORYO" then "投了"
255
+ when "JISHOGI" then "持将棋"
256
+ when "SENNICHITE" then "千日手"
257
+ when "TSUMI" then "詰み"
258
+ when "FUZUMI" then "不詰"
259
+ when "TIME_UP" then "切れ負け"
260
+ when "ILLEGAL_ACTION" then "反則勝ち"
261
+ when "ILLEGAL_MOVE" then "反則負け"
262
+ end
263
+ end
264
+
265
+ def ljust(str, n)
266
+ len = 0
267
+ str.each_codepoint { |codepoint| len += codepoint > 255 ? 2 : 1 }
268
+ str + ' '*(n-len)
269
+ end
270
+ end
271
+ end
@@ -0,0 +1,9 @@
1
+ module Jkf
2
+ module Converter
3
+ class ConvertError < StandardError; end
4
+ end
5
+ end
6
+
7
+ require 'json'
8
+ require 'jkf/converter/ki2'
9
+ require 'jkf/converter/kif'
@@ -0,0 +1,61 @@
1
+ module Jkf::Parser
2
+ class Base
3
+ def parse(input)
4
+ @input = input.clone
5
+
6
+ @current_pos = 0
7
+ @reported_pos = 0
8
+ @cached_pos = 0
9
+ @cached_pos_details = { line: 1, column: 1, seenCR: false }
10
+ @max_fail_pos = 0
11
+ @max_fail_expected = []
12
+ @silent_fails = 0
13
+
14
+ @result = parse_root
15
+
16
+ if @result != :failded && @current_pos == @input.length
17
+ return @result
18
+ else
19
+ fail({ type: "end", description: "end of input" }) if @result != :failed && @current_pos < input.length
20
+ raise ParseError
21
+ end
22
+ end
23
+
24
+ protected
25
+
26
+ def match_regexp(reg)
27
+ ret = nil
28
+ if matched = reg.match(@input[@current_pos])
29
+ ret = matched.to_s
30
+ @current_pos += ret.size
31
+ else
32
+ ret = :failed
33
+ fail({ type: "class", value: reg.inspect, description: reg.inspect }) if @silent_fails == 0
34
+ end
35
+ ret
36
+ end
37
+
38
+ def match_str(str)
39
+ ret = nil
40
+ if @input[@current_pos, str.size] == str
41
+ ret = str
42
+ @current_pos += str.size
43
+ else
44
+ ret = :failed
45
+ fail({ type: "literal", value: str, description: "\"#{str}\"" }) if @slient_fails == 0
46
+ end
47
+ ret
48
+ end
49
+
50
+ def fail(expected)
51
+ return if @current_pos < @max_fail_pos
52
+
53
+ if @current_pos > @max_fail_pos
54
+ @max_fail_pos = @current_pos
55
+ @max_fail_expected = []
56
+ end
57
+
58
+ @max_fail_expected << expected
59
+ end
60
+ end
61
+ end