trackler 2.2.1.65 → 2.2.1.66

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/problem-specifications/exercises/reverse-string/canonical-data.json +3 -3
  4. data/tracks/c/exercises/hello-world/makefile +9 -0
  5. data/tracks/c/exercises/phone-number/test/test_phone_number.c +2 -1
  6. data/tracks/go/exercises/collatz-conjecture/.meta/gen.go +72 -0
  7. data/tracks/go/exercises/collatz-conjecture/cases_test.go +43 -0
  8. data/tracks/go/exercises/collatz-conjecture/collatz_conjecture_test.go +0 -42
  9. data/tracks/perl6/config.json +10 -0
  10. data/tracks/perl6/docs/ABOUT.md +21 -12
  11. data/tracks/perl6/exercises/all-your-base/AllYourBase.pm6 +4 -1
  12. data/tracks/perl6/exercises/all-your-base/Example.pm6 +14 -34
  13. data/tracks/perl6/exercises/all-your-base/all-your-base.t +40 -53
  14. data/tracks/perl6/exercises/all-your-base/example.yaml +31 -51
  15. data/tracks/perl6/exercises/hamming/Example.pm6 +5 -4
  16. data/tracks/perl6/exercises/hamming/Hamming.pm6 +1 -1
  17. data/tracks/perl6/exercises/hamming/example.yaml +6 -5
  18. data/tracks/perl6/exercises/hamming/hamming.t +2 -2
  19. data/tracks/perl6/exercises/meetup/README.md +16 -12
  20. data/tracks/perl6/exercises/nucleotide-count/Example.pm6 +7 -0
  21. data/tracks/perl6/exercises/nucleotide-count/NucleotideCount.pm6 +4 -0
  22. data/tracks/perl6/exercises/nucleotide-count/README.md +38 -0
  23. data/tracks/perl6/exercises/nucleotide-count/example.yaml +24 -0
  24. data/tracks/perl6/exercises/nucleotide-count/nucleotide-count.t +116 -0
  25. data/tracks/python/exercises/perfect-numbers/example.py +13 -2
  26. data/tracks/python/exercises/perfect-numbers/perfect_numbers.py +1 -5
  27. data/tracks/python/exercises/perfect-numbers/perfect_numbers_test.py +60 -22
  28. data/tracks/python/test/check-exercises.py +1 -30
  29. data/tracks/scala/config.json +12 -0
  30. data/tracks/scala/exercises/flatten-array/README.md +29 -0
  31. data/tracks/scala/exercises/flatten-array/build.sbt +3 -0
  32. data/tracks/scala/exercises/flatten-array/example.scala +7 -0
  33. data/tracks/scala/exercises/flatten-array/project/build.properties +1 -0
  34. data/tracks/scala/exercises/flatten-array/src/main/scala/.keep +0 -0
  35. data/tracks/scala/exercises/flatten-array/src/test/scala/FlattenArrayTest.scala +55 -0
  36. metadata +15 -2
@@ -1,73 +1,53 @@
1
1
  exercise: AllYourBase
2
- version: 2
2
+ version: 3
3
3
  plan: 23
4
4
  imports: '&convert-base'
5
5
  tests: |-
