gettc 1.5 → 1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/gettc +45 -29
- data/core/lib/gettc.rb +7 -0
- data/core/lib/{topcoder → gettc}/download.rb +53 -45
- data/core/lib/gettc/generate.rb +145 -0
- data/core/lib/{topcoder → gettc}/parse.rb +104 -102
- data/core/lib/{topcoder → gettc}/print.rb +11 -11
- data/core/lib/{topcoder → gettc}/problem.rb +11 -11
- data/core/lib/{topcoder → gettc}/signature.rb +8 -8
- data/core/lib/{topcoder → gettc}/types.rb +34 -17
- data/core/test/{topcoder → gettc}/download_test.rb +6 -6
- data/core/test/gettc/generate_test.rb +31 -0
- data/core/test/{topcoder → gettc}/parse_test.rb +26 -26
- data/core/test/gettc/signature_test.rb +54 -0
- data/core/test/gettc/types_test.rb +24 -0
- data/dist/config.yml +1 -0
- data/dist/include/cpp/engine.rb +32 -32
- data/dist/include/cpp/topcoder +89 -25
- data/dist/include/haskell/TopCoder.hs +72 -53
- data/dist/include/haskell/engine.rb +49 -47
- data/dist/include/java/TopCoder.jar +0 -0
- data/dist/include/java/engine.rb +71 -71
- data/dist/include/python/engine.rb +46 -0
- data/dist/include/python/topcoder/__init__.py +3 -0
- data/dist/include/python/topcoder/errors.py +4 -0
- data/dist/include/python/topcoder/reader.py +160 -0
- data/dist/include/python/topcoder/writer.py +13 -0
- data/dist/template/bin/runner.sh +16 -6
- data/dist/template/solve/cpp/Makefile +9 -5
- data/dist/template/solve/cpp/{name}.cpp +8 -8
- data/dist/template/solve/cpp/{name}Runner.cpp +8 -8
- data/dist/template/solve/haskell/Makefile +9 -5
- data/dist/template/solve/haskell/{name}.hs +1 -1
- data/dist/template/solve/haskell/{name}Runner.hs +5 -5
- data/dist/template/solve/java/Makefile +18 -0
- data/dist/template/solve/java/build.xml +7 -3
- data/dist/template/solve/java/{name}.java +1 -1
- data/dist/template/solve/java/{name}Runner.java +1 -1
- data/dist/template/solve/python/Makefile +27 -0
- data/dist/template/solve/python/{name}.py +4 -0
- data/dist/template/solve/python/{name}Runner.py +27 -0
- data/dist/template/util/check/Makefile +3 -1
- data/dist/usage +5 -0
- metadata +30 -24
- data/Rakefile +0 -41
- data/core/lib/topcoder.rb +0 -3
- data/core/lib/topcoder/generate.rb +0 -131
- data/core/test/topcoder/generate_test.rb +0 -31
- data/core/test/topcoder/signature_test.rb +0 -52
- data/core/test/topcoder/types_test.rb +0 -24
- data/dist/template/solve/cpp/{name}Test.cpp +0 -8
- data/dist/template/solve/haskell/{name}Test.hs +0 -10
- data/dist/template/solve/java/{name}Test.java +0 -8
@@ -1,7 +1,7 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "gettc/problem"
|
2
|
+
require "rdiscount"
|
3
3
|
|
4
|
-
module
|
4
|
+
module Gettc
|
5
5
|
class Problem
|
6
6
|
def to_md
|
7
7
|
out = "# [#{@name}](#{@url})\n"
|
@@ -10,19 +10,19 @@ module TopCoder
|
|
10
10
|
out << "## Statement\n"
|
11
11
|
out << @statement << "\n\n"
|
12
12
|
|
13
|
-
|
13
|
+
unless @definitions.empty? then
|
14
14
|
out << "## Definitions\n"
|
15
15
|
@definitions.each do |k, v| out << "- *#{k}*: `#{v}`\n" end
|
16
16
|
out << "\n"
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
unless @notes.empty? then
|
20
20
|
out << "## Notes\n"
|
21
21
|
@notes.each do |note| out << "- #{note}\n" end
|
22
22
|
out << "\n"
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
unless @constraints.empty? then
|
26
26
|
out << "## Constraints\n"
|
27
27
|
@constraints.each do |constraint|
|
28
28
|
out << "- #{constraint}\n"
|
@@ -30,18 +30,18 @@ module TopCoder
|
|
30
30
|
out << "\n"
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
unless @examples.empty? then
|
34
34
|
out << "## Examples\n"
|
35
35
|
@examples.each_index do |i|
|
36
36
|
example = @examples[i]
|
37
37
|
out << "### Example #{i + 1}\n"
|
38
38
|
out << "#### Input\n<c>"
|
39
|
-
out << example.input.gsub("\n",
|
39
|
+
out << example.input.gsub("\n", "<br />")
|
40
40
|
out << "</c>\n"
|
41
41
|
out << "#### Output\n<c>"
|
42
|
-
out << example.output.gsub("\n",
|
42
|
+
out << example.output.gsub("\n", "<br />")
|
43
43
|
out << "</c>\n"
|
44
|
-
|
44
|
+
unless example.reason.empty? then
|
45
45
|
out << "#### Reason\n#{example.reason}\n\n"
|
46
46
|
end
|
47
47
|
end
|
@@ -53,4 +53,4 @@ module TopCoder
|
|
53
53
|
return markdown.to_html
|
54
54
|
end
|
55
55
|
end
|
56
|
-
end
|
56
|
+
end
|
@@ -1,27 +1,27 @@
|
|
1
|
-
module
|
1
|
+
module Gettc
|
2
2
|
class Case
|
3
3
|
attr_accessor :input, :output, :reason
|
4
4
|
def initialize
|
5
|
-
@input =
|
6
|
-
@output =
|
7
|
-
@reason =
|
5
|
+
@input = ""
|
6
|
+
@output = ""
|
7
|
+
@reason = ""
|
8
8
|
end
|
9
9
|
end
|
10
10
|
class Image
|
11
11
|
attr_accessor :name, :content
|
12
12
|
def initialize
|
13
|
-
@name =
|
14
|
-
@content =
|
13
|
+
@name = ""
|
14
|
+
@content = ""
|
15
15
|
end
|
16
16
|
end
|
17
17
|
class Problem
|
18
18
|
attr_accessor :name, :url, :source, :statement, :definitions, :notes,
|
19
19
|
:constraints, :examples, :systests, :images
|
20
20
|
def initialize
|
21
|
-
@name =
|
22
|
-
@url =
|
23
|
-
@source =
|
24
|
-
@statement =
|
21
|
+
@name = ""
|
22
|
+
@url = ""
|
23
|
+
@source = ""
|
24
|
+
@statement = ""
|
25
25
|
@definitions = { }
|
26
26
|
@notes = []
|
27
27
|
@constraints = []
|
@@ -30,4 +30,4 @@ module TopCoder
|
|
30
30
|
@images = []
|
31
31
|
end
|
32
32
|
end
|
33
|
-
end
|
33
|
+
end
|
@@ -1,18 +1,18 @@
|
|
1
|
-
require
|
1
|
+
require "gettc/types"
|
2
2
|
|
3
|
-
module
|
3
|
+
module Gettc
|
4
4
|
class SignatureError < StandardError
|
5
5
|
end
|
6
6
|
class CannotParseSignature < SignatureError
|
7
7
|
attr_accessor :source
|
8
|
-
def initialize source, msg =
|
8
|
+
def initialize source, msg = "Cannot parse signature"
|
9
9
|
@source = source
|
10
10
|
super "#{msg} (#{source}"
|
11
11
|
end
|
12
12
|
end
|
13
13
|
class InvalidVariableName < SignatureError
|
14
14
|
attr_accessor :name
|
15
|
-
def initialize name, msg =
|
15
|
+
def initialize name, msg = "Invalid variable name"
|
16
16
|
@name = name
|
17
17
|
super "#{msg} (#{name})"
|
18
18
|
end
|
@@ -39,17 +39,17 @@ module TopCoder
|
|
39
39
|
def parse_method_signature str
|
40
40
|
str.strip!
|
41
41
|
sigs = []
|
42
|
-
parts = str.split
|
42
|
+
parts = str.split "("
|
43
43
|
raise CannotParseSignature.new str if parts.size != 2
|
44
44
|
sigs << parse_signature(parts[0])
|
45
45
|
|
46
46
|
str = parts[1]
|
47
|
-
raise CannotParseSignature.new str if str[-1] !=
|
47
|
+
raise CannotParseSignature.new str if str[-1] != ")"
|
48
48
|
str.chop!
|
49
49
|
|
50
|
-
parts = str.split
|
50
|
+
parts = str.split ","
|
51
51
|
parts.each do |sig| sigs << parse_signature(sig) end
|
52
52
|
|
53
53
|
return sigs
|
54
54
|
end
|
55
|
-
end
|
55
|
+
end
|
@@ -1,11 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module TopCoder
|
4
|
-
class TypeError < StandardError
|
5
|
-
end
|
1
|
+
module Gettc
|
2
|
+
TypeError = Class.new StandardError
|
6
3
|
class UnrecognizedType < TypeError
|
7
4
|
attr_accessor :type
|
8
|
-
def initialize type = nil, msg =
|
5
|
+
def initialize type = nil, msg = "Not a valid TopCoder type"
|
9
6
|
@type = type
|
10
7
|
super "#{msg} (#{type})"
|
11
8
|
end
|
@@ -17,6 +14,26 @@ module TopCoder
|
|
17
14
|
def obj?
|
18
15
|
return @is_object
|
19
16
|
end
|
17
|
+
def to_s
|
18
|
+
if self == TInt then
|
19
|
+
return "int"
|
20
|
+
elsif self == TLong then
|
21
|
+
return "long"
|
22
|
+
elsif self == TFloat then
|
23
|
+
return "float"
|
24
|
+
elsif self == TDouble then
|
25
|
+
return "double"
|
26
|
+
elsif self == TChar then
|
27
|
+
return "char"
|
28
|
+
elsif self == TString then
|
29
|
+
return "String"
|
30
|
+
elsif self == TBoolean then
|
31
|
+
return "boolean"
|
32
|
+
elsif is_a? TArray then
|
33
|
+
return subtype.to_s + "[]"
|
34
|
+
end
|
35
|
+
return "unknown"
|
36
|
+
end
|
20
37
|
end
|
21
38
|
TBoolean = Type.new false
|
22
39
|
TInt = Type.new false
|
@@ -28,11 +45,11 @@ module TopCoder
|
|
28
45
|
class TArray < Type
|
29
46
|
attr_accessor :subtype
|
30
47
|
def initialize subtype
|
31
|
-
raise UnrecognizedType.new subtype
|
48
|
+
raise UnrecognizedType.new subtype unless subtype.is_a? Type
|
32
49
|
@subtype = subtype
|
33
50
|
end
|
34
51
|
def == ary
|
35
|
-
return false
|
52
|
+
return false unless ary.is_a? TArray
|
36
53
|
return @subtype == ary.subtype
|
37
54
|
end
|
38
55
|
def obj?
|
@@ -40,23 +57,23 @@ module TopCoder
|
|
40
57
|
end
|
41
58
|
end
|
42
59
|
def parse_type str
|
43
|
-
return TArray.new parse_type str[0 .. -3] if str[-2 .. -1] ==
|
60
|
+
return TArray.new parse_type str[0 .. -3] if str[-2 .. -1] == "[]"
|
44
61
|
case str
|
45
|
-
when
|
62
|
+
when "boolean"
|
46
63
|
return TBoolean
|
47
|
-
when
|
64
|
+
when "int"
|
48
65
|
return TInt
|
49
|
-
when
|
66
|
+
when "long"
|
50
67
|
return TLong
|
51
|
-
when
|
68
|
+
when "float"
|
52
69
|
return TFloat
|
53
|
-
when
|
70
|
+
when "double"
|
54
71
|
return TDouble
|
55
|
-
when
|
72
|
+
when "char"
|
56
73
|
return TChar
|
57
|
-
when
|
74
|
+
when "String"
|
58
75
|
return TString
|
59
76
|
end
|
60
77
|
raise UnrecognizedType.new str
|
61
78
|
end
|
62
|
-
end
|
79
|
+
end
|
@@ -1,14 +1,14 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "test/unit"
|
2
|
+
require "topcoder/download"
|
3
3
|
include TopCoder
|
4
4
|
|
5
5
|
class DownloadTest < Test::Unit::TestCase
|
6
6
|
def setup
|
7
|
-
@account = Account.new
|
7
|
+
@account = Account.new "gettc", "algorithm"
|
8
8
|
end
|
9
9
|
def test_wrong_account
|
10
10
|
assert_raises LoginFailed do
|
11
|
-
Downloader.new Account.new
|
11
|
+
Downloader.new Account.new "username", "password"
|
12
12
|
end
|
13
13
|
end
|
14
14
|
def test_wrong_id
|
@@ -23,7 +23,7 @@ class DownloadTest < Test::Unit::TestCase
|
|
23
23
|
3.times do
|
24
24
|
id = ids[rand ids.size]
|
25
25
|
html = downloader.download_problem id
|
26
|
-
assert_match
|
26
|
+
assert_match "<h3>Problem Statement</h3>", html
|
27
27
|
end
|
28
28
|
end
|
29
|
-
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 unless 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 unless File.exists? prob_d
|
28
|
+
assert_raise ProblemDirExists do @generator.generate prob end
|
29
|
+
FileUtils.rmdir prob_d
|
30
|
+
end
|
31
|
+
end
|
@@ -1,34 +1,34 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "test/unit"
|
2
|
+
require "topcoder/parse"
|
3
3
|
include TopCoder
|
4
4
|
|
5
5
|
class ParseTest < Test::Unit::TestCase
|
6
6
|
def setup
|
7
|
-
downloader = Downloader.new Account.new
|
7
|
+
downloader = Downloader.new Account.new "gettc", "algorithm"
|
8
8
|
@parser = Parser.new downloader
|
9
|
-
@
|
9
|
+
@data_d = File.join File.dirname(__FILE__), "../../temp/download_problem_statement"
|
10
10
|
end
|
11
11
|
def get_problem_raw prob
|
12
|
-
return File.read File.join @
|
12
|
+
return File.read File.join @data_d, prob + ".htm"
|
13
13
|
end
|
14
14
|
def test_indexes
|
15
|
-
assert_equal [0, 3], @parser.indexes(
|
16
|
-
assert_equal nil, @parser.indexes(
|
15
|
+
assert_equal [0, 3], @parser.indexes("abcde", "bc")
|
16
|
+
assert_equal nil, @parser.indexes("abcde", "f")
|
17
17
|
end
|
18
18
|
def test_filter
|
19
|
-
assert_equal
|
20
|
-
assert_equal
|
21
|
-
assert_equal
|
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
22
|
html = <<-END
|
23
23
|
<img src=
|
24
24
|
"http://www.topcoder.com/contest/problem/CirclesCountry/case1.gif">
|
25
25
|
END
|
26
|
-
assert_equal
|
26
|
+
assert_equal "![image](images/case1.gif)", @parser.filter(html)
|
27
27
|
end
|
28
28
|
def test_PageNumbers
|
29
|
-
html = get_problem_raw
|
29
|
+
html = get_problem_raw "PageNumbers"
|
30
30
|
prob = @parser.parse html
|
31
|
-
assert_equal
|
31
|
+
assert_equal "PageNumbers", prob.name
|
32
32
|
assert_equal 5, prob.definitions.size
|
33
33
|
assert_equal 1, prob.notes.size
|
34
34
|
assert_equal 1, prob.constraints.size
|
@@ -37,9 +37,9 @@ class ParseTest < Test::Unit::TestCase
|
|
37
37
|
assert_equal 0, prob.images.size
|
38
38
|
end
|
39
39
|
def test_CirclesCountry
|
40
|
-
html = get_problem_raw
|
40
|
+
html = get_problem_raw "CirclesCountry"
|
41
41
|
prob = @parser.parse html
|
42
|
-
assert_equal
|
42
|
+
assert_equal "CirclesCountry", prob.name
|
43
43
|
assert_equal 5, prob.definitions.size
|
44
44
|
assert_equal 0, prob.notes.size
|
45
45
|
assert_equal 7, prob.constraints.size
|
@@ -48,9 +48,9 @@ class ParseTest < Test::Unit::TestCase
|
|
48
48
|
assert_equal 4, prob.images.size
|
49
49
|
end
|
50
50
|
def test_TheTournamentDivOne
|
51
|
-
html = get_problem_raw
|
51
|
+
html = get_problem_raw "TheTournamentDivOne"
|
52
52
|
prob = @parser.parse html
|
53
|
-
assert_equal
|
53
|
+
assert_equal "TheTournamentDivOne", prob.name
|
54
54
|
assert_equal 5, prob.definitions.size
|
55
55
|
assert_equal 0, prob.notes.size
|
56
56
|
assert_equal 4, prob.constraints.size
|
@@ -59,9 +59,9 @@ class ParseTest < Test::Unit::TestCase
|
|
59
59
|
assert_equal 0, prob.images.size
|
60
60
|
end
|
61
61
|
def test_FunnyGames
|
62
|
-
html = get_problem_raw
|
62
|
+
html = get_problem_raw "FunnyGames"
|
63
63
|
prob = @parser.parse html
|
64
|
-
assert_equal
|
64
|
+
assert_equal "FunnyGames", prob.name
|
65
65
|
assert_equal 5, prob.definitions.size
|
66
66
|
assert_equal 0, prob.notes.size
|
67
67
|
assert_equal 6, prob.constraints.size
|
@@ -70,9 +70,9 @@ class ParseTest < Test::Unit::TestCase
|
|
70
70
|
assert_equal 0, prob.images.size
|
71
71
|
end
|
72
72
|
def test_BuildingRoads
|
73
|
-
html = get_problem_raw
|
73
|
+
html = get_problem_raw "BuildingRoads"
|
74
74
|
prob = @parser.parse html
|
75
|
-
assert_equal
|
75
|
+
assert_equal "BuildingRoads", prob.name
|
76
76
|
assert_equal 5, prob.definitions.size
|
77
77
|
assert_equal 2, prob.notes.size
|
78
78
|
assert_equal 10, prob.constraints.size
|
@@ -81,9 +81,9 @@ class ParseTest < Test::Unit::TestCase
|
|
81
81
|
assert_equal 2, prob.images.size
|
82
82
|
end
|
83
83
|
def test_Acronyms
|
84
|
-
html = get_problem_raw
|
84
|
+
html = get_problem_raw "Acronyms"
|
85
85
|
prob = @parser.parse html
|
86
|
-
assert_equal
|
86
|
+
assert_equal "Acronyms", prob.name
|
87
87
|
assert_equal 5, prob.definitions.size
|
88
88
|
assert_equal 1, prob.notes.size
|
89
89
|
assert_equal 8, prob.constraints.size
|
@@ -92,13 +92,13 @@ class ParseTest < Test::Unit::TestCase
|
|
92
92
|
assert_equal 0, prob.images.size
|
93
93
|
end
|
94
94
|
def test_BackyardTrees
|
95
|
-
html = get_problem_raw
|
95
|
+
html = get_problem_raw "BackyardTrees"
|
96
96
|
prob = @parser.parse html
|
97
|
-
assert_equal
|
97
|
+
assert_equal "BackyardTrees", prob.name
|
98
98
|
assert_equal 5, prob.definitions.size
|
99
99
|
assert_equal 0, prob.notes.size
|
100
100
|
assert_equal 4, prob.constraints.size
|
101
101
|
assert_equal 6, prob.examples.size
|
102
102
|
assert_equal 2, prob.images.size
|
103
103
|
end
|
104
|
-
end
|
104
|
+
end
|
@@ -0,0 +1,54 @@
|
|
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
|
17
|
+
parse_signature "int 0zero"
|
18
|
+
end
|
19
|
+
sig = parse_signature "String[] a_valid_nam3"
|
20
|
+
assert_equal TArray.new(TString), sig.type
|
21
|
+
assert_equal "a_valid_nam3", sig.name
|
22
|
+
end
|
23
|
+
def test_parse_method_signature
|
24
|
+
assert_raise CannotParseSignature do
|
25
|
+
parse_method_signature "there are no brackets"
|
26
|
+
end
|
27
|
+
assert_raise CannotParseSignature do
|
28
|
+
parse_method_signature "int main(int main())"
|
29
|
+
end
|
30
|
+
assert_raise CannotParseSignature do
|
31
|
+
parse_method_signature "int main(oops forget to close bracket"
|
32
|
+
end
|
33
|
+
method = " int leastBorders(String[] X , int[] Y, double[] R,"
|
34
|
+
method += " char my_x1, long y1 , float x2, int[][] y2) "
|
35
|
+
sigs = parse_method_signature method
|
36
|
+
assert_equal 8, sigs.size
|
37
|
+
assert_equal TInt, sigs[0].type
|
38
|
+
assert_equal "leastBorders", sigs[0].name
|
39
|
+
assert_equal TArray.new(TString), sigs[1].type
|
40
|
+
assert_equal "X", sigs[1].name
|
41
|
+
assert_equal TArray.new(TInt), sigs[2].type
|
42
|
+
assert_equal "Y", sigs[2].name
|
43
|
+
assert_equal TArray.new(TDouble), sigs[3].type
|
44
|
+
assert_equal "R", sigs[3].name
|
45
|
+
assert_equal TChar, sigs[4].type
|
46
|
+
assert_equal "my_x1", sigs[4].name
|
47
|
+
assert_equal TLong, sigs[5].type
|
48
|
+
assert_equal "y1", sigs[5].name
|
49
|
+
assert_equal TFloat, sigs[6].type
|
50
|
+
assert_equal "x2", sigs[6].name
|
51
|
+
assert_equal TArray.new(TArray.new(TInt)), sigs[7].type
|
52
|
+
assert_equal "y2", sigs[7].name
|
53
|
+
end
|
54
|
+
end
|