jkf 0.5.0 → 0.5.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.
@@ -1,188 +1,188 @@
1
- module Jkf::Converter
2
- # Intersection of KIF and KI2
3
- module Kifuable
4
- protected
5
-
6
- def convert_initial(initial)
7
- result = convert_handicap(initial["preset"])
8
- footer = ""
9
-
10
- data = initial["data"]
11
- if data
12
- result += convert_teban(data, 1)
13
- if hands = data["hands"]
14
- result += convert_hands(hands, 1) if hands[1]
15
- footer += convert_hands(hands, 0) if hands[0]
16
- end
17
- footer += convert_teban(data, 0)
1
+ module Jkf
2
+ module Converter
3
+ # Intersection of KIF and KI2
4
+ module Kifuable
5
+ protected
6
+
7
+ def convert_initial(initial)
8
+ result = convert_handicap(initial['preset'])
9
+ footer = ''
10
+
11
+ data = initial['data']
12
+ if data
13
+ result += convert_teban(data, 1)
14
+ if (hands = data['hands'])
15
+ result += convert_hands(hands, 1) if hands[1]
16
+ footer += convert_hands(hands, 0) if hands[0]
17
+ end
18
+ footer += convert_teban(data, 0)
18
19
 
19
- result += convert_board(data["board"]) if data["board"]
20
+ result += convert_board(data['board']) if data['board']
21
+ end
22
+ result + footer
20
23
  end
21
- result + footer
22
- end
23
24
 
24
- def convert_handicap(preset)
25
- preset == "OTHER" ? "" : "手合割:#{preset2str(preset)}\n"
26
- end
25
+ def convert_handicap(preset)
26
+ preset == 'OTHER' ? '' : "手合割:#{preset2str(preset)}\n"
27
+ end
27
28
 
28
- def convert_teban(data, color)
29
- data["color"] == color ? "#{@players[color]}手番\n" : ""
30
- end
29
+ def convert_teban(data, color)
30
+ data['color'] == color ? "#{@players[color]}手番\n" : ''
31
+ end
31
32
 
32
- def convert_hands(hands, color)
33
- "#{@players[color]}手の持駒:" + convert_motigoma(hands[color])
34
- end
33
+ def convert_hands(hands, color)
34
+ "#{@players[color]}手の持駒:" + convert_motigoma(hands[color])
35
+ end
35
36
 
36
- def convert_board(board)
37
- result = " 9 8 7 6 5 4 3 2 1\n+---------------------------+\n"
38
- 9.times do |y|
39
- line = "|"
40
- 9.times do |x|
41
- line += convert_board_piece(board[8 - x][y])
37
+ def convert_board(board)
38
+ result = " 9 8 7 6 5 4 3 2 1\n+---------------------------+\n"
39
+ 9.times do |y|
40
+ line = '|'
41
+ 9.times do |x|
42
+ line += convert_board_piece(board[8 - x][y])
43
+ end
44
+ line += "|#{n2kan(y + 1)}\n"
45
+ result += line
42
46
  end
43
- line += "|#{n2kan(y + 1)}\n"
44
- result += line
47
+ result + "+---------------------------+\n"
45
48
  end
46
- result + "+---------------------------+\n"
47
- end
48
49
 
49
- def convert_comments(comments)
50
- comments.map { |comment| "*#{comment}\n" }.join
51
- end
50
+ def convert_comments(comments)
51
+ comments.map { |comment| "*#{comment}\n" }.join
52
+ end
52
53
 
53
- def convert_motigoma(pieces)
54
- pieces.to_a.reverse.map do |(piece, num)|
55
- if num > 0
56
- str = csa2kind(piece)
57
- if num > 1
58
- str += n2kan(num / 10) if num / 10 > 0
59
- num %= 10
60
- str += n2kan(num)
54
+ def convert_motigoma(pieces)
55
+ pieces.to_a.reverse.filter_map do |(piece, num)|
56
+ if num > 0
57
+ str = csa2kind(piece)
58
+ if num > 1
59
+ str += n2kan(num / 10) if num / 10 > 0
60
+ num %= 10
61
+ str += n2kan(num)
62
+ end
63
+ str
61
64
  end
62
- str
63
- end
64
- end.compact.join(" ") + " \n"
65
- end
65
+ end.join(' ') + " \n"
66
+ end
66
67
 