6
-
7
- for @($c-data<cases>) -> $case {
8
- if $case<expected> ~~ Array:D { test }
9
- else {
10
- given $case<description> {
11
- when 'empty list' { test [] }
12
- when /base|digit/ { throws-like {call-convert-base}, Exception, $_ }
13
- when /zero/ {
14
- when 'leading zeros' { test [4,2] }
15
- default { test [0] }
16
- }
17
- flunk "$_; not tested" if %*ENV<EXERCISM>; # To ensure that no canonical-data cases are missed.
18
- }
6
+ for $c-data<cases>.values -> $case {
7
+ sub call-convert-base {
8
+ convert-base(
9
+ bases => %(<from to> Z=> .<input_base output_base>),
10
+ digits => .<input_digits>,
11
+ ) given $case;
19
12
  }
20
13
 
21
- sub test (Array:D $expected = $case<expected>) {
22
- is-deeply call-convert-base, $expected, $case<description>
14
+ given $case {
15
+ if .<expected><error> {
16
+ throws-like {call-convert-base}, Exception, .<description>;
17
+ }
18
+ else {
19
+ cmp-ok call-convert-base, ‘~~’, |.<expected description>;
20
+ }
23
21
  }
24
-
25
- sub call-convert-base { convert-base(|$case<input_base input_digits output_base>) }
26
22
  }
27
23
 
28
24
  unit: module
29
25
  example: |-
30
- class X::AllYourBase::InvalidBase is Exception {
31
- has $.payload;
32
- method message {"$!payload is not a valid base."}
33
- }
34
-
35
- class X::AllYourBase::InvalidDigit is Exception {
36
- has %.payload;
37
- method message {"%!payload<digit> is not a valid digit for base %!payload<base>."}
38
- }
39
-
40
- sub convert-base (Int:D $input-base, @input-digits, Int:D $output-base --> Array:D) is export {
41
- for $input-base, $output-base {
42
- X::AllYourBase::InvalidBase.new(payload => $_).throw if $_ < 2;
43
- }
44
- from-decimal($output-base, (to-decimal $input-base, @input-digits));
26
+ sub convert-base (
27
+ :%bases! where all(.keys ~~ <from to>.Set, .values.all > 1),
28
+ :@digits! where %bases<from> > .all ~~ UInt:D,
29
+ --> Array[UInt:D]
30
+ ) is export {
31
+ from-decimal %bases<to>, to-decimal(%bases<from>, @digits);
45
32
  }
46
33
 
47
34
  sub to-decimal ($input-base, @input-digits) {
48
- return [].Slip if !@input-digits;
49
35
  my $elems = @input-digits.elems;
50
- for @input-digits {
51
- if $_ == 0 { $elems-- }
52
- else { last }
53
- }
54
- my $dec = 0;
55
- loop (my $i = 0; $i < $elems; $i++) {
56
- if @input-digits.reverse[$i] < 0 || @input-digits.reverse[$i] >= $input-base {
57
- X::AllYourBase::InvalidDigit.new( :payload(base => $input-base, digit => @input-digits.reverse[$i]) ).throw;
58
- }
59
- $dec += @input-digits.reverse[$i] * $input-base ** $i;
60
- }
61
- return $dec;
36
+ $_ == 0 ?? $elems-- !! last for @input-digits;
37
+ (loop (my $i = 0; $i < $elems; $i++) {
38
+ @input-digits.reverse[$i] * $input-base ** $i;
39
+ }).sum;
62
40
  }
63
41
 
64
- sub from-decimal ($output-base, $dec) {
65
- my @output-digits;
66
- my $num = $dec;
42
+ sub from-decimal ($output-base, $num is copy) {
43
+ my UInt:D @output-digits;
67
44
  while $num >= $output-base {
68
45
  unshift @output-digits, $num % $output-base;
69
46
  $num div= $output-base;
70
47
  }
71
- unshift @output-digits, $num;
72
- return @output-digits;
48
+ @output-digits.unshift: $num;
49
+ }
50
+
51
+ stub: |-
52
+ sub convert-base (:%bases!, :@digits!) is export {
73
53
  }
@@ -1,6 +1,7 @@
1
- unit module Hamming:ver<1>;
1
+ unit module Hamming:ver<2>;
2
2
 
3
- sub hamming-distance ( Str:D $strand1, Str:D $strand2 --> Int:D ) is export {
4
- die ‘left and right strands must be of equal length’ if $strand1.chars $strand2.chars;
5
- ($strand1.comb Zne $strand2.comb).sum
3
+ sub hamming-distance (
4
+ +@strands where { .elems == 2 && [==] $_».chars } --> Int:D
5
+ ) is export {
6
+ sum [Zne] @strands».comb
6
7
  }
@@ -1,4 +1,4 @@
1
- unit module Hamming:ver<1>;
1
+ unit module Hamming:ver<2>;
2
2
 
3
3
  sub hamming-distance ($strand1, $strand2) is export {
4
4
  }
@@ -1,11 +1,11 @@
1
1
  exercise: Hamming
2
- version: 1
2
+ version: 2
3
3
  plan: 17
4
4
  imports: '&hamming-distance'
5
5
  tests: |-
6
6
  for $c-data<cases>.values {
7
7
  if .<expected><error> {
8
- throws-like {hamming-distance(|.<strand1 strand2>)}, Exception, .<description>, message => .<expected><error>;
8
+ throws-like {hamming-distance(|.<strand1 strand2>)}, Exception, .<description>;
9
9
  } else {
10
10
  is hamming-distance(|.<strand1 strand2>), |.<expected description>;
11
11
  }
@@ -13,9 +13,10 @@ tests: |-
13
13
 
14
14
  unit: module
15
15
  example: |-
16
- sub hamming-distance ( Str:D $strand1, Str:D $strand2 --> Int:D ) is export {
17
- die ‘left and right strands must be of equal length’ if $strand1.chars $strand2.chars;
18
- ($strand1.comb Zne $strand2.comb).sum
16
+ sub hamming-distance (
17
+ +@strands where { .elems == 2 && [==] $_».chars } --> Int:D
18
+ ) is export {
19
+ sum [Zne] @strands».comb
19
20
  }
20
21
  stub: |-
21
22
  sub hamming-distance ($strand1, $strand2) is export {
@@ -5,7 +5,7 @@ use lib my $dir = $?FILE.IO.dirname;
5
5
  use JSON::Fast;
6
6
 
7
7
  my Str:D $exercise := 'Hamming';
8
- my Version:D $version = v1;
8
+ my Version:D $version = v2;
9
9
  my Str $module //= $exercise;
10
10
  plan 17;
11
11
 
@@ -24,7 +24,7 @@ require ::($module) <&hamming-distance>;
24
24
  my $c-data = from-json $=pod.pop.contents;
25
25
  for $c-data<cases>.values {
26
26
  if .<expected><error> {
27
- throws-like {hamming-distance(|.<strand1 strand2>)}, Exception, .<description>, message => .<expected><error>;
27
+ throws-like {hamming-distance(|.<strand1 strand2>)}, Exception, .<description>;
28
28
  } else {
29
29
  is hamming-distance(|.<strand1 strand2>), |.<expected description>;
30
30
  }
@@ -2,25 +2,29 @@
2
2
 
3
3
  Calculate the date of meetups.
4
4
 
5
- Typically meetups happen on the same day of the week. In this exercise, you will take
6
- a description of a meetup date, and return the actual meetup date.
5
+ Typically meetups happen on the same day of the week. In this exercise, you
6
+ will take a description of a meetup date, and return the actual meetup date.
7
7
 
8
8
  Examples of general descriptions are:
9
9
 
10
- - the first Monday of January 2017
11
- - the third Tuesday of January 2017
12
- - the Wednesteenth of January 2017
13
- - the last Thursday of January 2017
10
+ - The first Monday of January 2017
11
+ - The third Tuesday of January 2017
12
+ - The wednesteenth of January 2017
13
+ - The last Thursday of January 2017
14
14
 
15
- Note that "Monteenth", "Tuesteenth", etc are all made up words. There
16
- was a meetup whose members realized that there are exactly 7 numbered days in a month that
17
- end in '-teenth'. Therefore, one is guaranteed that each day of the week
15
+ The descriptors you are expected to parse are:
16
+ first, second, third, fourth, fifth, last, monteenth, tuesteenth, wednesteenth,
17
+ thursteenth, friteenth, saturteenth, sunteenth
18
+
19
+ Note that "monteenth", "tuesteenth", etc are all made up words. There was a
20
+ meetup whose members realized that there are exactly 7 numbered days in a month
21
+ that end in '-teenth'. Therefore, one is guaranteed that each day of the week
18
22
  (Monday, Tuesday, ...) will have exactly one date that is named with '-teenth'
19
23
  in every month.
20
24
 
21
- Given examples of a meetup dates, each containing a month, day, year, and descriptor
22
- (first, second, teenth, etc), calculate the date of the actual meetup.
23
- For example, if given "First Monday of January 2017", the correct meetup date is 2017/1/2
25
+ Given examples of a meetup dates, each containing a month, day, year, and
26
+ descriptor calculate the date of the actual meetup. For example, if given
27
+ "The first Monday of January 2017", the correct meetup date is 2017/1/2.
24
28
 
25
29
  ## Resources
26
30
 
@@ -0,0 +1,7 @@
1
+ unit module NucleotideCount:ver<1>;
2
+
3
+ sub nucleotide-count (
4
+ Str:D $_ where { .comb.Set ⊆ <A C G T> } --> Bag(Iterable:D)
5
+ ) is export {
6
+ .comb
7
+ }
@@ -0,0 +1,4 @@
1
+ unit module NucleotideCount:ver<1>;
2
+
3
+ sub nucleotide-count ($strand) is export {
4
+ }
@@ -0,0 +1,38 @@
1
+ # Nucleotide Count
2
+
3
+ Given a single stranded DNA string, compute how many times each nucleotide occurs in the string.
4
+
5
+ The genetic language of every living thing on the planet is DNA.
6
+ DNA is a large molecule that is built from an extremely long sequence of individual elements called nucleotides.
7
+ 4 types exist in DNA and these differ only slightly and can be represented as the following symbols: 'A' for adenine, 'C' for cytosine, 'G' for guanine, and 'T' thymine.
8
+
9
+ Here is an analogy:
10
+ - twigs are to birds nests as
11
+ - nucleotides are to DNA as
12
+ - legos are to lego houses as
13
+ - words are to sentences as...
14
+
15
+ ## Resources
16
+
17
+ Remember to check out the Perl 6 [documentation](https://docs.perl6.org/) and
18
+ [resources](https://perl6.org/resources/) pages for information, tips, and
19
+ examples if you get stuck.
20
+
21
+ ## Running the tests
22
+
23
+ There is a test suite and module included with the exercise.
24
+ The test suite (a file with the extension `.t`) will attempt to run routines
25
+ from the module (a file with the extension `.pm6`).
26
+ Add/modify routines in the module so that the tests will pass! You can view the
27
+ test data by executing the command `perl6 --doc *.t` (\* being the name of the
28
+ test suite), and run the test suite for the exercise by executing the command
29
+ `prove . --exec=perl6` in the exercise directory.
30
+ You can also add the `-v` flag e.g. `prove . --exec=perl6 -v` to display all
31
+ tests, including any optional tests marked as 'TODO'.
32
+
33
+ ## Source
34
+
35
+ The Calculating DNA Nucleotides_problem at Rosalind [http://rosalind.info/problems/dna/](http://rosalind.info/problems/dna/)
36
+
37
+ ## Submitting Incomplete Solutions
38
+ It's possible to submit an incomplete solution so you can see how others have completed the exercise.
@@ -0,0 +1,24 @@
1
+ exercise: NucleotideCount
2
+ version: 1
3
+ plan: 7
4
+ imports: '&nucleotide-count'
5
+ tests: |-
6
+ for $c-data<cases>».<cases>».Array.flat {
7
+ if .<expected><error> {
8
+ throws-like {nucleotide-count(.<strand>)}, Exception, .<description>;
9
+ }
10
+ else {
11
+ cmp-ok nucleotide-count(.<strand>), '~~', .<expected>.Bag, .<description>;
12
+ }
13
+ }
14
+
15
+ unit: module
16
+ example: |-
17
+ sub nucleotide-count (
18
+ Str:D $_ where { .comb.Set ⊆ <A C G T> } --> Bag(Iterable:D)
19
+ ) is export {
20
+ .comb
21
+ }
22
+ stub: |-
23
+ sub nucleotide-count ($strand) is export {
24
+ }
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env perl6
2
+ use v6;
3
+ use Test;
4
+ use lib my $dir = $?FILE.IO.dirname;
5
+ use JSON::Fast;
6
+
7
+ my Str:D $exercise := 'NucleotideCount';
8
+ my Version:D $version = v1;
9
+ my Str $module //= $exercise;
10
+ plan 7;
11
+
12
+ use-ok $module or bail-out;
13
+ require ::($module);
14
+
15
+ if ::($exercise).^ver !~~ $version {
16
+ warn "\nExercise version mismatch. Further tests may fail!"
17
+ ~ "\n$exercise is $(::($exercise).^ver.gist). "
18
+ ~ "Test is $($version.gist).\n";
19
+ bail-out 'Example version must match test version.' if %*ENV<EXERCISM>;
20
+ }
21
+
22
+ require ::($module) <&nucleotide-count>;
23
+
24
+ my $c-data = from-json $=pod.pop.contents;
25
+ for $c-data<cases>».<cases>».Array.flat {
26
+ if .<expected><error> {
27
+ throws-like {nucleotide-count(.<strand>)}, Exception, .<description>;
28
+ }
29
+ else {
30
+ cmp-ok nucleotide-count(.<strand>), '~~', .<expected>.Bag, .<description>;
31
+ }
32
+ }
33
+
34
+ =head2 Canonical Data
35
+ =begin code
36
+
37
+ {
38
+ "exercise": "nucleotide-count",
39
+ "version": "1.2.0",
40
+ "cases": [
41
+ {
42
+ "description": "count all nucleotides in a strand",
43
+ "cases": [
44
+ {
45
+ "description": "empty strand",
46
+ "property": "nucleotideCounts",
47
+ "strand": "",
48
+ "expected": {
49
+ "A": 0,
50
+ "C": 0,
51
+ "G": 0,
52
+ "T": 0
53
+ }
54
+ },
55
+ {
56
+ "description": "can count one nucleotide in single-character input",
57
+ "property": "nucleotideCounts",
58
+ "strand": "G",
59
+ "expected": {
60
+ "A": 0,
61
+ "C": 0,
62
+ "G": 1,
63
+ "T": 0
64
+ }
65
+ },
66
+ {
67
+ "description": "strand with repeated nucleotide",
68
+ "property": "nucleotideCounts",
69
+ "strand": "GGGGGGG",
70
+ "expected": {
71
+ "A": 0,
72
+ "C": 0,
73
+ "G": 7,
74
+ "T": 0
75
+ }
76
+ },
77
+ {
78
+ "description": "strand with multiple nucleotides",
79
+ "property": "nucleotideCounts",
80
+ "strand": "AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC",
81
+ "expected": {
82
+ "A": 20,
83
+ "C": 12,
84
+ "G": 17,
85
+ "T": 21
86
+ }
87
+ },
88
+ {
89
+ "description": "strand with invalid nucleotides",
90
+ "property": "nucleotideCounts",
91
+ "strand": "AGXXACT",
92
+ "expected": {
93
+ "error": "Invalid nucleotide in strand"
94
+ }
95
+ }
96
+ ]
97
+ }
98
+ ]
99
+ }
100
+
101
+ =end code
102
+
103
+ unless %*ENV<EXERCISM> {
104
+ skip-rest 'exercism tests';
105
+ exit;
106
+ }
107
+
108
+ subtest 'canonical-data' => {
109
+ (my $c-data-file = "$dir/../../problem-specifications/exercises/{
110
+ $dir.IO.resolve.basename
111
+ }/canonical-data.json".IO.resolve) ~~ :f ??
112
+ is-deeply $c-data, EVAL('from-json $c-data-file.slurp'), 'match problem-specifications' !!
113
+ flunk 'problem-specifications file not found';
114
+ }
115
+
116
+ INIT { $module = 'Example' if %*ENV<EXERCISM> }
@@ -7,6 +7,17 @@ def divisor_generator(n):
7
7
  yield n // i
8
8
 
9
9
 
10
- def is_perfect(n):
10
+ def classify(n):
11
11
  ''' A perfect number equals the sum of its positive divisors. '''
12
- return sum(divisor_generator(n)) + 1 == n
12
+ if n <= 0:
13
+ raise ValueError("Classification is only possible" +
14
+ " for positive whole numbers.")
15
+
16
+ aliquot_sum = sum(divisor_generator(n)) + (1 if n > 1 else 0)
17
+
18
+ if aliquot_sum < n:
19
+ return "deficient"
20
+ elif aliquot_sum == n:
21
+ return "perfect"
22
+ else:
23
+ return "abundant"
@@ -1,6 +1,2 @@
1
- def divisor_generator(number):
2
- pass
3
-
4
-
5
- def is_perfect(number):
1
+ def classify(number):
6
2
  pass
@@ -1,42 +1,80 @@
1
1
  import unittest
2
2
 
3
- from perfect_numbers import is_perfect
3
+ from perfect_numbers import classify
4
+
5
+ # Tests adapted from `problem-specifications//canonical-data.json` @ v1.0.1
4
6
 
5
7
 
6
8
  class PerfectNumbersTest(unittest.TestCase):
9
+ def test_smallest_perfect_number(self):
10
+ self.assertIs(classify(6), "perfect")
7
11
 
8
- def test_first_perfect_number(self):
9
- self.assertIs(is_perfect(6), True)
12
+ def test_medium_perfect_number(self):
13
+ self.assertIs(classify(28), "perfect")
10
14
 
11
- def test_no_perfect_number(self):
12
- self.assertIs(is_perfect(8), False)
15
+ def test_large_perfect_number(self):
16
+ self.assertIs(classify(33550336), "perfect")
13
17
 
14
- def test_second_perfect_number(self):
15
- self.assertIs(is_perfect(28), True)
18
+ # Additional tests for this track
19
+ def test_third_perfect_number(self):
20
+ self.assertIs(classify(496), "perfect")
16
21
 
17
- def test_abundant(self):
18
- self.assertIs(is_perfect(20), False)
22
+ def test_fourth_perfect_number(self):
23
+ self.assertIs(classify(8128), "perfect")
19
24
 
20
- def test_answer_to_the_ultimate_question_of_life(self):
21
- self.assertIs(is_perfect(42), False)
25
+ def test_sixth_perfect_number(self):
26
+ self.assertIs(classify(8589869056), "perfect")
22
27
 
23
- def test_third_perfect_number(self):
24
- self.assertIs(is_perfect(496), True)
28
+ def test_seventh_perfect_number(self):
29
+ self.assertIs(classify(137438691328), "perfect")
30
+
31
+
32
+ class AbundantNumbersTest(unittest.TestCase):
33
+ def test_smallest_abundant_number(self):
34
+ self.assertIs(classify(12), "abundant")
35
+
36
+ def test_medium_abundant_number(self):
37
+ self.assertIs(classify(30), "abundant")
38
+
39
+ def test_large_abundant_number(self):
40
+ self.assertIs(classify(33550335), "abundant")
41
+
42
+ # Additional tests for this track
43
+ def test_answer_to_the_ultimate_question_of_life(self):
44
+ self.assertIs(classify(42), "abundant")
25
45
 
26
46
  def test_odd_abundant(self):
27
- self.assertIs(is_perfect(945), False)
47
+ self.assertIs(classify(945), "abundant")
28
48
 
29
- def test_fourth_perfect_number(self):
30
- self.assertIs(is_perfect(8128), True)
49
+ def test_even_abundant(self):
50
+ self.assertIs(classify(20), "abundant")
31
51
 
32
- def test_fifth_perfect_number(self):
33
- self.assertIs(is_perfect(33550336), True)
34
52
 
35
- def test_sixth_perfect_number(self):
36
- self.assertIs(is_perfect(8589869056), True)
53
+ class DeficientNumbersTest(unittest.TestCase):
54
+ def test_smallest_prime_deficient_number(self):
55
+ self.assertIs(classify(2), "deficient")
37
56
 
38
- def test_seventh_perfect_number(self):
39
- self.assertIs(is_perfect(137438691328), True)
57
+ def test_smallest_nonprime_deficient_number(self):
58
+ self.assertIs(classify(4), "deficient")
59
+
60
+ def test_medium_deficient_number(self):
61
+ self.assertIs(classify(32), "deficient")
62
+
63
+ def test_large_deficient_number(self):
64
+ self.assertIs(classify(33550337), "deficient")
65
+
66
+ def test_edge_case(self):
67
+ self.assertIs(classify(1), "deficient")
68
+
69
+
70
+ class InvalidInputsTest(unittest.TestCase):
71
+ def test_zero(self):
72
+ with self.assertRaises(ValueError):
73
+ classify(0)
74
+
75
+ def test_negative(self):
76
+ with self.assertRaises(ValueError):
77
+ classify(-1)
40
78
 
41
79
 
42
80
  if __name__ == '__main__':