gettc 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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 '![image](images/case1.gif)', @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
|