67
- def convert_board_piece(piece)
68
- result = ""
68
+ def convert_board_piece(piece)
69
+ result = ''
69
70
 
70
- if piece == {}
71
- result = ""
72
- else
73
- result += piece["color"] == 0 ? " " : "v"
74
- result += csa2kind(piece["kind"])
71
+ if piece == {}
72
+ result = ''
73
+ else
74
+ result += piece['color'] == 0 ? ' ' : 'v'
75
+ result += csa2kind(piece['kind'])
76
+ end
77
+
78
+ result
75
79
  end
76
80
 
77
- result
78
- end
81
+ def convert_special(special, index)
82
+ result = "まで#{index + 1}手"
83
+
84
+ if special == 'TORYO' || special.include?('ILLEGAL')
85
+ turn = @players[index % 2]
86
+ result += "で#{turn}手の"
87
+ result += { 'TORYO' => '勝ち',
88
+ 'ILLEGAL_ACTION' => '反則勝ち',
89
+ 'ILLEGAL_MOVE' => '反則負け' }[special]
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
79
101
 
80
- def convert_special(special, index)
81
- result = "まで#{index + 1}手"
82
-
83
- if special == "TORYO" || special =~ /ILLEGAL/
84
- turn = @players[index % 2]
85
- result += "で#{turn}手の"
86
- result += case special
87
- when "TORYO" then "勝ち"
88
- when "ILLEGAL_ACTION" then "反則勝ち"
89
- when "ILLEGAL_MOVE" then "反則負け"
90
- end
91
- else
92
- turn = @players[(index + 1) % 2]
93
- result += case special
94
- when "TIME_UP" then "で時間切れにより#{turn}手の勝ち"
95
- when "CHUDAN" then "で中断"
96
- when "JISHOGI" then "で持将棋"
97
- when "SENNICHITE" then "で千日手"
98
- when "TSUMI" then "で詰み"
99
- when "FUZUMI" then "で不詰"
100
- end
101
- end
102
-
103
- result + "\n"
104
- end
102
+ result + "\n"
103
+ end
105
104
 
106
- def convert_piece_with_pos(move)
107
- result = if move["to"]
108
- n2zen(move["to"]["x"]) + n2kan(move["to"]["y"])
109
- elsif move["same"]
110
- "同 "
111
- end
112
- result += csa2kind(move["piece"])
113
- result += "" if move["promote"]
114
- result
115
- end
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
+ end
111
+ result += csa2kind(move['piece'])
112
+ result += '' if move['promote']
113
+ result
114
+ end
116
115
 
117
- def convert_forks(forks, index)
118
- result = "\n"
119
- result = "変化:%4d手\n" % [index] # ki2の場合\nなし
120
- forks.each do |moves|
121
- result += convert_moves(moves, index)
116
+ def convert_forks(forks, index)
117
+ result = "\n"
118
+ result = "変化:%4d手\n" % [index] # ki2の場合\nなし
119
+ forks.each do |moves|
120
+ result += convert_moves(moves, index)
121
+ end
122
+ result
122
123
  end
123
- result
124
- end
125
124
 
126
- def reset!
127
- @forks = []
128
- @header2 = []
129
- end
125
+ def reset!
126
+ @forks = []
127
+ @header2 = []
128
+ end
130
129
 
131
- def setup_players!(jkf)
132
- players_flag = :sengo
133
- jkf["header"] && jkf["header"].keys.detect { |key| key =~ /[上下]手/ } && players_flag = :uwasimo
134
- @players = if players_flag == :uwasimo
135
- ["", ""]
136
- else
137
- ["", ""]
138
- end
139
- end
130
+ def setup_players!(jkf)
131
+ players_flag = :sengo
132
+ jkf['header']&.keys&.detect { |key| key =~ /[上下]手/ } && players_flag = :uwasimo
133
+ @players = if players_flag == :uwasimo
134
+ ['', '']
135
+ else
136
+ ['', '']
137
+ end
138
+ end
140
139
 
141
- def n2zen(n)
142
- "0123456789"[n]
143
- end
140
+ def n2zen(n)
141
+ '0123456789'[n]
142
+ end
144
143
 
145
- def n2kan(n)
146
- "〇一二三四五六七八九"[n]
147
- end
144
+ def n2kan(n)
145
+ '〇一二三四五六七八九'[n]
146
+ end
148
147
 
