gettc 1.2.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.
- checksums.yaml +7 -0
- data/Rakefile +41 -0
- data/bin/gettc +63 -0
- data/core/lib/topcoder.rb +3 -0
- data/core/lib/topcoder/download.rb +89 -0
- data/core/lib/topcoder/generate.rb +131 -0
- data/core/lib/topcoder/parse.rb +231 -0
- data/core/lib/topcoder/print.rb +56 -0
- data/core/lib/topcoder/problem.rb +33 -0
- data/core/lib/topcoder/signature.rb +55 -0
- data/core/lib/topcoder/types.rb +62 -0
- data/core/test/topcoder/download_test.rb +29 -0
- data/core/test/topcoder/generate_test.rb +31 -0
- data/core/test/topcoder/parse_test.rb +104 -0
- data/core/test/topcoder/signature_test.rb +52 -0
- data/core/test/topcoder/types_test.rb +24 -0
- data/dist/config.yml +2 -0
- data/dist/include/cpp/engine.rb +90 -0
- data/dist/include/cpp/topcoder +212 -0
- data/dist/include/haskell/TopCoder.hs +82 -0
- data/dist/include/haskell/engine.rb +122 -0
- data/dist/include/java/TopCoder.jar +0 -0
- data/dist/include/java/engine.rb +207 -0
- data/dist/template/bin/runner.sh +113 -0
- data/dist/template/data/demo/{examples_d} +0 -0
- data/dist/template/data/sys/{systests_d} +0 -0
- data/dist/template/prob/images/{images_d} +0 -0
- data/dist/template/prob/{name}.html +8 -0
- data/dist/template/prob/{name}.md +1 -0
- data/dist/template/solve/cpp/Makefile +30 -0
- data/dist/template/solve/cpp/{name}.cpp +11 -0
- data/dist/template/solve/cpp/{name}Runner.cpp +26 -0
- data/dist/template/solve/cpp/{name}Test.cpp +8 -0
- data/dist/template/solve/haskell/Makefile +30 -0
- data/dist/template/solve/haskell/{name}.hs +7 -0
- data/dist/template/solve/haskell/{name}Runner.hs +27 -0
- data/dist/template/solve/haskell/{name}Test.hs +10 -0
- data/dist/template/solve/java/build.xml +78 -0
- data/dist/template/solve/java/{name}.java +9 -0
- data/dist/template/solve/java/{name}Runner.java +32 -0
- data/dist/template/solve/java/{name}Test.java +8 -0
- data/dist/template/util/check/Makefile +5 -0
- data/dist/template/util/check/check.cpp +26 -0
- metadata +121 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'topcoder/problem'
|
2
|
+
require 'bluecloth'
|
3
|
+
|
4
|
+
module TopCoder
|
5
|
+
class Problem
|
6
|
+
def to_md
|
7
|
+
out = "# [#{@name}](#{@url})\n"
|
8
|
+
out << "*#{@source}*\n\n"
|
9
|
+
|
10
|
+
out << "## Statement\n"
|
11
|
+
out << @statement << "\n\n"
|
12
|
+
|
13
|
+
if not @definitions.empty? then
|
14
|
+
out << "## Definitions\n"
|
15
|
+
@definitions.each do |k, v| out << "- *#{k}*: `#{v}`\n" end
|
16
|
+
out << "\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
if not @notes.empty? then
|
20
|
+
out << "## Notes\n"
|
21
|
+
@notes.each do |note| out << "- #{note}\n" end
|
22
|
+
out << "\n"
|
23
|
+
end
|
24
|
+
|
25
|
+
if not @constraints.empty? then
|
26
|
+
out << "## Constraints\n"
|
27
|
+
@constraints.each do |constraint|
|
28
|
+
out << "- #{constraint}\n"
|
29
|
+
end
|
30
|
+
out << "\n"
|
31
|
+
end
|
32
|
+
|
33
|
+
if not @examples.empty? then
|
34
|
+
out << "## Examples\n"
|
35
|
+
@examples.each_index do |i|
|
36
|
+
example = @examples[i]
|
37
|
+
out << "### Example #{i + 1}\n"
|
38
|
+
out << "#### Input\n<c>"
|
39
|
+
out << example.input.gsub("\n", '<br />')
|
40
|
+
out << "</c>\n"
|
41
|
+
out << "#### Output\n<c>"
|
42
|
+
out << example.output.gsub("\n", '<br />')
|
43
|
+
out << "</c>\n"
|
44
|
+
if not example.reason.empty? then
|
45
|
+
out << "#### Reason\n#{example.reason}\n\n"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
return out
|
50
|
+
end
|
51
|
+
def to_html
|
52
|
+
bc = BlueCloth.new to_md
|
53
|
+
return bc.to_html
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module TopCoder
|
2
|
+
class Case
|
3
|
+
attr_accessor :input, :output, :reason
|
4
|
+
def initialize
|
5
|
+
@input = ''
|
6
|
+
@output = ''
|
7
|
+
@reason = ''
|
8
|
+
end
|
9
|
+
end
|
10
|
+
class Image
|
11
|
+
attr_accessor :name, :content
|
12
|
+
def initialize
|
13
|
+
@name = ''
|
14
|
+
@content = ''
|
15
|
+
end
|
16
|
+
end
|
17
|
+
class Problem
|
18
|
+
attr_accessor :name, :url, :source, :statement, :definitions, :notes,
|
19
|
+
:constraints, :examples, :systests, :images
|
20
|
+
def initialize
|
21
|
+
@name = ''
|
22
|
+
@url = ''
|
23
|
+
@source = ''
|
24
|
+
@statement = ''
|
25
|
+
@definitions = { }
|
26
|
+
@notes = []
|
27
|
+
@constraints = []
|
28
|
+
@examples = []
|
29
|
+
@systests = []
|
30
|
+
@images = []
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'topcoder/types'
|
2
|
+
|
3
|
+
module TopCoder
|
4
|
+
class SignatureError < StandardError
|
5
|
+
end
|
6
|
+
class CannotParseSignature < SignatureError
|
7
|
+
attr_accessor :source
|
8
|
+
def initialize source, msg = 'Cannot parse signature'
|
9
|
+
@source = source
|
10
|
+
super "#{msg} (#{source}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
class InvalidVariableName < SignatureError
|
14
|
+
attr_accessor :name
|
15
|
+
def initialize name, msg = 'Invalid variable name'
|
16
|
+
@name = name
|
17
|
+
super "#{msg} (#{name})"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
class Signature
|
21
|
+
attr_accessor :type, :name
|
22
|
+
def initialize type, name
|
23
|
+
@type = type
|
24
|
+
@name = name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
def parse_signature str
|
28
|
+
str.strip!
|
29
|
+
parts = str.split
|
30
|
+
raise CannotParseSignature.new str if parts.size != 2
|
31
|
+
type = parse_type parts[0]
|
32
|
+
name = parts[1]
|
33
|
+
if name =~ /^[a-zA-Z_]\w*$/
|
34
|
+
return Signature.new type, name
|
35
|
+
else
|
36
|
+
raise InvalidVariableName.new name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
def parse_method_signature str
|
40
|
+
str.strip!
|
41
|
+
sigs = []
|
42
|
+
parts = str.split '('
|
43
|
+
raise CannotParseSignature.new str if parts.size != 2
|
44
|
+
sigs << parse_signature(parts[0])
|
45
|
+
|
46
|
+
str = parts[1]
|
47
|
+
raise CannotParseSignature.new str if str[-1] != ')'
|
48
|
+
str.chop!
|
49
|
+
|
50
|
+
parts = str.split ','
|
51
|
+
parts.each do |sig| sigs << parse_signature(sig) end
|
52
|
+
|
53
|
+
return sigs
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module TopCoder
|
4
|
+
class TypeError < StandardError
|
5
|
+
end
|
6
|
+
class UnrecognizedType < TypeError
|
7
|
+
attr_accessor :type
|
8
|
+
def initialize type = nil, msg = 'Not a valid TopCoder type'
|
9
|
+
@type = type
|
10
|
+
super "#{msg} (#{type})"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
class Type
|
14
|
+
def initialize is_object
|
15
|
+
@is_object = is_object
|
16
|
+
end
|
17
|
+
def obj?
|
18
|
+
return @is_object
|
19
|
+
end
|
20
|
+
end
|
21
|
+
TBoolean = Type.new false
|
22
|
+
TInt = Type.new false
|
23
|
+
TLong = Type.new false
|
24
|
+
TFloat = Type.new false
|
25
|
+
TDouble = Type.new false
|
26
|
+
TChar = Type.new false
|
27
|
+
TString = Type.new true
|
28
|
+
class TArray < Type
|
29
|
+
attr_accessor :subtype
|
30
|
+
def initialize subtype
|
31
|
+
raise UnrecognizedType.new subtype if not subtype.is_a? Type
|
32
|
+
@subtype = subtype
|
33
|
+
end
|
34
|
+
def == ary
|
35
|
+
return false if not ary.is_a? TArray
|
36
|
+
return @subtype == ary.subtype
|
37
|
+
end
|
38
|
+
def obj?
|
39
|
+
return true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
def parse_type str
|
43
|
+
return TArray.new parse_type str[0 .. -3] if str[-2 .. -1] == '[]'
|
44
|
+
case str
|
45
|
+
when 'boolean'
|
46
|
+
return TBoolean
|
47
|
+
when 'int'
|
48
|
+
return TInt
|
49
|
+
when 'long'
|
50
|
+
return TLong
|
51
|
+
when 'float'
|
52
|
+
return TFloat
|
53
|
+
when 'double'
|
54
|
+
return TDouble
|
55
|
+
when 'char'
|
56
|
+
return TChar
|
57
|
+
when 'String'
|
58
|
+
return TString
|
59
|
+
end
|
60
|
+
raise UnrecognizedType.new str
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'topcoder/download'
|
3
|
+
include TopCoder
|
4
|
+
|
5
|
+
class DownloadTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@account = Account.new 'gettc', 'algorithm'
|
8
|
+
end
|
9
|
+
def test_wrong_account
|
10
|
+
assert_raises LoginFailed do
|
11
|
+
Downloader.new Account.new 'username', 'password'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
def test_wrong_id
|
15
|
+
assert_raises IDNotAvailable do
|
16
|
+
(Downloader.new @account).download_problem 1000000
|
17
|
+
end
|
18
|
+
end
|
19
|
+
def test_download_ok
|
20
|
+
ids = [10297, 10324, 10329, 10330, 10505, 10685, 10686, 10690, 11264,
|
21
|
+
11266, 11303, 11315, 11322, 11350, 11357, 11419, 8763, 8819, 9995]
|
22
|
+
downloader = Downloader.new @account
|
23
|
+
3.times do
|
24
|
+
id = ids[rand ids.size]
|
25
|
+
html = downloader.download_problem id
|
26
|
+
assert_match '<h3>Problem Statement</h3>', html
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
require 'topcoder/generate'
|
6
|
+
include TopCoder
|
7
|
+
|
8
|
+
class GenerateTest < Test::Unit::TestCase
|
9
|
+
def setup
|
10
|
+
@source_d = File.join File.dirname(__FILE__), '../../../dist/template'
|
11
|
+
@target_d = File.join Dir.tmpdir, 'gettc'
|
12
|
+
FileUtils.mkdir @target_d if not File.directory? @target_d
|
13
|
+
@generator = Generator.new @source_d, @target_d
|
14
|
+
end
|
15
|
+
def test_initialize
|
16
|
+
assert_raise SourceDirNotExist do
|
17
|
+
Generator.new 'this_directory_must_not_exist', @target_d
|
18
|
+
end
|
19
|
+
assert_raise TargetDirNotExist do
|
20
|
+
Generator.new @source_d, 'this_directory_must_not_exist'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
def test_prob_dir_exists
|
24
|
+
prob = Problem.new
|
25
|
+
prob.name = 'JustATest'
|
26
|
+
prob_d = File.join @target_d, prob.name
|
27
|
+
FileUtils.mkdir prob_d if not File.exists? prob_d
|
28
|
+
assert_raise ProblemDirExists do @generator.generate prob end
|
29
|
+
FileUtils.rmdir prob_d
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'topcoder/parse'
|
3
|
+
include TopCoder
|
4
|
+
|
5
|
+
class ParseTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
downloader = Downloader.new Account.new 'gettc', 'algorithm'
|
8
|
+
@parser = Parser.new downloader
|
9
|
+
@datadir = File.join File.dirname(__FILE__), '../../files/stats'
|
10
|
+
end
|
11
|
+
def get_problem_raw prob
|
12
|
+
return File.read File.join @datadir, prob + '.htm'
|
13
|
+
end
|
14
|
+
def test_indexes
|
15
|
+
assert_equal [0, 3], @parser.indexes('abcde', 'bc')
|
16
|
+
assert_equal nil, @parser.indexes('abcde', 'f')
|
17
|
+
end
|
18
|
+
def test_filter
|
19
|
+
assert_equal 'Lorem Ipsum', @parser.filter('<xml> Lorem Ipsum </xml> ')
|
20
|
+
assert_equal '2^(3)', @parser.filter('2<sup>3</sup>')
|
21
|
+
assert_equal '*hi*', @parser.filter(' <b>hi</b>')
|
22
|
+
html = <<-END
|
23
|
+
<img src=
|
24
|
+
"http://www.topcoder.com/contest/problem/CirclesCountry/case1.gif">
|
25
|
+
END
|
26
|
+
assert_equal '', @parser.filter(html)
|
27
|
+
end
|
28
|
+
def test_PageNumbers
|
29
|
+
html = get_problem_raw 'PageNumbers'
|
30
|
+
prob = @parser.parse html
|
31
|
+
assert_equal 'PageNumbers', prob.name
|
32
|
+
assert_equal 5, prob.definitions.size
|
33
|
+
assert_equal 1, prob.notes.size
|
34
|
+
assert_equal 1, prob.constraints.size
|
35
|
+
assert_equal 5, prob.examples.size
|
36
|
+
assert_equal 118, prob.systests.size
|
37
|
+
assert_equal 0, prob.images.size
|
38
|
+
end
|
39
|
+
def test_CirclesCountry
|
40
|
+
html = get_problem_raw 'CirclesCountry'
|
41
|
+
prob = @parser.parse html
|
42
|
+
assert_equal 'CirclesCountry', prob.name
|
43
|
+
assert_equal 5, prob.definitions.size
|
44
|
+
assert_equal 0, prob.notes.size
|
45
|
+
assert_equal 7, prob.constraints.size
|
46
|
+
assert_equal 5, prob.examples.size
|
47
|
+
assert_equal 228, prob.systests.size
|
48
|
+
assert_equal 4, prob.images.size
|
49
|
+
end
|
50
|
+
def test_TheTournamentDivOne
|
51
|
+
html = get_problem_raw 'TheTournamentDivOne'
|
52
|
+
prob = @parser.parse html
|
53
|
+
assert_equal 'TheTournamentDivOne', prob.name
|
54
|
+
assert_equal 5, prob.definitions.size
|
55
|
+
assert_equal 0, prob.notes.size
|
56
|
+
assert_equal 4, prob.constraints.size
|
57
|
+
assert_equal 4, prob.examples.size
|
58
|
+
assert_equal 0, prob.systests.size
|
59
|
+
assert_equal 0, prob.images.size
|
60
|
+
end
|
61
|
+
def test_FunnyGames
|
62
|
+
html = get_problem_raw 'FunnyGames'
|
63
|
+
prob = @parser.parse html
|
64
|
+
assert_equal 'FunnyGames', prob.name
|
65
|
+
assert_equal 5, prob.definitions.size
|
66
|
+
assert_equal 0, prob.notes.size
|
67
|
+
assert_equal 6, prob.constraints.size
|
68
|
+
assert_equal 5, prob.examples.size
|
69
|
+
assert_equal 0, prob.systests.size
|
70
|
+
assert_equal 0, prob.images.size
|
71
|
+
end
|
72
|
+
def test_BuildingRoads
|
73
|
+
html = get_problem_raw 'BuildingRoads'
|
74
|
+
prob = @parser.parse html
|
75
|
+
assert_equal 'BuildingRoads', prob.name
|
76
|
+
assert_equal 5, prob.definitions.size
|
77
|
+
assert_equal 2, prob.notes.size
|
78
|
+
assert_equal 10, prob.constraints.size
|
79
|
+
assert_equal 5, prob.examples.size
|
80
|
+
assert_equal 0, prob.systests.size
|
81
|
+
assert_equal 2, prob.images.size
|
82
|
+
end
|
83
|
+
def test_Acronyms
|
84
|
+
html = get_problem_raw 'Acronyms'
|
85
|
+
prob = @parser.parse html
|
86
|
+
assert_equal 'Acronyms', prob.name
|
87
|
+
assert_equal 5, prob.definitions.size
|
88
|
+
assert_equal 1, prob.notes.size
|
89
|
+
assert_equal 8, prob.constraints.size
|
90
|
+
assert_equal 8, prob.examples.size
|
91
|
+
assert_equal 39, prob.systests.size
|
92
|
+
assert_equal 0, prob.images.size
|
93
|
+
end
|
94
|
+
def test_BackyardTrees
|
95
|
+
html = get_problem_raw 'BackyardTrees'
|
96
|
+
prob = @parser.parse html
|
97
|
+
assert_equal 'BackyardTrees', prob.name
|
98
|
+
assert_equal 5, prob.definitions.size
|
99
|
+
assert_equal 0, prob.notes.size
|
100
|
+
assert_equal 4, prob.constraints.size
|
101
|
+
assert_equal 6, prob.examples.size
|
102
|
+
assert_equal 2, prob.images.size
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'topcoder/signature'
|
3
|
+
include TopCoder
|
4
|
+
|
5
|
+
class SignatureTest < Test::Unit::TestCase
|
6
|
+
def test_parse_signature
|
7
|
+
assert_raise CannotParseSignature do
|
8
|
+
parse_signature 'invalid_signature'
|
9
|
+
end
|
10
|
+
assert_raise UnrecognizedType do
|
11
|
+
parse_signature 'strange_type name'
|
12
|
+
end
|
13
|
+
assert_raise InvalidVariableName do
|
14
|
+
parse_signature 'int not&ok&name'
|
15
|
+
end
|
16
|
+
assert_raise InvalidVariableName do parse_signature 'int 0zero' end
|
17
|
+
sig = parse_signature 'String[] a_valid_nam3'
|
18
|
+
assert_equal TArray.new(TString), sig.type
|
19
|
+
assert_equal 'a_valid_nam3', sig.name
|
20
|
+
end
|
21
|
+
def test_parse_method_signature
|
22
|
+
assert_raise CannotParseSignature do
|
23
|
+
parse_method_signature 'there are no brackets'
|
24
|
+
end
|
25
|
+
assert_raise CannotParseSignature do
|
26
|
+
parse_method_signature 'int main(int main())'
|
27
|
+
end
|
28
|
+
assert_raise CannotParseSignature do
|
29
|
+
parse_method_signature 'int main(oops forget to close bracket'
|
30
|
+
end
|
31
|
+
method = ' int leastBorders(String[] X , int[] Y, double[] R,'
|
32
|
+
method += ' char my_x1, long y1 , float x2, int[][] y2) '
|
33
|
+
sigs = parse_method_signature method
|
34
|
+
assert_equal 8, sigs.size
|
35
|
+
assert_equal TInt, sigs[0].type
|
36
|
+
assert_equal 'leastBorders', sigs[0].name
|
37
|
+
assert_equal TArray.new(TString), sigs[1].type
|
38
|
+
assert_equal 'X', sigs[1].name
|
39
|
+
assert_equal TArray.new(TInt), sigs[2].type
|
40
|
+
assert_equal 'Y', sigs[2].name
|
41
|
+
assert_equal TArray.new(TDouble), sigs[3].type
|
42
|
+
assert_equal 'R', sigs[3].name
|
43
|
+
assert_equal TChar, sigs[4].type
|
44
|
+
assert_equal 'my_x1', sigs[4].name
|
45
|
+
assert_equal TLong, sigs[5].type
|
46
|
+
assert_equal 'y1', sigs[5].name
|
47
|
+
assert_equal TFloat, sigs[6].type
|
48
|
+
assert_equal 'x2', sigs[6].name
|
49
|
+
assert_equal TArray.new(TArray.new(TInt)), sigs[7].type
|
50
|
+
assert_equal 'y2', sigs[7].name
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'topcoder/types'
|
3
|
+
include TopCoder
|
4
|
+
|
5
|
+
class TypesTest < Test::Unit::TestCase
|
6
|
+
def test_parse_type
|
7
|
+
assert_raise UnrecognizedType do array = TArray.new 123 end
|
8
|
+
assert_raise UnrecognizedType do type = parse_type '' end
|
9
|
+
assert_raise UnrecognizedType do type = parse_type ' ' end
|
10
|
+
assert_raise UnrecognizedType do type = parse_type '[]' end
|
11
|
+
assert_raise UnrecognizedType do type = parse_type 'vector' end
|
12
|
+
assert_raise UnrecognizedType do type = parse_type 'vector[]' end
|
13
|
+
assert_equal TBoolean, parse_type('boolean')
|
14
|
+
assert_equal TInt, parse_type('int')
|
15
|
+
assert_equal TLong, parse_type('long')
|
16
|
+
assert_equal TFloat, parse_type('float')
|
17
|
+
assert_equal TDouble, parse_type('double')
|
18
|
+
assert_equal TChar, parse_type('char')
|
19
|
+
assert_equal TString, parse_type('String')
|
20
|
+
assert_equal TArray.new(TBoolean), parse_type('boolean[]')
|
21
|
+
assert_equal TArray.new(TInt), parse_type('int[]')
|
22
|
+
assert_equal TArray.new(TArray.new(TString)), parse_type('String[][]')
|
23
|
+
end
|
24
|
+
end
|