at_coder_friends 0.6.9 → 0.7.0
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.
- checksums.yaml +4 -4
- data/.gitattributes +1 -1
- data/.github/workflows/ruby.yml +7 -1
- data/.gitignore +3 -0
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +17 -4
- data/Gemfile.lock +37 -40
- data/README.md +10 -91
- data/at_coder_friends.gemspec +2 -2
- data/lib/at_coder_friends/cli.rb +13 -28
- data/lib/at_coder_friends/config_loader.rb +1 -2
- data/lib/at_coder_friends/generator/any_builtin.rb +22 -0
- data/lib/at_coder_friends/generator/base.rb +55 -6
- data/lib/at_coder_friends/generator/c_builtin.rb +22 -0
- data/lib/at_coder_friends/generator/cxx_builtin.rb +8 -239
- data/lib/at_coder_friends/generator/fragment.rb +106 -0
- data/lib/at_coder_friends/generator/main.rb +14 -6
- data/lib/at_coder_friends/generator/ruby_builtin.rb +13 -165
- data/lib/at_coder_friends/parser/binary.rb +9 -3
- data/lib/at_coder_friends/parser/constraints.rb +8 -8
- data/lib/at_coder_friends/parser/input_format.rb +5 -5
- data/lib/at_coder_friends/path_util.rb +1 -1
- data/lib/at_coder_friends/problem.rb +4 -4
- data/lib/at_coder_friends/scraping/session.rb +1 -1
- data/lib/at_coder_friends/scraping/tasks.rb +1 -1
- data/lib/at_coder_friends/version.rb +1 -1
- data/lib/at_coder_friends.rb +3 -0
- data/templates/any_builtin.md.erb +30 -0
- data/templates/any_builtin_fragments.yml +5 -0
- data/templates/c_builtin.c.erb +36 -0
- data/templates/c_builtin_fragments.yml +127 -0
- data/templates/csharp_sample.cs.erb +29 -0
- data/templates/csharp_sample_fragments.yml +159 -0
- data/templates/java_sample.java.erb +25 -0
- data/templates/java_sample_fragments.yml +98 -0
- data/templates/ruby_builtin_fragments.yml +93 -0
- metadata +22 -6
- data/.travis.yml +0 -16
- data/docs/CONFIGURATION.md +0 -421
@@ -2,256 +2,25 @@
|
|
2
2
|
|
3
3
|
module AtCoderFriends
|
4
4
|
module Generator
|
5
|
-
# generates C++ constants
|
6
|
-
module CxxBuiltinConstGen
|
7
|
-
def gen_const(c)
|
8
|
-
v = cnv_const_value(c.value)
|
9
|
-
if c.type == :max
|
10
|
-
"const int #{c.name.upcase}_MAX = #{v};"
|
11
|
-
else
|
12
|
-
"const int MOD = #{v};"
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def cnv_const_value(v)
|
17
|
-
v
|
18
|
-
.sub(/\b10\^/, '1e')
|
19
|
-
.sub(/\b2\^/, '1<<')
|
20
|
-
.gsub(',', "'")
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# generates C++ variable declarations
|
25
|
-
module CxxBuiltinDeclGen
|
26
|
-
TYPE_TBL = {
|
27
|
-
number: 'int',
|
28
|
-
decimal: 'double',
|
29
|
-
string: 'char',
|
30
|
-
char: 'char'
|
31
|
-
}.tap { |h| h.default = 'int' }
|
32
|
-
def gen_decl(inpdef)
|
33
|
-
if inpdef.components
|
34
|
-
inpdef.components.map { |cmp| gen_decl(cmp) }
|
35
|
-
else
|
36
|
-
case inpdef.container
|
37
|
-
when :single
|
38
|
-
gen_single_decl(inpdef)
|
39
|
-
when :harray
|
40
|
-
gen_harray_decl(inpdef)
|
41
|
-
when :varray
|
42
|
-
gen_varray_decl(inpdef)
|
43
|
-
when :matrix, :vmatrix, :hmatrix
|
44
|
-
gen_matrix_decl(inpdef)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def gen_single_decl(inpdef)
|
50
|
-
names, cols = inpdef.vars.transpose
|
51
|
-
if cols.uniq.size == 1 && cols[0] != :string
|
52
|
-
type = TYPE_TBL[cols[0]]
|
53
|
-
dcl = names.join(', ')
|
54
|
-
"#{type} #{dcl};"
|
55
|
-
else
|
56
|
-
inpdef.vars.map do |v, item|
|
57
|
-
type = TYPE_TBL[item]
|
58
|
-
dcl = v
|
59
|
-
dcl += "[#{v.upcase}_MAX + 1]" if item == :string
|
60
|
-
"#{type} #{dcl};"
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def gen_harray_decl(inpdef)
|
66
|
-
type = TYPE_TBL[inpdef.item]
|
67
|
-
v = inpdef.names[0]
|
68
|
-
sz = gen_arr_size(inpdef.size)[0]
|
69
|
-
case inpdef.item
|
70
|
-
when :number, :decimal
|
71
|
-
"#{type} #{v}[#{sz}];"
|
72
|
-
when :string
|
73
|
-
"#{type} #{v}[#{sz}][#{v.upcase}_MAX + 1];"
|
74
|
-
when :char
|
75
|
-
"#{type} #{v}[#{sz} + 1];"
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def gen_varray_decl(inpdef)
|
80
|
-
sz = gen_arr_size(inpdef.size)[0]
|
81
|
-
inpdef.vars.map do |v, item|
|
82
|
-
type = TYPE_TBL[item]
|
83
|
-
dcl = "#{v}[#{sz}]"
|
84
|
-
dcl += "[#{v.upcase}_MAX + 1]" if item == :string
|
85
|
-
"#{type} #{dcl};"
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def gen_matrix_decl(inpdef)
|
90
|
-
sz1, sz2 = gen_arr_size(inpdef.size)
|
91
|
-
inpdef.vars.map do |v, item|
|
92
|
-
type = TYPE_TBL[item]
|
93
|
-
dcl = "#{v}[#{sz1}]"
|
94
|
-
dcl += item == :char ? "[#{sz2} + 1]" : "[#{sz2}]"
|
95
|
-
dcl += "[#{v.upcase}_MAX + 1]" if item == :string
|
96
|
-
"#{type} #{dcl};"
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def gen_arr_size(szs)
|
101
|
-
szs.map { |sz| sz.gsub(/([a-z][a-z0-9_]*)/i, '\1_MAX').upcase }
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# generates C++ input source
|
106
|
-
module CxxBuiltinInputGen
|
107
|
-
SCANF_FMTS = [
|
108
|
-
'scanf("%<fmt>s", %<addr>s);',
|
109
|
-
'REP(i, %<sz1>s) scanf("%<fmt>s", %<addr>s);',
|
110
|
-
'REP(i, %<sz1>s) REP(j, %<sz2>s) scanf("%<fmt>s", %<addr>s);'
|
111
|
-
].freeze
|
112
|
-
SCANF_FMTS_CMB = {
|
113
|
-
varray_matrix:
|
114
|
-
[
|
115
|
-
<<~TEXT,
|
116
|
-
REP(i, %<sz1>s) {
|
117
|
-
scanf("%<fmt1>s", %<addr1>s);
|
118
|
-
scanf("%<fmt2>s", %<addr2>s);
|
119
|
-
}
|
120
|
-
TEXT
|
121
|
-
<<~TEXT
|
122
|
-
REP(i, %<sz1>s) {
|
123
|
-
scanf("%<fmt1>s", %<addr1>s);
|
124
|
-
REP(j, %<sz2>s[i]) scanf("%<fmt2>s", %<addr2>s);
|
125
|
-
}
|
126
|
-
TEXT
|
127
|
-
],
|
128
|
-
matrix_varray:
|
129
|
-
[
|
130
|
-
<<~TEXT,
|
131
|
-
REP(i, %<sz1>s) {
|
132
|
-
scanf("%<fmt1>s", %<addr1>s);
|
133
|
-
scanf("%<fmt2>s", %<addr2>s);
|
134
|
-
}
|
135
|
-
TEXT
|
136
|
-
<<~TEXT
|
137
|
-
REP(i, %<sz1>s) {
|
138
|
-
REP(j, %<sz2>s) scanf("%<fmt1>s", %<addr1>s);
|
139
|
-
scanf("%<fmt2>s", %<addr2>s);
|
140
|
-
}
|
141
|
-
TEXT
|
142
|
-
]
|
143
|
-
}.tap { |h| h.default = h[:varray_matrix] }
|
144
|
-
FMT_FMTS = {
|
145
|
-
number: '%d',
|
146
|
-
decimal: '%lf',
|
147
|
-
string: '%s',
|
148
|
-
char: '%s'
|
149
|
-
}.tap { |h| h.default = h[:number] }
|
150
|
-
SINGLE_ADDR_FMTS = {
|
151
|
-
number: '&%<v>s',
|
152
|
-
decimal: '&%<v>s',
|
153
|
-
string: '%<v>s'
|
154
|
-
}.tap { |h| h.default = h[:number] }
|
155
|
-
ARRAY_ADDR_FMTS = {
|
156
|
-
number: '%<v>s + i',
|
157
|
-
decimal: '%<v>s + i',
|
158
|
-
string: '%<v>s[i]',
|
159
|
-
char: '%<v>s'
|
160
|
-
}.tap { |h| h.default = h[:number] }
|
161
|
-
MATRIX_ADDR_FMTS = {
|
162
|
-
number: '&%<v>s[i][j]',
|
163
|
-
decimal: '&%<v>s[i][j]',
|
164
|
-
string: '%<v>s[i][j]',
|
165
|
-
char: '%<v>s[i]'
|
166
|
-
}.tap { |h| h.default = h[:number] }
|
167
|
-
ADDR_FMTS = {
|
168
|
-
single: SINGLE_ADDR_FMTS,
|
169
|
-
harray: ARRAY_ADDR_FMTS,
|
170
|
-
varray: ARRAY_ADDR_FMTS,
|
171
|
-
matrix: MATRIX_ADDR_FMTS,
|
172
|
-
vmatrix: MATRIX_ADDR_FMTS,
|
173
|
-
hmatrix: MATRIX_ADDR_FMTS
|
174
|
-
}.tap { |h| h.default = h[:single] }
|
175
|
-
|
176
|
-
def gen_input(inpdef)
|
177
|
-
if inpdef.components
|
178
|
-
gen_cmb_input(inpdef)
|
179
|
-
else
|
180
|
-
gen_plain_input(inpdef)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
def gen_plain_input(inpdef)
|
185
|
-
scanf = SCANF_FMTS[inpdef.size.size - (inpdef.item == :char ? 1 : 0)]
|
186
|
-
sz1, sz2 = inpdef.size
|
187
|
-
fmt, addr = scanf_params(inpdef)
|
188
|
-
format(scanf, sz1: sz1, sz2: sz2, fmt: fmt, addr: addr)
|
189
|
-
end
|
190
|
-
|
191
|
-
def gen_cmb_input(inpdef)
|
192
|
-
scanf = SCANF_FMTS_CMB.dig(
|
193
|
-
inpdef.container, inpdef.item == :char ? 0 : 1
|
194
|
-
)
|
195
|
-
sz1 = inpdef.size[0]
|
196
|
-
sz2 = inpdef.size[1].split('_')[0]
|
197
|
-
fmt1, addr1, fmt2, addr2 =
|
198
|
-
inpdef.components.map { |cmp| scanf_params(cmp) }.flatten
|
199
|
-
format(
|
200
|
-
scanf,
|
201
|
-
sz1: sz1, sz2: sz2,
|
202
|
-
fmt1: fmt1, addr1: addr1,
|
203
|
-
fmt2: fmt2, addr2: addr2
|
204
|
-
).split("\n")
|
205
|
-
end
|
206
|
-
|
207
|
-
def scanf_params(inpdef)
|
208
|
-
[scanf_fmt(inpdef), scanf_addr(inpdef)]
|
209
|
-
end
|
210
|
-
|
211
|
-
def scanf_fmt(inpdef)
|
212
|
-
inpdef.vars.map { |(_v, item)| FMT_FMTS[item] }.join
|
213
|
-
end
|
214
|
-
|
215
|
-
def scanf_addr(inpdef)
|
216
|
-
inpdef.vars.map do |(v, item)|
|
217
|
-
addr_fmt = ADDR_FMTS.dig(inpdef.container, item)
|
218
|
-
format(addr_fmt, v: v)
|
219
|
-
end.join(', ')
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
5
|
# generates C++ source from problem description
|
224
|
-
class CxxBuiltin <
|
225
|
-
|
226
|
-
|
227
|
-
include CxxBuiltinInputGen
|
228
|
-
|
229
|
-
ACF_HOME = File.realpath(File.join(__dir__, '..', '..', '..'))
|
230
|
-
TMPL_DIR = File.join(ACF_HOME, 'templates')
|
231
|
-
DEFAULT_TMPL = File.join(TMPL_DIR, 'cxx_builtin.cxx.erb')
|
232
|
-
ATTRS = Attributes.new(:cxx, DEFAULT_TMPL)
|
6
|
+
class CxxBuiltin < CBuiltin
|
7
|
+
TEMPLATE = File.join(TMPL_DIR, 'cxx_builtin.cxx.erb')
|
8
|
+
ATTRS = Attributes.new(:cxx, TEMPLATE, FRAGMENTS)
|
233
9
|
|
234
10
|
def attrs
|
235
11
|
ATTRS
|
236
12
|
end
|
237
13
|
|
14
|
+
def gen_const(c)
|
15
|
+
ConstFragment.new(c, fragments['cxx_constant']).generate
|
16
|
+
end
|
17
|
+
|
18
|
+
# deprecated, use ERB syntax
|
238
19
|
def render(src)
|
239
20
|
src = embed_lines(src, '/*** CONSTS ***/', gen_consts)
|
240
21
|
src = embed_lines(src, '/*** DCLS ***/', gen_decls)
|
241
22
|
embed_lines(src, '/*** INPUTS ***/', gen_inputs)
|
242
23
|
end
|
243
|
-
|
244
|
-
def gen_consts(constants = pbm.constants)
|
245
|
-
constants.map { |c| gen_const(c) }
|
246
|
-
end
|
247
|
-
|
248
|
-
def gen_decls(inpdefs = pbm.formats)
|
249
|
-
inpdefs.map { |inpdef| gen_decl(inpdef) }.flatten
|
250
|
-
end
|
251
|
-
|
252
|
-
def gen_inputs(inpdefs = pbm.formats)
|
253
|
-
inpdefs.map { |inpdef| gen_input(inpdef) }.flatten
|
254
|
-
end
|
255
24
|
end
|
256
25
|
end
|
257
26
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
module AtCoderFriends
|
6
|
+
module Generator
|
7
|
+
# base class for code fragment generator
|
8
|
+
class FragmentBase
|
9
|
+
attr_reader :templates
|
10
|
+
|
11
|
+
def initialize(obj, templates)
|
12
|
+
@obj = obj
|
13
|
+
@templates = templates
|
14
|
+
end
|
15
|
+
|
16
|
+
def render(*keys)
|
17
|
+
keys = keys.map(&:to_s)
|
18
|
+
template = templates.dig(*keys) || (raise AppError, "fragment key #{keys} not found")
|
19
|
+
|
20
|
+
return ERB.new(template, trim_mode: '-').result(binding) if template.is_a?(String)
|
21
|
+
|
22
|
+
if template.is_a?(Hash)
|
23
|
+
sub_key_props = template['__key'] || (raise AppError, "'__key' not found in fragment hash #{keys}")
|
24
|
+
sub_keys = sub_key_props.map { |k| send(k) }
|
25
|
+
return render(*keys, *sub_keys)
|
26
|
+
end
|
27
|
+
|
28
|
+
raise AppError, "can't render fragment #{keys}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# delegate method calls to obj
|
32
|
+
def method_missing(name, *args, &block)
|
33
|
+
if @obj.respond_to?(name)
|
34
|
+
@obj.send(name, *args, &block)
|
35
|
+
elsif templates.key?(name.to_s)
|
36
|
+
render(name)
|
37
|
+
else
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def respond_to_missing?(name, include_private = false)
|
43
|
+
@obj.respond_to?(name, include_private) ||
|
44
|
+
templates.key?(name.to_s) ||
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
@obj.to_s
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# base class for constant declaration generator
|
54
|
+
class ConstFragment < FragmentBase
|
55
|
+
def generate
|
56
|
+
render(type)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# base class for variable declaration generator
|
61
|
+
class InputFormatFragment < FragmentBase
|
62
|
+
def generate
|
63
|
+
render(:main)
|
64
|
+
end
|
65
|
+
|
66
|
+
def vs
|
67
|
+
names
|
68
|
+
end
|
69
|
+
|
70
|
+
def v
|
71
|
+
vs[0]
|
72
|
+
end
|
73
|
+
|
74
|
+
def sz1
|
75
|
+
size[0]
|
76
|
+
end
|
77
|
+
alias sz sz1
|
78
|
+
|
79
|
+
def sz2
|
80
|
+
size[1]
|
81
|
+
end
|
82
|
+
|
83
|
+
def delims
|
84
|
+
delim.chars
|
85
|
+
end
|
86
|
+
|
87
|
+
def vars
|
88
|
+
@vars ||= super.map do |v, item|
|
89
|
+
var = Problem::InputFormat.new(
|
90
|
+
container: container,
|
91
|
+
names: [v],
|
92
|
+
item: item,
|
93
|
+
size: size
|
94
|
+
)
|
95
|
+
self.class.new(var, templates)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def components
|
100
|
+
@components ||= super&.map do |cmp|
|
101
|
+
self.class.new(cmp, templates)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -18,26 +18,34 @@ module AtCoderFriends
|
|
18
18
|
gen_obj.process(pbm)
|
19
19
|
rescue StandardError => e
|
20
20
|
puts "an error occurred in generator:#{gen_name}."
|
21
|
-
puts e
|
21
|
+
puts e
|
22
22
|
puts e.backtrace
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
def load_obj(gen_name)
|
27
27
|
@cache[gen_name] ||= begin
|
28
|
-
|
28
|
+
cls_name = gen_name.split('_')[0]
|
29
|
+
gen_class = load_class(cls_name)
|
29
30
|
gen_cnf = config_for(gen_name)
|
30
31
|
gen_class.new(gen_cnf)
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
34
35
|
def load_class(gen_name)
|
35
|
-
|
36
|
-
|
37
|
-
end
|
36
|
+
snake_gen_name = to_snake(gen_name)
|
37
|
+
require "at_coder_friends/generator/#{snake_gen_name}" unless AtCoderFriends::Generator.const_defined?(gen_name)
|
38
38
|
AtCoderFriends::Generator.const_get(gen_name)
|
39
39
|
rescue LoadError
|
40
|
-
raise AppError,
|
40
|
+
raise AppError, <<~MSG
|
41
|
+
Error: Failed to load plugin.
|
42
|
+
The '#{gen_name}' plugin could not be found. To use this plugin, please install the required gem by following these steps:
|
43
|
+
|
44
|
+
1. Open a terminal or command prompt.
|
45
|
+
2. Run the following command:
|
46
|
+
gem install at_coder_friends-generator-#{snake_gen_name}
|
47
|
+
3. Once the above command completes, please run the program again.
|
48
|
+
MSG
|
41
49
|
end
|
42
50
|
|
43
51
|
def config_for(gen_name)
|
@@ -4,181 +4,29 @@ module AtCoderFriends
|
|
4
4
|
module Generator
|
5
5
|
# generates Ruby source from problem description
|
6
6
|
class RubyBuiltin < Base
|
7
|
+
include ConstFragmentMixin
|
8
|
+
include DeclFragmentMixin
|
9
|
+
|
7
10
|
ACF_HOME = File.realpath(File.join(__dir__, '..', '..', '..'))
|
8
11
|
TMPL_DIR = File.join(ACF_HOME, 'templates')
|
9
|
-
|
10
|
-
|
12
|
+
TEMPLATE = File.join(TMPL_DIR, 'ruby_builtin.rb.erb')
|
13
|
+
FRAGMENTS = File.realpath(File.join(TMPL_DIR, 'ruby_builtin_fragments.yml'))
|
14
|
+
ATTRS = Attributes.new(:rb, TEMPLATE, FRAGMENTS)
|
11
15
|
|
12
16
|
def attrs
|
13
17
|
ATTRS
|
14
18
|
end
|
15
19
|
|
16
|
-
def
|
17
|
-
|
18
|
-
embed_lines(src, '### DCLS ###', gen_decls)
|
19
|
-
end
|
20
|
-
|
21
|
-
def gen_consts(constants = pbm.constants)
|
22
|
-
constants
|
20
|
+
def gen_consts
|
21
|
+
pbm.constants
|
23
22
|
.select { |c| c.type == :mod }
|
24
|
-
.map { |c|
|
25
|
-
end
|
26
|
-
|
27
|
-
def gen_mod(c)
|
28
|
-
v = c.value.gsub('^', '**').gsub(',', '_')
|
29
|
-
"MOD = #{v}"
|
30
|
-
end
|
31
|
-
|
32
|
-
def gen_decls(inpdefs = pbm.formats)
|
33
|
-
inpdefs.map { |inpdef| gen_decl(inpdef) }.flatten
|
23
|
+
.map { |c| gen_const(c) }
|
34
24
|
end
|
35
25
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
when :harray
|
41
|
-
gen_harray_decl(inpdef)
|
42
|
-
when :varray
|
43
|
-
gen_varray_decl(inpdef)
|
44
|
-
when :matrix
|
45
|
-
gen_matrix_decl(inpdef)
|
46
|
-
when :varray_matrix, :matrix_varray
|
47
|
-
gen_cmb_decl(inpdef)
|
48
|
-
when :vmatrix
|
49
|
-
gen_vmatrix_decl(inpdef)
|
50
|
-
when :hmatrix
|
51
|
-
gen_hmatrix_decl(inpdef)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def gen_single_decl(inpdef)
|
56
|
-
names = inpdef.names
|
57
|
-
dcl = names.join(', ')
|
58
|
-
expr = gen_expr(inpdef, names.size > 1)
|
59
|
-
"#{dcl} = #{expr}"
|
60
|
-
end
|
61
|
-
|
62
|
-
def gen_harray_decl(inpdef)
|
63
|
-
v = inpdef.names[0]
|
64
|
-
dcl = "#{v}s"
|
65
|
-
expr = gen_expr(inpdef, true)
|
66
|
-
"#{dcl} = #{expr}"
|
67
|
-
end
|
68
|
-
|
69
|
-
def gen_varray_decl(inpdef)
|
70
|
-
if inpdef.names.size == 1
|
71
|
-
gen_varray_1_decl(inpdef)
|
72
|
-
else
|
73
|
-
gen_varray_n_decl(inpdef)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def gen_varray_1_decl(inpdef)
|
78
|
-
v = inpdef.names[0]
|
79
|
-
sz = inpdef.size[0]
|
80
|
-
dcl = "#{v}s"
|
81
|
-
expr = gen_expr(inpdef, false)
|
82
|
-
"#{dcl} = Array.new(#{sz}) { #{expr} }"
|
83
|
-
end
|
84
|
-
|
85
|
-
def gen_varray_n_decl(inpdef)
|
86
|
-
names = inpdef.names
|
87
|
-
sz = inpdef.size[0]
|
88
|
-
dcl = names.map { |v| "#{v}s[i]" }.join(', ')
|
89
|
-
expr = gen_expr(inpdef, true)
|
90
|
-
ret = []
|
91
|
-
ret += names.map { |v| "#{v}s = Array.new(#{sz})" }
|
92
|
-
ret << "#{sz}.times do |i|"
|
93
|
-
ret << " #{dcl} = #{expr}"
|
94
|
-
ret << 'end'
|
95
|
-
ret
|
96
|
-
end
|
97
|
-
|
98
|
-
def gen_matrix_decl(inpdef)
|
99
|
-
v = inpdef.names[0]
|
100
|
-
sz = inpdef.size[0]
|
101
|
-
decl = "#{v}ss"
|
102
|
-
expr = gen_expr(inpdef, true)
|
103
|
-
"#{decl} = Array.new(#{sz}) { #{expr} }"
|
104
|
-
end
|
105
|
-
|
106
|
-
def gen_cmb_decl(inpdef)
|
107
|
-
mx = inpdef.container == :varray_matrix ? -1 : 0
|
108
|
-
vs = inpdef.names.map { |v| "#{v}s" }
|
109
|
-
vs[mx] += 's'
|
110
|
-
sz = inpdef.size[0]
|
111
|
-
dcls = vs.map { |v| "#{v}[i]" }
|
112
|
-
dcls[mx] = "*#{dcls[mx]}" unless inpdef.item == :char
|
113
|
-
dcl = dcls.join(', ')
|
114
|
-
expr = gen_cmb_expr(inpdef)
|
115
|
-
ret = []
|
116
|
-
ret += vs.map { |v| "#{v} = Array.new(#{sz})" }
|
117
|
-
ret << "#{sz}.times do |i|"
|
118
|
-
ret << " #{dcl} = #{expr}"
|
119
|
-
ret << 'end'
|
120
|
-
ret
|
121
|
-
end
|
122
|
-
|
123
|
-
def gen_vmatrix_decl(inpdef)
|
124
|
-
names = inpdef.names
|
125
|
-
sz1, sz2 = inpdef.size
|
126
|
-
dcl = names.map { |v| "#{v}ss[i][j]" }.join(', ')
|
127
|
-
expr = gen_expr(inpdef, true)
|
128
|
-
ret = []
|
129
|
-
ret += names.map do |v|
|
130
|
-
"#{v}ss = Array.new(#{sz1}) { Array.new(#{sz2}) }"
|
131
|
-
end
|
132
|
-
ret << "#{sz1}.times do |i|"
|
133
|
-
ret << " #{sz2}.times do |j|"
|
134
|
-
ret << " #{dcl} = #{expr}"
|
135
|
-
ret << ' end'
|
136
|
-
ret << 'end'
|
137
|
-
ret
|
138
|
-
end
|
139
|
-
|
140
|
-
def gen_hmatrix_decl(inpdef)
|
141
|
-
names = inpdef.names
|
142
|
-
sz = inpdef.size[0]
|
143
|
-
dcl = names.map { |v| "#{v}ss[i]" }.join(', ')
|
144
|
-
expr = gen_expr(inpdef, true)
|
145
|
-
ret = []
|
146
|
-
ret += names.map { |v| "#{v}ss = Array.new(#{sz})" }
|
147
|
-
ret << "#{sz}.times do |i|"
|
148
|
-
ret << " #{dcl} = #{expr}.each_slice(#{names.size}).to_a.transpose"
|
149
|
-
ret << 'end'
|
150
|
-
ret
|
151
|
-
end
|
152
|
-
|
153
|
-
def gen_expr(inpdef, split)
|
154
|
-
read = gen_read(inpdef.delim)
|
155
|
-
case inpdef.item
|
156
|
-
when :number
|
157
|
-
split ? "#{read}.split.map(&:to_i)" : "#{read}.to_i"
|
158
|
-
when :decimal
|
159
|
-
split ? "#{read}.split.map(&:to_f)" : "#{read}.to_f"
|
160
|
-
when :string
|
161
|
-
split ? "#{read}.chomp.split" : "#{read}.chomp"
|
162
|
-
when :char
|
163
|
-
'gets.chomp'
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
def gen_cmb_expr(inpdef)
|
168
|
-
read = gen_read(inpdef.delim)
|
169
|
-
case inpdef.item
|
170
|
-
when :number
|
171
|
-
"#{read}.split.map(&:to_i)"
|
172
|
-
when :decimal
|
173
|
-
"#{read}.split.map(&:to_f)"
|
174
|
-
when :string, :char
|
175
|
-
"#{read}.chomp.split"
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
def gen_read(delim)
|
180
|
-
sub = delim.chars.map { |d| ".gsub('#{d}', ' ')" }.join
|
181
|
-
"gets#{sub}"
|
26
|
+
# deprecated, use ERB syntax
|
27
|
+
def render(src)
|
28
|
+
src = embed_lines(src, '### CONSTS ###', gen_consts)
|
29
|
+
embed_lines(src, '### DCLS ###', gen_decls)
|
182
30
|
end
|
183
31
|
end
|
184
32
|
end
|
@@ -8,9 +8,7 @@ module AtCoderFriends
|
|
8
8
|
|
9
9
|
def process(pbm)
|
10
10
|
vs = exp_values(pbm)
|
11
|
-
return unless vs
|
12
|
-
return if vs.any? { |v| v.include?("\n") }
|
13
|
-
return if vs.any? { |v| v =~ /\A[0-9\s]*\z/ }
|
11
|
+
return unless binary_values?(vs)
|
14
12
|
|
15
13
|
out_fmt = output_format(pbm)
|
16
14
|
re1, re2 = vs.map { |v| Regexp.escape(v) }
|
@@ -32,6 +30,14 @@ module AtCoderFriends
|
|
32
30
|
.uniq
|
33
31
|
end
|
34
32
|
|
33
|
+
def binary_values?(vs)
|
34
|
+
return false unless vs.size == 2
|
35
|
+
return false if vs.any? { |v| v.include?("\n") }
|
36
|
+
return false if vs.any? { |v| v =~ /\A[0-9\s]*\z/ }
|
37
|
+
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
35
41
|
def output_format(pbm)
|
36
42
|
pbm.sections[Problem::SECTION_OUT_FMT]&.content || ''
|
37
43
|
end
|
@@ -34,14 +34,14 @@ module AtCoderFriends
|
|
34
34
|
|
35
35
|
def parse(str)
|
36
36
|
str = normalize_content(str)
|
37
|
-
str
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
.
|
43
|
-
|
44
|
-
|
37
|
+
pats = str.scan(MAX_PATTERN).map(&:compact)
|
38
|
+
pairs = pats.each_with_object([]) do |(k, v), result|
|
39
|
+
value = normalize_value(v)
|
40
|
+
next unless value && !value.empty?
|
41
|
+
|
42
|
+
normalize_names(k).each { |name| result << [name, value] }
|
43
|
+
end
|
44
|
+
pairs.uniq.map { |k, v| Problem::Constant.new(k, :max, v) }
|
45
45
|
end
|
46
46
|
|
47
47
|
def normalize_content(s)
|
@@ -144,7 +144,7 @@ module AtCoderFriends
|
|
144
144
|
sz = str.split('_')
|
145
145
|
return sz if sz.size == 2
|
146
146
|
|
147
|
-
[str[0] || '_', str[1
|
147
|
+
[str[0] || '_', str[1..] || '_']
|
148
148
|
end
|
149
149
|
end
|
150
150
|
|
@@ -343,7 +343,7 @@ module AtCoderFriends
|
|
343
343
|
gen_pat2:
|
344
344
|
lambda { |vs|
|
345
345
|
m = vs[0]
|
346
|
-
ws = vs[1
|
346
|
+
ws = vs[1..].map { |v| v + RE_IX.source }.join('\s+')
|
347
347
|
/
|
348
348
|
\A
|
349
349
|
#{m}#{RE_IX}
|
@@ -367,7 +367,7 @@ module AtCoderFriends
|
|
367
367
|
lambda { |vs|
|
368
368
|
ws = [
|
369
369
|
vs[0] + RE_SZ.source,
|
370
|
-
*vs[1
|
370
|
+
*vs[1..]&.map { |v| v + RE_IX.source }
|
371
371
|
].join('\s+')
|
372
372
|
/\A#{ws}\z/
|
373
373
|
}
|
@@ -389,7 +389,7 @@ module AtCoderFriends
|
|
389
389
|
ws1 = vs.map { |v| v + RE_IX.source }.join('\s+')
|
390
390
|
ws2 = [
|
391
391
|
vs[0] + RE_SZ.source,
|
392
|
-
*vs[1
|
392
|
+
*vs[1..]&.map { |v| v + RE_IX.source }
|
393
393
|
].join('\s+')
|
394
394
|
/
|
395
395
|
\A
|
@@ -412,7 +412,7 @@ module AtCoderFriends
|
|
412
412
|
lambda { |vs|
|
413
413
|
ws = [
|
414
414
|
vs[0] + RE_SZ.source,
|
415
|
-
*vs[1
|
415
|
+
*vs[1..]&.map { |v| v + RE_IX.source }
|
416
416
|
].join('\s+')
|
417
417
|
/\A#{ws}\z/
|
418
418
|
}
|