jkf 0.5.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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