149
- def csa2kind(csa)
150
- {
151
- "FU" => "",
152
- "KY" => "",
153
- "KE" => "",
154
- "GI" => "",
155
- "KI" => "",
156
- "KA" => "",
157
- "HI" => "",
158
- "OU" => "",
159
- "TO" => "",
160
- "NY" => "成香",
161
- "NK" => "成桂",
162
- "NG" => "成銀",
163
- "UM" => "",
164
- "RY" => ""
165
- }[csa]
166
- end
148
+ def csa2kind(csa)
149
+ {
150
+ 'FU' => '',
151
+ 'KY' => '',
152
+ 'KE' => '',
153
+ 'GI' => '',
154
+ 'KI' => '',
155
+ 'KA' => '',
156
+ 'HI' => '',
157
+ 'OU' => '',
158
+ 'TO' => '',
159
+ 'NY' => '成香',
160
+ 'NK' => '成桂',
161
+ 'NG' => '成銀',
162
+ 'UM' => '',
163
+ 'RY' => ''
164
+ }[csa]
165
+ end
167
166
 
168
- def preset2str(preset)
169
- {
170
- "HIRATE" => "平手",
171
- "KY" => "香落ち",
172
- "KY_R" => "右香落ち",
173
- "KA" => "角落ち",
174
- "HI" => "飛車落ち",
175
- "HIKY" => "飛香落ち",
176
- "2" => "二枚落ち",
177
- "3" => "三枚落ち",
178
- "4" => "四枚落ち",
179
- "5" => "五枚落ち",
180
- "5_L" => "左五枚落ち",
181
- "6" => "六枚落ち",
182
- "8" => "八枚落ち",
183
- "10" => "十枚落ち",
184
- "OTHER" => "その他"
185
- }[preset]
167
+ def preset2str(preset)
168
+ {
169
+ 'HIRATE' => '平手',
170
+ 'KY' => '香落ち',
171
+ 'KY_R' => '右香落ち',
172
+ 'KA' => '角落ち',
173
+ 'HI' => '飛車落ち',
174
+ 'HIKY' => '飛香落ち',
175
+ '2' => '二枚落ち',
176
+ '3' => '三枚落ち',
177
+ '4' => '四枚落ち',
178
+ '5' => '五枚落ち',
179
+ '5_L' => '左五枚落ち',
180
+ '6' => '六枚落ち',
181
+ '8' => '八枚落ち',
182
+ '10' => '十枚落ち',
183
+ 'OTHER' => 'その他'
184
+ }[preset]
185
+ end
186
186
  end
187
187
  end
188
188
  end
data/lib/jkf/converter.rb CHANGED
@@ -1,14 +1,12 @@
1
1
  module Jkf
2
- # Define converter namespace
3
2
  module Converter
4
- # Convert error
5
3
  class ConvertError < StandardError; end
6
4
  end
7
5
  end
8
6
 
9
- require "json"
10
- require "jkf/converter/base"
11
- require "jkf/converter/kifuable"
12
- require "jkf/converter/kif"
13
- require "jkf/converter/ki2"
14
- require "jkf/converter/csa"
7
+ require 'json'
8
+ require_relative 'converter/base'
9
+ require_relative 'converter/kifuable'
10
+ require_relative 'converter/kif'
11
+ require_relative 'converter/ki2'
12
+ require_relative 'converter/csa'
@@ -1,118 +1,104 @@
1
- module Jkf::Parser
2
- # Base of Parser
3
- class Base
4
- # start parse
5
- #
6
- # @param [String] input
7
- #
8
- # @return [Hash] JKF
9
- def parse(input)
10
- @input = input.clone
11
-
12
- @current_pos = 0
13
- @reported_pos = 0
14
- @cached_pos = 0
15
- @cached_pos_details = { line: 1, column: 1, seenCR: false }
16
- @max_fail_pos = 0
17
- @max_fail_expected = []
18
- @silent_fails = 0
19
-
20
- @result = parse_root
21
-
22
- if success? && @current_pos == @input.size
23
- return @result
24
- else
25
- fail(type: "end", description: "end of input") if failed? && @current_pos < input.size
26
- raise ParseError
1
+ require 'strscan'
2
+
3
+ module Jkf
4
+ module Parser
5
+ # Base of Parser
6
+ class Base
7
+ # start parse
8
+ #
9
+ # @param [String] input
10
+ #
11
+ # @return [Hash] JKF
12
+ def parse(input)
13
+ @scanner = StringScanner.new(input.dup)
14
+ @reported_pos = 0
15
+ @max_fail_pos = 0
16
+
17
+ @result = parse_root
18
+
19
+ if success? && @scanner.eos?
20
+ @result
21
+ else
22
+ record_failure(type: 'end', description: 'end of input') if failed? && @scanner.pos < input.size
23
+ raise ParseError
24
+ end
27
25
  end
