at_coder_friends 0.6.2 → 0.6.3
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/CHANGELOG.md +20 -0
- data/Gemfile.lock +2 -2
- data/docs/CONFIGURATION.md +2 -4
- data/lib/at_coder_friends/generator/base.rb +41 -0
- data/lib/at_coder_friends/generator/cxx_builtin.rb +196 -143
- data/lib/at_coder_friends/generator/main.rb +7 -2
- data/lib/at_coder_friends/generator/ruby_builtin.rb +97 -51
- data/lib/at_coder_friends/parser/input_format.rb +387 -188
- data/lib/at_coder_friends/parser/input_type.rb +91 -0
- data/lib/at_coder_friends/parser/main.rb +1 -0
- data/lib/at_coder_friends/problem.rb +81 -6
- data/lib/at_coder_friends/version.rb +1 -1
- data/lib/at_coder_friends.rb +2 -0
- data/tasks/regression/check_const.rake +15 -14
- data/tasks/regression/check_diff.rake +2 -2
- data/tasks/regression/check_fmt.rake +18 -15
- data/tasks/regression/check_parse.rake +3 -4
- data/tasks/regression/list_handler.rb +46 -0
- data/tasks/regression/regression.rb +7 -41
- data/tasks/regression/report_handler.rb +20 -0
- data/tasks/regression/section_list.rake +1 -1
- data/templates/{cxx_builtin_interactive.cxx → cxx_builtin.cxx.erb} +33 -2
- data/templates/{ruby_builtin_interactive.rb → ruby_builtin.rb.erb} +17 -2
- metadata +8 -6
- data/templates/cxx_builtin_default.cxx +0 -26
- data/templates/ruby_builtin_default.rb +0 -7
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AtCoderFriends
|
4
|
+
module Parser
|
5
|
+
# parses input data types and updates input definitons
|
6
|
+
module InputType
|
7
|
+
module_function
|
8
|
+
|
9
|
+
NUMBER_PAT = /\A[+-]?[0-9]+\z/.freeze
|
10
|
+
TYPE_TBL = [
|
11
|
+
[:number, NUMBER_PAT],
|
12
|
+
[:decimal, /\A[+-]?[0-9]+(\.[0-9]+)?\z/]
|
13
|
+
].freeze
|
14
|
+
|
15
|
+
def process(pbm)
|
16
|
+
parse(pbm.formats_src, pbm.samples)
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse(inpdefs, smps)
|
20
|
+
lines = max_smp(smps)&.split("\n")
|
21
|
+
lines && match_smp(inpdefs, lines)
|
22
|
+
end
|
23
|
+
|
24
|
+
def max_smp(smps)
|
25
|
+
smps
|
26
|
+
.select { |smp| smp.ext == :in }
|
27
|
+
.max_by { |smp| smp.txt.size }
|
28
|
+
&.txt
|
29
|
+
end
|
30
|
+
|
31
|
+
def match_smp(inpdefs, lines)
|
32
|
+
vars = {}
|
33
|
+
inpdefs.each do |inpdef|
|
34
|
+
break unless (k = get_line_cnt(inpdef))
|
35
|
+
|
36
|
+
k, parsed = parse_line_cnt(k, vars)
|
37
|
+
rows = lines.shift(k).map { |line| line.split(/[#{inpdef.delim} ]/) }
|
38
|
+
break if rows.empty?
|
39
|
+
|
40
|
+
inpdef.container == :single &&
|
41
|
+
vars.merge!(inpdef.names.zip(rows[0]).to_h)
|
42
|
+
inpdef.cols = detect_cols_type(rows)
|
43
|
+
break unless parsed
|
44
|
+
end
|
45
|
+
inpdefs
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_line_cnt(inpdef)
|
49
|
+
case inpdef.size.size
|
50
|
+
when 0
|
51
|
+
1
|
52
|
+
when 1
|
53
|
+
inpdef.container == :harray ? 1 : inpdef.size[0]
|
54
|
+
when 2
|
55
|
+
inpdef.size[0]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_line_cnt(k, vars)
|
60
|
+
if k.is_a?(Integer)
|
61
|
+
[k, true]
|
62
|
+
elsif k =~ NUMBER_PAT
|
63
|
+
[k.to_i, true]
|
64
|
+
elsif vars[k] =~ NUMBER_PAT
|
65
|
+
[vars[k].to_i, true]
|
66
|
+
elsif vars[(k2 = k.gsub(/-1\z/, ''))] =~ NUMBER_PAT
|
67
|
+
[vars[k2].to_i - 1, true]
|
68
|
+
else
|
69
|
+
[1, false]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def detect_cols_type(rows)
|
74
|
+
cols = fill_transpose(rows).map(&:compact)
|
75
|
+
cols.map { |col| detect_col_type(col) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def fill_transpose(arr)
|
79
|
+
Array.new(arr.map(&:size).max) { |i| arr.map { |e| e[i] } }
|
80
|
+
end
|
81
|
+
|
82
|
+
def detect_col_type(arr)
|
83
|
+
ret = :string
|
84
|
+
TYPE_TBL.any? do |type, pat|
|
85
|
+
arr.all? { |v| v =~ pat } && ret = type
|
86
|
+
end
|
87
|
+
ret
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -18,13 +18,84 @@ module AtCoderFriends
|
|
18
18
|
|
19
19
|
SampleData = Struct.new(:no, :ext, :txt)
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
# holds information about input format
|
22
|
+
class InputFormat
|
23
|
+
ITEM_RANK = { number: 1, decimal: 2, string: 3 }.freeze
|
24
|
+
|
25
|
+
attr_reader :container, :names, :size, :delim
|
26
|
+
attr_accessor :cols
|
27
|
+
|
28
|
+
def initialize(
|
29
|
+
container: nil,
|
30
|
+
item: nil,
|
31
|
+
names: [],
|
32
|
+
size: [],
|
33
|
+
delim: '',
|
34
|
+
cols: []
|
35
|
+
)
|
36
|
+
@container = container
|
37
|
+
@item = item
|
38
|
+
@names = names
|
39
|
+
@size = size
|
40
|
+
@delim = delim
|
41
|
+
@cols = cols
|
24
42
|
end
|
25
43
|
|
26
44
|
def to_s
|
27
|
-
|
45
|
+
if container == :unknown
|
46
|
+
"#{container} #{item}"
|
47
|
+
else
|
48
|
+
"#{container} #{item}(#{cols}) #{names} #{size} #{delim}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def item
|
53
|
+
@item || cols.max_by { |k| ITEM_RANK[k] } || :number
|
54
|
+
end
|
55
|
+
|
56
|
+
def vars
|
57
|
+
tmp = @item && [@item] || cols
|
58
|
+
names.zip(tmp).map { |(name, col)| [name, col || :number] }
|
59
|
+
end
|
60
|
+
|
61
|
+
def components
|
62
|
+
@components ||=
|
63
|
+
case container
|
64
|
+
when :varray_matrix
|
65
|
+
varray_matrix_components
|
66
|
+
when :matrix_varray
|
67
|
+
matrix_varray_components
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def varray_matrix_components
|
72
|
+
[
|
73
|
+
self.class.new(
|
74
|
+
container: :varray,
|
75
|
+
names: names[0..-2], size: size[0..0],
|
76
|
+
delim: delim, cols: cols[0..-2]
|
77
|
+
),
|
78
|
+
self.class.new(
|
79
|
+
container: :matrix, item: @item,
|
80
|
+
names: names[-1..-1], size: size,
|
81
|
+
delim: delim, cols: cols[-1..-1] || []
|
82
|
+
)
|
83
|
+
]
|
84
|
+
end
|
85
|
+
|
86
|
+
def matrix_varray_components
|
87
|
+
[
|
88
|
+
self.class.new(
|
89
|
+
container: :matrix, item: @item,
|
90
|
+
names: names[0..0], size: size,
|
91
|
+
delim: delim, cols: cols[0..0]
|
92
|
+
),
|
93
|
+
self.class.new(
|
94
|
+
container: :varray,
|
95
|
+
names: names[1..-1], size: size[0..0],
|
96
|
+
delim: delim, cols: cols[1..-1] || []
|
97
|
+
)
|
98
|
+
]
|
28
99
|
end
|
29
100
|
end
|
30
101
|
|
@@ -35,14 +106,14 @@ module AtCoderFriends
|
|
35
106
|
SourceCode = Struct.new(:ext, :txt)
|
36
107
|
|
37
108
|
attr_reader :q, :samples, :sources, :options
|
38
|
-
attr_accessor :page, :sections, :
|
109
|
+
attr_accessor :page, :sections, :formats_src, :constants
|
39
110
|
|
40
111
|
def initialize(q, page = Mechanize::Page.new)
|
41
112
|
@q = q
|
42
113
|
@page = page
|
43
114
|
@sections = {}
|
44
115
|
@samples = []
|
45
|
-
@
|
116
|
+
@formats_src = []
|
46
117
|
@constants = []
|
47
118
|
@options = Options.new
|
48
119
|
@sources = []
|
@@ -57,6 +128,10 @@ module AtCoderFriends
|
|
57
128
|
@body_content ||= page.search('body')[0]&.content
|
58
129
|
end
|
59
130
|
|
131
|
+
def formats
|
132
|
+
@formats ||= formats_src.reject { |f| f.container == :unknown }
|
133
|
+
end
|
134
|
+
|
60
135
|
def add_smp(no, ext, txt)
|
61
136
|
@samples << SampleData.new(no, ext, txt)
|
62
137
|
end
|
data/lib/at_coder_friends.rb
CHANGED
@@ -20,11 +20,13 @@ require 'at_coder_friends/parser/introduction_wrapper'
|
|
20
20
|
require 'at_coder_friends/parser/sections'
|
21
21
|
require 'at_coder_friends/parser/sample_data'
|
22
22
|
require 'at_coder_friends/parser/input_format'
|
23
|
+
require 'at_coder_friends/parser/input_type'
|
23
24
|
require 'at_coder_friends/parser/constraints'
|
24
25
|
require 'at_coder_friends/parser/modulo'
|
25
26
|
require 'at_coder_friends/parser/interactive'
|
26
27
|
require 'at_coder_friends/parser/binary'
|
27
28
|
require 'at_coder_friends/parser/main'
|
29
|
+
require 'at_coder_friends/generator/base'
|
28
30
|
require 'at_coder_friends/generator/cxx_builtin'
|
29
31
|
require 'at_coder_friends/generator/ruby_builtin'
|
30
32
|
require 'at_coder_friends/generator/main'
|
@@ -23,23 +23,23 @@ module AtCoderFriends
|
|
23
23
|
}.freeze
|
24
24
|
|
25
25
|
def collect(tgt)
|
26
|
-
|
26
|
+
open_const_report('collect', tgt) do |f|
|
27
27
|
local_pbm_list.each do |contest, q, url|
|
28
28
|
page = agent.get(url)
|
29
29
|
body = page.body.force_encoding('utf-8')
|
30
30
|
ms = body.scan(CONST_PAT[tgt.to_sym])
|
31
31
|
ms.each do |m|
|
32
|
-
s = m[0].delete("\r\n
|
33
|
-
f.puts [contest, q, s].join("\t")
|
32
|
+
s = m[0].delete("\r\n")
|
33
|
+
f.puts [contest, q, tsv_escape(s)].join("\t")
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
39
|
def check_mod
|
40
|
-
|
40
|
+
open_const_report('check', 'mod') do |f|
|
41
41
|
local_pbm_list.each do |contest, q, url|
|
42
|
-
pbm =
|
42
|
+
pbm = local_scraping_agent(nil, contest).fetch_problem(q, url)
|
43
43
|
Parser::Sections.process(pbm)
|
44
44
|
Parser::Modulo.process(pbm)
|
45
45
|
pbm.constants.each do |cnst|
|
@@ -50,9 +50,9 @@ module AtCoderFriends
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def check_max
|
53
|
-
|
53
|
+
open_const_report('check', 'max') do |f|
|
54
54
|
local_pbm_list.each do |contest, q, url|
|
55
|
-
pbm =
|
55
|
+
pbm = local_scraping_agent(nil, contest).fetch_problem(q, url)
|
56
56
|
Parser::Sections.process(pbm)
|
57
57
|
Parser::Constraints.process(pbm)
|
58
58
|
pbm.constants.each do |cns|
|
@@ -70,10 +70,10 @@ module AtCoderFriends
|
|
70
70
|
def load_merge_list(tgt)
|
71
71
|
tbl = {}
|
72
72
|
%w[collect check]
|
73
|
-
.map { |act|
|
73
|
+
.map { |act| load_const_report(act, tgt) }
|
74
74
|
.each
|
75
|
-
.with_index(1) do |
|
76
|
-
|
75
|
+
.with_index(1) do |data, n|
|
76
|
+
data
|
77
77
|
.group_by { |contest, q, _| "#{contest}\t#{q}" }
|
78
78
|
.map { |key, grp| [key, grp.map { |row| row[2] }.join("\n")] }
|
79
79
|
.each do |key, txt|
|
@@ -85,18 +85,19 @@ module AtCoderFriends
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def save_merge_list(tgt, tbl)
|
88
|
-
|
88
|
+
open_const_report('merge', tgt) do |f|
|
89
89
|
tbl.sort.each do |k, h|
|
90
90
|
f.puts [k, h['v1'], h['v2']].join("\t")
|
91
91
|
end
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
-
def
|
96
|
-
|
95
|
+
def open_const_report(act, tgt)
|
96
|
+
open_report("#{act}_#{tgt}.txt") { |f| yield f }
|
97
97
|
end
|
98
98
|
|
99
|
-
def
|
99
|
+
def load_const_report(act, tgt)
|
100
|
+
file = report_path("#{act}_#{tgt}.txt")
|
100
101
|
Encoding.default_external = 'utf-8'
|
101
102
|
CSV.read(file, col_sep: "\t", headers: false)
|
102
103
|
end
|
@@ -12,11 +12,11 @@ module AtCoderFriends
|
|
12
12
|
rmdir_force(emit_dir)
|
13
13
|
|
14
14
|
local_pbm_list.each do |contest, q, url|
|
15
|
-
pbm =
|
15
|
+
pbm = local_scraping_agent(emit_dir, contest).fetch_problem(q, url)
|
16
16
|
pipeline(pbm)
|
17
17
|
end
|
18
18
|
|
19
|
-
diff_log =
|
19
|
+
diff_log = report_path('check_diff.txt')
|
20
20
|
system("diff -r --exclude=.git #{EMIT_ORG_DIR} #{emit_dir} > #{diff_log}")
|
21
21
|
end
|
22
22
|
end
|
@@ -8,28 +8,31 @@ module AtCoderFriends
|
|
8
8
|
module_function
|
9
9
|
|
10
10
|
def check_fmt
|
11
|
-
|
12
|
-
local_pbm_list.
|
13
|
-
|
14
|
-
Parser::Sections.process(pbm)
|
15
|
-
fmt = Parser::InputFormat.find_fmt(pbm)
|
16
|
-
next unless fmt && !fmt.empty?
|
11
|
+
open_report('check_fmt.txt') do |f|
|
12
|
+
local_pbm_list.each do |contest, q, url|
|
13
|
+
next unless (res = process_fmt(contest, q, url))
|
17
14
|
|
18
|
-
n_fmt = Parser::InputFormat.normalize_fmt(fmt).join("\n")
|
19
|
-
Parser::InputFormat.process(pbm)
|
20
|
-
res = pbm.formats.map(&:to_s).join("\n")
|
21
15
|
f.puts [
|
22
|
-
contest, q,
|
23
|
-
tsv_escape(fmt),
|
24
|
-
tsv_escape(n_fmt),
|
25
|
-
tsv_escape(res)
|
16
|
+
contest, q, *res.map { |s| tsv_escape(s) }
|
26
17
|
].join("\t")
|
27
18
|
end
|
28
19
|
end
|
29
20
|
end
|
30
21
|
|
31
|
-
def
|
32
|
-
|
22
|
+
def process_fmt(contest, q, url)
|
23
|
+
pbm = local_scraping_agent(nil, contest).fetch_problem(q, url)
|
24
|
+
Parser::Sections.process(pbm)
|
25
|
+
Parser::SampleData.process(pbm)
|
26
|
+
fmt1 = Parser::InputFormat.find_fmt(pbm)
|
27
|
+
return unless fmt1 && !fmt1.empty?
|
28
|
+
|
29
|
+
fmt2 = Parser::InputFormat.normalize_fmt(fmt1).join("\n")
|
30
|
+
Parser::InputFormat.process(pbm)
|
31
|
+
Parser::InputType.process(pbm)
|
32
|
+
inpdefs = pbm.formats_src
|
33
|
+
fmt3 = inpdefs.map(&:to_s).join("\n")
|
34
|
+
fmt4 = inpdefs.any? { |inpdef| inpdef.cols.empty? } ? '○' : ''
|
35
|
+
[fmt1, fmt2, fmt3, fmt4]
|
33
36
|
end
|
34
37
|
end
|
35
38
|
end
|
@@ -10,7 +10,7 @@ module AtCoderFriends
|
|
10
10
|
|
11
11
|
def check_parse
|
12
12
|
list = local_pbm_list.map do |contest, q, url|
|
13
|
-
pbm =
|
13
|
+
pbm = local_scraping_agent(nil, contest).fetch_problem(q, url)
|
14
14
|
Parser::Main.process(pbm)
|
15
15
|
flags = [
|
16
16
|
!fmt?(pbm),
|
@@ -24,7 +24,7 @@ module AtCoderFriends
|
|
24
24
|
|
25
25
|
def check_bin
|
26
26
|
list = local_pbm_list.map do |contest, q, url|
|
27
|
-
pbm =
|
27
|
+
pbm = local_scraping_agent(nil, contest).fetch_problem(q, url)
|
28
28
|
Parser::Main.process(pbm)
|
29
29
|
flags = [pbm.options.binary_values]
|
30
30
|
[contest, q, flags]
|
@@ -38,11 +38,10 @@ module AtCoderFriends
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def report(list, file)
|
41
|
-
|
41
|
+
open_report(file) do |f|
|
42
42
|
list
|
43
43
|
.select { |_, _, flags| flags.any? }
|
44
44
|
.map { |c, q, flags| [c, q, flags.map { |flg| f_to_s(flg) }] }
|
45
|
-
.sort
|
46
45
|
.each { |args| f.puts args.flatten.join("\t") }
|
47
46
|
end
|
48
47
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
require 'json'
|
6
|
+
require 'csv'
|
7
|
+
|
8
|
+
module AtCoderFriends
|
9
|
+
# tasks for regression
|
10
|
+
module Regression
|
11
|
+
module_function
|
12
|
+
|
13
|
+
CONTEST_LIST_URL = 'https://kenkoooo.com/atcoder/resources/contests.json'
|
14
|
+
ACF_HOME = File.expand_path(File.join(__dir__, '..', '..'))
|
15
|
+
REGRESSION_HOME = File.join(ACF_HOME, 'regression')
|
16
|
+
PAGES_DIR = File.join(REGRESSION_HOME, 'pages')
|
17
|
+
EMIT_ORG_DIR = File.join(REGRESSION_HOME, 'emit_org')
|
18
|
+
EMIT_DIR_FMT = File.join(REGRESSION_HOME, 'emit_%<now>s')
|
19
|
+
|
20
|
+
def contest_id_list
|
21
|
+
uri = URI.parse(CONTEST_LIST_URL)
|
22
|
+
json = Net::HTTP.get(uri)
|
23
|
+
contests = JSON.parse(json)
|
24
|
+
puts "Total #{contests.size} contests"
|
25
|
+
contests.map { |h| h['id'] }
|
26
|
+
end
|
27
|
+
|
28
|
+
def local_pbm_list
|
29
|
+
Dir.glob(PAGES_DIR + '/**/*.html').map do |pbm_path|
|
30
|
+
contest = File.basename(File.dirname(pbm_path))
|
31
|
+
q = File.basename(pbm_path, '.html')
|
32
|
+
url = "file://#{pbm_path}"
|
33
|
+
[contest, q, url]
|
34
|
+
end.sort # .take(10)
|
35
|
+
end
|
36
|
+
|
37
|
+
def pbm_list_from_file(file)
|
38
|
+
dat = File.join(REGRESSION_HOME, file)
|
39
|
+
CSV.read(dat, col_sep: "\t", headers: false).map do |contest, q|
|
40
|
+
pbm_path = File.join(PAGES_DIR, contest, "#{q}.html")
|
41
|
+
url = "file://#{pbm_path}"
|
42
|
+
[contest, q, url]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,56 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'net/http'
|
4
|
-
require 'uri'
|
5
|
-
require 'json'
|
6
|
-
require 'csv'
|
7
3
|
require 'mechanize'
|
8
4
|
require 'at_coder_friends'
|
5
|
+
require_relative 'list_handler'
|
6
|
+
require_relative 'report_handler'
|
9
7
|
|
10
8
|
module AtCoderFriends
|
11
9
|
# tasks for regression
|
12
10
|
module Regression
|
13
11
|
module_function
|
14
12
|
|
15
|
-
CONTEST_LIST_URL = 'https://kenkoooo.com/atcoder/resources/contests.json'
|
16
|
-
ACF_HOME = File.expand_path(File.join(__dir__, '..', '..'))
|
17
|
-
REGRESSION_HOME = File.join(ACF_HOME, 'regression')
|
18
|
-
PAGES_DIR = File.join(REGRESSION_HOME, 'pages')
|
19
|
-
EMIT_ORG_DIR = File.join(REGRESSION_HOME, 'emit_org')
|
20
|
-
EMIT_DIR_FMT = File.join(REGRESSION_HOME, 'emit_%<now>s')
|
21
|
-
|
22
|
-
def contest_id_list
|
23
|
-
uri = URI.parse(CONTEST_LIST_URL)
|
24
|
-
json = Net::HTTP.get(uri)
|
25
|
-
contests = JSON.parse(json)
|
26
|
-
puts "Total #{contests.size} contests"
|
27
|
-
contests.map { |h| h['id'] }
|
28
|
-
end
|
29
|
-
|
30
|
-
def local_pbm_list
|
31
|
-
Dir.glob(PAGES_DIR + '/**/*.html').map do |pbm_path|
|
32
|
-
contest = File.basename(File.dirname(pbm_path))
|
33
|
-
q = File.basename(pbm_path, '.html')
|
34
|
-
url = "file://#{pbm_path}"
|
35
|
-
[contest, q, url]
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def pbm_list_from_file(file)
|
40
|
-
dat = File.join(REGRESSION_HOME, file)
|
41
|
-
CSV.read(dat, col_sep: "\t", headers: false).map do |contest, q|
|
42
|
-
pbm_path = File.join(PAGES_DIR, contest, "#{q}.html")
|
43
|
-
url = "file://#{pbm_path}"
|
44
|
-
[contest, q, url]
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
13
|
def scraping_agent(root, contest)
|
49
14
|
root ||= REGRESSION_HOME
|
50
15
|
@ctx = Context.new({}, File.join(root, contest))
|
51
16
|
@ctx.scraping_agent
|
52
17
|
end
|
53
18
|
|
19
|
+
def local_scraping_agent(root, contest)
|
20
|
+
scraping_agent(root, contest)
|
21
|
+
.tap { |sa| sa.agent.pre_connect_hooks.clear }
|
22
|
+
end
|
23
|
+
|
54
24
|
def agent
|
55
25
|
@agent ||= Mechanize.new
|
56
26
|
end
|
@@ -64,9 +34,5 @@ module AtCoderFriends
|
|
64
34
|
def rmdir_force(dir)
|
65
35
|
FileUtils.rm_r(dir) if Dir.exist?(dir)
|
66
36
|
end
|
67
|
-
|
68
|
-
def log_path(file)
|
69
|
-
File.join(REGRESSION_HOME, file)
|
70
|
-
end
|
71
37
|
end
|
72
38
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AtCoderFriends
|
4
|
+
# tasks for regression
|
5
|
+
module Regression
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def open_report(file)
|
9
|
+
File.open(report_path(file), 'wb') { |f| yield f }
|
10
|
+
end
|
11
|
+
|
12
|
+
def report_path(file)
|
13
|
+
File.join(REGRESSION_HOME, file)
|
14
|
+
end
|
15
|
+
|
16
|
+
def tsv_escape(str)
|
17
|
+
'"' + str.gsub('"', '""').gsub("\t", ' ') + '"'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -26,7 +26,7 @@ module AtCoderFriends
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def save_section_list(list)
|
29
|
-
|
29
|
+
open_report('section_list.txt') do |f|
|
30
30
|
list.group_by(&:title).each do |k, vs|
|
31
31
|
f.puts [k, vs.size, vs[0].contest, vs[0].q].join("\t")
|
32
32
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
-
//
|
1
|
+
// <%= pbm.url %>
|
2
2
|
|
3
|
-
|
3
|
+
<%
|
4
|
+
if pbm.options.interactive
|
5
|
+
%>#include <cstdio>
|
4
6
|
#include <vector>
|
5
7
|
#include <string>
|
6
8
|
|
@@ -52,8 +54,37 @@ void input() {
|
|
52
54
|
#ifdef DEBUG
|
53
55
|
scanf("%s", source);
|
54
56
|
#endif
|
57
|
+
}<%
|
58
|
+
else
|
59
|
+
%>#include <cstdio>
|
60
|
+
|
61
|
+
using namespace std;
|
62
|
+
|
63
|
+
#define REP(i,n) for(int i=0; i<(int)(n); i++)
|
64
|
+
#define FOR(i,b,e) for(int i=(b); i<=(int)(e); i++)
|
65
|
+
|
66
|
+
/*** CONSTS ***/
|
67
|
+
|
68
|
+
/*** DCLS ***/
|
69
|
+
|
70
|
+
void solve() {
|
71
|
+
<%
|
72
|
+
if (vs = pbm.options.binary_values)
|
73
|
+
%> bool cond = false;
|
74
|
+
puts(cond ? "<%= vs[0] %>" : "<%= vs[1] %>");<%
|
75
|
+
else
|
76
|
+
%> int ans = 0;
|
77
|
+
printf("%d\n", ans);<%
|
78
|
+
end
|
79
|
+
%>
|
55
80
|
}
|
56
81
|
|
82
|
+
void input() {
|
83
|
+
/*** INPUTS ***/
|
84
|
+
}<%
|
85
|
+
end
|
86
|
+
%>
|
87
|
+
|
57
88
|
int main() {
|
58
89
|
input();
|
59
90
|
solve();
|
@@ -1,6 +1,8 @@
|
|
1
|
-
#
|
1
|
+
# <%= pbm.url %>
|
2
2
|
|
3
|
-
|
3
|
+
<%
|
4
|
+
if pbm.options.interactive
|
5
|
+
%>def query(*args)
|
4
6
|
puts "? #{args.join(' ')}"
|
5
7
|
STDOUT.flush
|
6
8
|
if $DEBUG
|
@@ -31,4 +33,17 @@ if $DEBUG
|
|
31
33
|
puts "query results:"
|
32
34
|
@responses.each { |res| puts res }
|
33
35
|
puts "----------------------------------------"
|
36
|
+
end<%
|
37
|
+
else
|
38
|
+
%>### CONSTS ###
|
39
|
+
|
40
|
+
### DCLS ###
|
41
|
+
|
42
|
+
<%
|
43
|
+
if (vs = pbm.options.binary_values)
|
44
|
+
%>puts cond ? '<%= vs[0] %>' : '<%= vs[1] %>'<%
|
45
|
+
else
|
46
|
+
%>puts ans<%
|
47
|
+
end
|
34
48
|
end
|
49
|
+
%>
|