at_coder_friends 0.6.2 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
%>
|