28
- end
29
26
 
30
- protected
27
+ protected
31
28
 
32
- def success?
33
- @result != :failed
34
- end
29
+ def success?
30
+ @result != :failed
31
+ end
35
32
 
36
- def failed?; !success?; end
37
-
38
- # match regexp
39
- def match_regexp(reg)
40
- ret = nil
41
- if matched = reg.match(@input[@current_pos])
42
- ret = matched.to_s
43
- @current_pos += ret.size
44
- else
45
- ret = :failed
46
- fail(type: "class", value: reg.inspect, description: reg.inspect) if @silent_fails == 0
33
+ def failed?; !success?; end
34
+
35
+ def match_regexp(reg)
36
+ matched = @scanner.scan(reg)
37
+ unless matched
38
+ record_failure(type: 'class', value: reg.inspect, description: reg.inspect)
39
+ return :failed
40
+ end
41
+ matched
47
42
  end
48
- ret
49
- end
50
43
 
51
- # match string
52
- def match_str(str)
53
- ret = nil
54
- if @input[@current_pos, str.size] == str
55
- ret = str
56
- @current_pos += str.size
57
- else
58
- ret = :failed
59
- fail(type: "literal", value: str, description: "\"#{str}\"") if @slient_fails == 0
44
+ def match_str(str)
45
+ matched = @scanner.scan(str)
46
+ unless matched
47
+ record_failure(type: 'literal', value: str, description: str.inspect)
48
+ return :failed
49
+ end
50
+ matched
60
51
  end
61
- ret
62
- end
63
52
 
64
- # match space
65
- def match_space
66
- match_str(" ")
67
- end
53
+ # match space
54
+ def match_space
55
+ match_str(' ')
56
+ end
68
57
 
69
- # match space one or more
70
- def match_spaces
71
- stack = []
72
- matched = match_space
73
- while matched != :failed
74
- stack << matched
58
+ # match space one or more
59
+ def match_spaces
60
+ stack = []
75
61
  matched = match_space
62
+ while matched != :failed
63
+ stack << matched
64
+ matched = match_space
65
+ end
66
+ stack
76
67
  end
77
- stack
78
- end
79
68
 
80
- # match digit
81
- def match_digit
82
- match_regexp(/^\d/)
83
- end
69
+ # match digit
70
+ def match_digit
71
+ match_regexp(/\d/)
72
+ end
84
73
 
85
- # match digits
86
- def match_digits
87
- stack = []
88
- matched = match_digit
89
- while matched != :failed
90
- stack << matched
74
+ # match digits
75
+ def match_digits
76
+ stack = []
91
77
  matched = match_digit
78
+ while matched != :failed
79
+ stack << matched
80
+ matched = match_digit
81
+ end
82
+ stack
92
83
  end
93
- stack
94
- end
95
84
 
96
- # match digit one ore more
97
- def match_digits!
98
- matched = match_digits
99
- if matched.empty?
100
- :failed
101
- else
102
- matched
85
+ # match digit one ore more
86
+ def match_digits!
87
+ matched = match_digits
88
+ if matched.empty?
89
+ :failed
90
+ else
91
+ matched
92
+ end
103
93
  end
104
- end
105
94
 
106
- # record failure
107
- def fail(expected)
108
- return if @current_pos < @max_fail_pos
95
+ def record_failure(_expected)
96
+ return if @scanner.pos < @max_fail_pos
109
97
 
110
- if @current_pos > @max_fail_pos
111
- @max_fail_pos = @current_pos
112
- @max_fail_expected = []
113
- end
98
+ return unless @scanner.pos > @max_fail_pos
114
99
 
115
- @max_fail_expected << expected
100
+ @max_fail_pos = @scanner.pos
101
+ end
116
102
  end
117
103
  end
118
104
  end