trackler 2.1.0.28 → 2.1.0.29
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 +4 -4
- data/lib/trackler/version.rb +1 -1
- data/tracks/ceylon/README.md +1 -1
- data/tracks/java/config.json +5 -0
- data/tracks/java/exercises/settings.gradle +1 -0
- data/tracks/java/exercises/word-search/build.gradle +18 -0
- data/tracks/java/exercises/word-search/src/example/java/Pair.java +37 -0
- data/tracks/java/exercises/word-search/src/example/java/WordLocation.java +29 -0
- data/tracks/java/exercises/word-search/src/example/java/WordSearcher.java +94 -0
- data/tracks/java/exercises/word-search/src/main/java/Pair.java +37 -0
- data/tracks/java/exercises/word-search/src/main/java/WordLocation.java +29 -0
- data/tracks/java/exercises/word-search/src/test/java/WordSearcherTest.java +278 -0
- data/tracks/scala/README.md +4 -7
- data/tracks/scala/config.json +11 -10
- data/tracks/scala/exercises/beer-song/src/test/scala/BeerSongTest.scala +2 -1
- data/tracks/scala/exercises/perfect-numbers/example.scala +14 -10
- data/tracks/scala/exercises/perfect-numbers/src/test/scala/PerfectNumbersTest.scala +34 -27
- data/tracks/scala/testgen/src/main/scala/BeerSongTestGenerator.scala +2 -0
- data/tracks/scala/testgen/src/main/scala/PerfectNumbersTestGenerator.scala +42 -0
- data/tracks/scala/testgen/src/main/scala/testgen/CanonicalDataParser.scala +1 -1
- data/tracks/scala/testgen/src/main/scala/testgen/TestSuiteBuilder.scala +2 -2
- data/tracks/vimscript/config.json +6 -2
- data/tracks/vimscript/exercises/etl/etl.vader +27 -0
- data/tracks/vimscript/exercises/etl/etl.vim +12 -0
- data/tracks/vimscript/exercises/etl/example.vim +11 -0
- metadata +13 -3
- data/tracks/scala/exercises/perfect-numbers/src/main/scala/PerfectNumbers.scala +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73dfe16b1709780cb1c87bc8a36da3a089c2ea4e
|
4
|
+
data.tar.gz: 41508819e3d7596fc565fad1029ca178ada8d123
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c2a66c4a2a066f2a5fa9655a3ec3c9ee78d0ef560f9fa6b3ae7e0d1369f4c40a02cdb61c757079709cc87ec1fb0039b0cc1e50452b482e26c8869aeafc96121
|
7
|
+
data.tar.gz: 2c1dd36f3e6189b96fc37dac36f2bb23e3802f74abe75383547f5f5962ed18d20269a5a05dc4ec163ab077ef128562aa59893e1ec49d5aa89e4420920cd4ffd5
|
data/lib/trackler/version.rb
CHANGED
data/tracks/ceylon/README.md
CHANGED
@@ -13,7 +13,7 @@ You can just ask in the [Exercism Gitter support](https://gitter.im/exercism/sup
|
|
13
13
|
|
14
14
|
### How to contribute
|
15
15
|
|
16
|
-
The Exercism-wide [contributing guide](https://github.com/exercism/
|
16
|
+
The Exercism-wide [contributing guide](https://github.com/exercism/docs/tree/master/contributing-to-language-tracks) covers topics relevant to contributing to the entire Exercism project, including but not limited to the Ceylon track.
|
17
17
|
|
18
18
|
* To report a bug or ask a question, [create an issue](https://help.github.com/articles/creating-an-issue/).
|
19
19
|
* If you already have a fix for a bug, you could [create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
|
data/tracks/java/config.json
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
apply plugin: "java"
|
2
|
+
apply plugin: "eclipse"
|
3
|
+
apply plugin: "idea"
|
4
|
+
|
5
|
+
repositories {
|
6
|
+
mavenCentral()
|
7
|
+
}
|
8
|
+
|
9
|
+
dependencies {
|
10
|
+
testCompile "junit:junit:4.12"
|
11
|
+
}
|
12
|
+
|
13
|
+
test {
|
14
|
+
testLogging {
|
15
|
+
exceptionFormat = 'full'
|
16
|
+
events = ["passed", "failed", "skipped"]
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Pair {
|
2
|
+
|
3
|
+
private final int x;
|
4
|
+
|
5
|
+
private final int y;
|
6
|
+
|
7
|
+
Pair(final int x, final int y) {
|
8
|
+
this.y = y;
|
9
|
+
this.x = x;
|
10
|
+
}
|
11
|
+
|
12
|
+
int getX() {
|
13
|
+
return x;
|
14
|
+
}
|
15
|
+
|
16
|
+
int getY() {
|
17
|
+
return y;
|
18
|
+
}
|
19
|
+
|
20
|
+
@Override
|
21
|
+
public boolean equals(final Object o) {
|
22
|
+
if (this == o) return true;
|
23
|
+
if (o == null || getClass() != o.getClass()) return false;
|
24
|
+
|
25
|
+
Pair pair = (Pair) o;
|
26
|
+
|
27
|
+
return x == pair.x && y == pair.y;
|
28
|
+
}
|
29
|
+
|
30
|
+
@Override
|
31
|
+
public int hashCode() {
|
32
|
+
int result = x;
|
33
|
+
result = 31 * result + y;
|
34
|
+
return result;
|
35
|
+
}
|
36
|
+
|
37
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class WordLocation {
|
2
|
+
|
3
|
+
private final Pair startCoord;
|
4
|
+
|
5
|
+
private final Pair endCoord;
|
6
|
+
|
7
|
+
WordLocation(final Pair startCoord, final Pair endCoord) {
|
8
|
+
this.startCoord = startCoord;
|
9
|
+
this.endCoord = endCoord;
|
10
|
+
}
|
11
|
+
|
12
|
+
@Override
|
13
|
+
public boolean equals(final Object o) {
|
14
|
+
if (this == o) return true;
|
15
|
+
if (o == null || getClass() != o.getClass()) return false;
|
16
|
+
|
17
|
+
WordLocation that = (WordLocation) o;
|
18
|
+
|
19
|
+
return startCoord.equals(that.startCoord) && endCoord.equals(that.endCoord);
|
20
|
+
}
|
21
|
+
|
22
|
+
@Override
|
23
|
+
public int hashCode() {
|
24
|
+
int result = startCoord.hashCode();
|
25
|
+
result = 31 * result + endCoord.hashCode();
|
26
|
+
return result;
|
27
|
+
}
|
28
|
+
|
29
|
+
}
|
@@ -0,0 +1,94 @@
|
|
1
|
+
import java.util.*;
|
2
|
+
import java.util.function.Function;
|
3
|
+
import java.util.stream.Collectors;
|
4
|
+
|
5
|
+
class WordSearcher {
|
6
|
+
|
7
|
+
private static final List<Pair> DIRECTIONS = Arrays.asList(
|
8
|
+
new Pair( 1, 0), // N
|
9
|
+
new Pair( 1, 1), // NE
|
10
|
+
new Pair( 0, 1), // E
|
11
|
+
new Pair(-1, 1), // SE
|
12
|
+
new Pair(-1, 0), // S
|
13
|
+
new Pair(-1, -1), // SW
|
14
|
+
new Pair( 0, -1), // W
|
15
|
+
new Pair( 1, -1)); // NW
|
16
|
+
|
17
|
+
/*
|
18
|
+
* Search for multiple words in the given grid.
|
19
|
+
*/
|
20
|
+
Map<String, Optional<WordLocation>> search(final Set<String> words, final char[][] grid) {
|
21
|
+
return words
|
22
|
+
.stream()
|
23
|
+
.collect(Collectors.toMap(Function.identity(), s -> search(s, grid)));
|
24
|
+
}
|
25
|
+
|
26
|
+
/*
|
27
|
+
* Search for a single word in the given grid.
|
28
|
+
*/
|
29
|
+
private Optional<WordLocation> search(final CharSequence word, final char[][] grid) {
|
30
|
+
final int nRows = grid.length;
|
31
|
+
final int nCols = grid[0].length;
|
32
|
+
|
33
|
+
// 1-indexed
|
34
|
+
for (int c = 1; c <= nCols; c++) {
|
35
|
+
for (int r = 1; r <= nRows; r++) {
|
36
|
+
final Optional<WordLocation> wordLocation = search(word, grid, new Pair(c, r));
|
37
|
+
if (wordLocation.isPresent()) return wordLocation;
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
return Optional.empty();
|
42
|
+
}
|
43
|
+
|
44
|
+
/*
|
45
|
+
* Search for a single word starting at a given coordinate within the given grid.
|
46
|
+
*/
|
47
|
+
private Optional<WordLocation> search(final CharSequence word, final char[][] grid, final Pair startCoord) {
|
48
|
+
if (grid[startCoord.getY() - 1][startCoord.getX() - 1] != word.charAt(0)) return Optional.empty();
|
49
|
+
|
50
|
+
for (final Pair direction : DIRECTIONS) {
|
51
|
+
final Optional<WordLocation> wordLocation = check(word, grid, startCoord, direction);
|
52
|
+
if (wordLocation.isPresent()) return wordLocation;
|
53
|
+
}
|
54
|
+
|
55
|
+
return Optional.empty();
|
56
|
+
}
|
57
|
+
|
58
|
+
/*
|
59
|
+
* Check whether a single word starts at a given coordinate and is aligned in a given direction within the given
|
60
|
+
* grid.
|
61
|
+
*/
|
62
|
+
private Optional<WordLocation> check(
|
63
|
+
final CharSequence word,
|
64
|
+
final char[][] grid,
|
65
|
+
final Pair startCoord,
|
66
|
+
final Pair direction) {
|
67
|
+
|
68
|
+
final int nRows = grid.length;
|
69
|
+
final int nCols = grid[0].length;
|
70
|
+
|
71
|
+
Pair nextCoord = startCoord;
|
72
|
+
|
73
|
+
for (int charIndex = 1; charIndex < word.length(); charIndex++) {
|
74
|
+
nextCoord = new Pair(
|
75
|
+
startCoord.getX() + charIndex * direction.getX(),
|
76
|
+
startCoord.getY() + charIndex * direction.getY());
|
77
|
+
|
78
|
+
if (nextCoord.getY() < 1 ||
|
79
|
+
nextCoord.getY() > nRows ||
|
80
|
+
nextCoord.getX() < 1 ||
|
81
|
+
nextCoord.getX() > nCols) {
|
82
|
+
|
83
|
+
return Optional.empty();
|
84
|
+
}
|
85
|
+
|
86
|
+
if (grid[nextCoord.getY() - 1][nextCoord.getX() - 1] != word.charAt(charIndex)) {
|
87
|
+
return Optional.empty();
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
return Optional.of(new WordLocation(startCoord, nextCoord));
|
92
|
+
}
|
93
|
+
|
94
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Pair {
|
2
|
+
|
3
|
+
private final int x;
|
4
|
+
|
5
|
+
private final int y;
|
6
|
+
|
7
|
+
Pair(final int x, final int y) {
|
8
|
+
this.y = y;
|
9
|
+
this.x = x;
|
10
|
+
}
|
11
|
+
|
12
|
+
int getX() {
|
13
|
+
return x;
|
14
|
+
}
|
15
|
+
|
16
|
+
int getY() {
|
17
|
+
return y;
|
18
|
+
}
|
19
|
+
|
20
|
+
@Override
|
21
|
+
public boolean equals(final Object o) {
|
22
|
+
if (this == o) return true;
|
23
|
+
if (o == null || getClass() != o.getClass()) return false;
|
24
|
+
|
25
|
+
Pair pair = (Pair) o;
|
26
|
+
|
27
|
+
return x == pair.x && y == pair.y;
|
28
|
+
}
|
29
|
+
|
30
|
+
@Override
|
31
|
+
public int hashCode() {
|
32
|
+
int result = x;
|
33
|
+
result = 31 * result + y;
|
34
|
+
return result;
|
35
|
+
}
|
36
|
+
|
37
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class WordLocation {
|
2
|
+
|
3
|
+
private final Pair startCoord;
|
4
|
+
|
5
|
+
private final Pair endCoord;
|
6
|
+
|
7
|
+
WordLocation(final Pair startCoord, final Pair endCoord) {
|
8
|
+
this.startCoord = startCoord;
|
9
|
+
this.endCoord = endCoord;
|
10
|
+
}
|
11
|
+
|
12
|
+
@Override
|
13
|
+
public boolean equals(final Object o) {
|
14
|
+
if (this == o) return true;
|
15
|
+
if (o == null || getClass() != o.getClass()) return false;
|
16
|
+
|
17
|
+
WordLocation that = (WordLocation) o;
|
18
|
+
|
19
|
+
return startCoord.equals(that.startCoord) && endCoord.equals(that.endCoord);
|
20
|
+
}
|
21
|
+
|
22
|
+
@Override
|
23
|
+
public int hashCode() {
|
24
|
+
int result = startCoord.hashCode();
|
25
|
+
result = 31 * result + endCoord.hashCode();
|
26
|
+
return result;
|
27
|
+
}
|
28
|
+
|
29
|
+
}
|
@@ -0,0 +1,278 @@
|
|
1
|
+
import org.junit.Before;
|
2
|
+
import org.junit.Test;
|
3
|
+
|
4
|
+
import java.util.*;
|
5
|
+
|
6
|
+
import static org.junit.Assert.assertEquals;
|
7
|
+
|
8
|
+
/*
|
9
|
+
* version: 1.0.0
|
10
|
+
*/
|
11
|
+
public class WordSearcherTest {
|
12
|
+
|
13
|
+
private WordSearcher wordSearcher;
|
14
|
+
|
15
|
+
@Before
|
16
|
+
public void setUp() {
|
17
|
+
wordSearcher = new WordSearcher();
|
18
|
+
}
|
19
|
+
|
20
|
+
@Test
|
21
|
+
public void testLocatesWordsWrittenLeftToRight() {
|
22
|
+
Map<String, Optional<WordLocation>> expectedLocations = new HashMap<>();
|
23
|
+
expectedLocations.put("clojure", Optional.of(new WordLocation(new Pair(1, 10), new Pair(7, 10))));
|
24
|
+
|
25
|
+
Set<String> searchWords = expectedLocations.keySet();
|
26
|
+
|
27
|
+
Map<String, Optional<WordLocation>> actualLocations = wordSearcher.search(
|
28
|
+
searchWords,
|
29
|
+
new char[][]{
|
30
|
+
{'j', 'e', 'f', 'b', 'l', 'p', 'e', 'p', 'r', 'e'},
|
31
|
+
{'c', 'a', 'm', 'd', 'c', 'i', 'm', 'g', 't', 'c'},
|
32
|
+
{'o', 'i', 'v', 'o', 'k', 'p', 'r', 'j', 's', 'm'},
|
33
|
+
{'p', 'b', 'w', 'a', 's', 'q', 'r', 'o', 'u', 'a'},
|
34
|
+
{'r', 'i', 'x', 'i', 'l', 'e', 'l', 'h', 'r', 's'},
|
35
|
+
{'w', 'o', 'l', 'c', 'q', 'l', 'i', 'r', 'p', 'c'},
|
36
|
+
{'s', 'c', 'r', 'e', 'e', 'a', 'u', 'm', 'g', 'r'},
|
37
|
+
{'a', 'l', 'x', 'h', 'p', 'b', 'u', 'r', 'y', 'i'},
|
38
|
+
{'j', 'a', 'l', 'a', 'y', 'c', 'a', 'l', 'm', 'p'},
|
39
|
+
{'c', 'l', 'o', 'j', 'u', 'r', 'e', 'r', 'm', 't'}
|
40
|
+
}
|
41
|
+
);
|
42
|
+
|
43
|
+
assertEquals(expectedLocations, actualLocations);
|
44
|
+
}
|
45
|
+
|
46
|
+
@Test
|
47
|
+
public void testLocatesWordsWrittenRightToLeft() {
|
48
|
+
Map<String, Optional<WordLocation>> expectedLocations = new HashMap<>();
|
49
|
+
expectedLocations.put("clojure", Optional.of(new WordLocation(new Pair(1, 10), new Pair(7, 10))));
|
50
|
+
expectedLocations.put("elixir", Optional.of(new WordLocation(new Pair(6, 5), new Pair(1, 5))));
|
51
|
+
|
52
|
+
Set<String> searchWords = expectedLocations.keySet();
|
53
|
+
|
54
|
+
Map<String, Optional<WordLocation>> actualLocations = wordSearcher.search(
|
55
|
+
searchWords,
|
56
|
+
new char[][]{
|
57
|
+
{'j', 'e', 'f', 'b', 'l', 'p', 'e', 'p', 'r', 'e'},
|
58
|
+
{'c', 'a', 'm', 'd', 'c', 'i', 'm', 'g', 't', 'c'},
|
59
|
+
{'o', 'i', 'v', 'o', 'k', 'p', 'r', 'j', 's', 'm'},
|
60
|
+
{'p', 'b', 'w', 'a', 's', 'q', 'r', 'o', 'u', 'a'},
|
61
|
+
{'r', 'i', 'x', 'i', 'l', 'e', 'l', 'h', 'r', 's'},
|
62
|
+
{'w', 'o', 'l', 'c', 'q', 'l', 'i', 'r', 'p', 'c'},
|
63
|
+
{'s', 'c', 'r', 'e', 'e', 'a', 'u', 'm', 'g', 'r'},
|
64
|
+
{'a', 'l', 'x', 'h', 'p', 'b', 'u', 'r', 'y', 'i'},
|
65
|
+
{'j', 'a', 'l', 'a', 'y', 'c', 'a', 'l', 'm', 'p'},
|
66
|
+
{'c', 'l', 'o', 'j', 'u', 'r', 'e', 'r', 'm', 't'}
|
67
|
+
}
|
68
|
+
);
|
69
|
+
|
70
|
+
assertEquals(expectedLocations, actualLocations);
|
71
|
+
}
|
72
|
+
|
73
|
+
@Test
|
74
|
+
public void testLocatesWordsWrittenTopToBottom() {
|
75
|
+
Map<String, Optional<WordLocation>> expectedLocations = new HashMap<>();
|
76
|
+
expectedLocations.put("clojure", Optional.of(new WordLocation(new Pair( 1, 10), new Pair( 7, 10))));
|
77
|
+
expectedLocations.put("elixir", Optional.of(new WordLocation(new Pair( 6, 5), new Pair( 1, 5))));
|
78
|
+
expectedLocations.put("ecmascript", Optional.of(new WordLocation(new Pair(10, 1), new Pair(10, 10))));
|
79
|
+
|
80
|
+
Set<String> searchWords = expectedLocations.keySet();
|
81
|
+
|
82
|
+
Map<String, Optional<WordLocation>> actualLocations = wordSearcher.search(
|
83
|
+
searchWords,
|
84
|
+
new char[][]{
|
85
|
+
{'j', 'e', 'f', 'b', 'l', 'p', 'e', 'p', 'r', 'e'},
|
86
|
+
{'c', 'a', 'm', 'd', 'c', 'i', 'm', 'g', 't', 'c'},
|
87
|
+
{'o', 'i', 'v', 'o', 'k', 'p', 'r', 'j', 's', 'm'},
|
88
|
+
{'p', 'b', 'w', 'a', 's', 'q', 'r', 'o', 'u', 'a'},
|
89
|
+
{'r', 'i', 'x', 'i', 'l', 'e', 'l', 'h', 'r', 's'},
|
90
|
+
{'w', 'o', 'l', 'c', 'q', 'l', 'i', 'r', 'p', 'c'},
|
91
|
+
{'s', 'c', 'r', 'e', 'e', 'a', 'u', 'm', 'g', 'r'},
|
92
|
+
{'a', 'l', 'x', 'h', 'p', 'b', 'u', 'r', 'y', 'i'},
|
93
|
+
{'j', 'a', 'l', 'a', 'y', 'c', 'a', 'l', 'm', 'p'},
|
94
|
+
{'c', 'l', 'o', 'j', 'u', 'r', 'e', 'r', 'm', 't'}
|
95
|
+
}
|
96
|
+
);
|
97
|
+
|
98
|
+
assertEquals(expectedLocations, actualLocations);
|
99
|
+
}
|
100
|
+
|
101
|
+
@Test
|
102
|
+
public void testLocatesWordsWrittenBottomToTop() {
|
103
|
+
Map<String, Optional<WordLocation>> expectedLocations = new HashMap<>();
|
104
|
+
expectedLocations.put("clojure", Optional.of(new WordLocation(new Pair( 1, 10), new Pair( 7, 10))));
|
105
|
+
expectedLocations.put("elixir", Optional.of(new WordLocation(new Pair( 6, 5), new Pair( 1, 5))));
|
106
|
+
expectedLocations.put("ecmascript", Optional.of(new WordLocation(new Pair(10, 1), new Pair(10, 10))));
|
107
|
+
expectedLocations.put("rust", Optional.of(new WordLocation(new Pair( 9, 5), new Pair( 9, 2))));
|
108
|
+
|
109
|
+
Set<String> searchWords = expectedLocations.keySet();
|
110
|
+
|
111
|
+
Map<String, Optional<WordLocation>> actualLocations = wordSearcher.search(
|
112
|
+
searchWords,
|
113
|
+
new char[][]{
|
114
|
+
{'j', 'e', 'f', 'b', 'l', 'p', 'e', 'p', 'r', 'e'},
|
115
|
+
{'c', 'a', 'm', 'd', 'c', 'i', 'm', 'g', 't', 'c'},
|
116
|
+
{'o', 'i', 'v', 'o', 'k', 'p', 'r', 'j', 's', 'm'},
|
117
|
+
{'p', 'b', 'w', 'a', 's', 'q', 'r', 'o', 'u', 'a'},
|
118
|
+
{'r', 'i', 'x', 'i', 'l', 'e', 'l', 'h', 'r', 's'},
|
119
|
+
{'w', 'o', 'l', 'c', 'q', 'l', 'i', 'r', 'p', 'c'},
|
120
|
+
{'s', 'c', 'r', 'e', 'e', 'a', 'u', 'm', 'g', 'r'},
|
121
|
+
{'a', 'l', 'x', 'h', 'p', 'b', 'u', 'r', 'y', 'i'},
|
122
|
+
{'j', 'a', 'l', 'a', 'y', 'c', 'a', 'l', 'm', 'p'},
|
123
|
+
{'c', 'l', 'o', 'j', 'u', 'r', 'e', 'r', 'm', 't'}});
|
124
|
+
|
125
|
+
assertEquals(expectedLocations, actualLocations);
|
126
|
+
}
|
127
|
+
|
128
|
+
@Test
|
129
|
+
public void testLocatesWordsWrittenTopLeftToBottomRight() {
|
130
|
+
Map<String, Optional<WordLocation>> expectedLocations = new HashMap<>();
|
131
|
+
expectedLocations.put("clojure", Optional.of(new WordLocation(new Pair( 1, 10), new Pair( 7, 10))));
|
132
|
+
expectedLocations.put("elixir", Optional.of(new WordLocation(new Pair( 6, 5), new Pair( 1, 5))));
|
133
|
+
expectedLocations.put("ecmascript", Optional.of(new WordLocation(new Pair(10, 1), new Pair(10, 10))));
|
134
|
+
expectedLocations.put("rust", Optional.of(new WordLocation(new Pair( 9, 5), new Pair( 9, 2))));
|
135
|
+
expectedLocations.put("java", Optional.of(new WordLocation(new Pair( 1, 1), new Pair( 4, 4))));
|
136
|
+
|
137
|
+
Set<String> searchWords = expectedLocations.keySet();
|
138
|
+
|
139
|
+
Map<String, Optional<WordLocation>> actualLocations = wordSearcher.search(
|
140
|
+
searchWords,
|
141
|
+
new char[][]{
|
142
|
+
{'j', 'e', 'f', 'b', 'l', 'p', 'e', 'p', 'r', 'e'},
|
143
|
+
{'c', 'a', 'm', 'd', 'c', 'i', 'm', 'g', 't', 'c'},
|
144
|
+
{'o', 'i', 'v', 'o', 'k', 'p', 'r', 'j', 's', 'm'},
|
145
|
+
{'p', 'b', 'w', 'a', 's', 'q', 'r', 'o', 'u', 'a'},
|
146
|
+
{'r', 'i', 'x', 'i', 'l', 'e', 'l', 'h', 'r', 's'},
|
147
|
+
{'w', 'o', 'l', 'c', 'q', 'l', 'i', 'r', 'p', 'c'},
|
148
|
+
{'s', 'c', 'r', 'e', 'e', 'a', 'u', 'm', 'g', 'r'},
|
149
|
+
{'a', 'l', 'x', 'h', 'p', 'b', 'u', 'r', 'y', 'i'},
|
150
|
+
{'j', 'a', 'l', 'a', 'y', 'c', 'a', 'l', 'm', 'p'},
|
151
|
+
{'c', 'l', 'o', 'j', 'u', 'r', 'e', 'r', 'm', 't'}});
|
152
|
+
|
153
|
+
assertEquals(expectedLocations, actualLocations);
|
154
|
+
}
|
155
|
+
|
156
|
+
@Test
|
157
|
+
public void testLocatesWordsWrittenBottomRightToTopLeft() {
|
158
|
+
Map<String, Optional<WordLocation>> expectedLocations = new HashMap<>();
|
159
|
+
expectedLocations.put("clojure", Optional.of(new WordLocation(new Pair( 1, 10), new Pair( 7, 10))));
|
160
|
+
expectedLocations.put("elixir", Optional.of(new WordLocation(new Pair( 6, 5), new Pair( 1, 5))));
|
161
|
+
expectedLocations.put("ecmascript", Optional.of(new WordLocation(new Pair(10, 1), new Pair(10, 10))));
|
162
|
+
expectedLocations.put("rust", Optional.of(new WordLocation(new Pair( 9, 5), new Pair( 9, 2))));
|
163
|
+
expectedLocations.put("java", Optional.of(new WordLocation(new Pair( 1, 1), new Pair( 4, 4))));
|
164
|
+
expectedLocations.put("lua", Optional.of(new WordLocation(new Pair( 8, 9), new Pair( 6, 7))));
|
165
|
+
|
166
|
+
Set<String> searchWords = expectedLocations.keySet();
|
167
|
+
|
168
|
+
Map<String, Optional<WordLocation>> actualLocations = wordSearcher.search(
|
169
|
+
searchWords,
|
170
|
+
new char[][]{
|
171
|
+
{'j', 'e', 'f', 'b', 'l', 'p', 'e', 'p', 'r', 'e'},
|
172
|
+
{'c', 'a', 'm', 'd', 'c', 'i', 'm', 'g', 't', 'c'},
|
173
|
+
{'o', 'i', 'v', 'o', 'k', 'p', 'r', 'j', 's', 'm'},
|
174
|
+
{'p', 'b', 'w', 'a', 's', 'q', 'r', 'o', 'u', 'a'},
|
175
|
+
{'r', 'i', 'x', 'i', 'l', 'e', 'l', 'h', 'r', 's'},
|
176
|
+
{'w', 'o', 'l', 'c', 'q', 'l', 'i', 'r', 'p', 'c'},
|
177
|
+
{'s', 'c', 'r', 'e', 'e', 'a', 'u', 'm', 'g', 'r'},
|
178
|
+
{'a', 'l', 'x', 'h', 'p', 'b', 'u', 'r', 'y', 'i'},
|
179
|
+
{'j', 'a', 'l', 'a', 'y', 'c', 'a', 'l', 'm', 'p'},
|
180
|
+
{'c', 'l', 'o', 'j', 'u', 'r', 'e', 'r', 'm', 't'}});
|
181
|
+
|
182
|
+
assertEquals(expectedLocations, actualLocations);
|
183
|
+
}
|
184
|
+
|
185
|
+
@Test
|
186
|
+
public void testLocatesWordsWrittenBottomLeftToTopRight() {
|
187
|
+
Map<String, Optional<WordLocation>> expectedLocations = new HashMap<>();
|
188
|
+
expectedLocations.put("clojure", Optional.of(new WordLocation(new Pair( 1, 10), new Pair( 7, 10))));
|
189
|
+
expectedLocations.put("elixir", Optional.of(new WordLocation(new Pair( 6, 5), new Pair( 1, 5))));
|
190
|
+
expectedLocations.put("ecmascript", Optional.of(new WordLocation(new Pair(10, 1), new Pair(10, 10))));
|
191
|
+
expectedLocations.put("rust", Optional.of(new WordLocation(new Pair( 9, 5), new Pair( 9, 2))));
|
192
|
+
expectedLocations.put("java", Optional.of(new WordLocation(new Pair( 1, 1), new Pair( 4, 4))));
|
193
|
+
expectedLocations.put("lua", Optional.of(new WordLocation(new Pair( 8, 9), new Pair( 6, 7))));
|
194
|
+
expectedLocations.put("lisp", Optional.of(new WordLocation(new Pair( 3, 6), new Pair( 6, 3))));
|
195
|
+
|
196
|
+
Set<String> searchWords = expectedLocations.keySet();
|
197
|
+
|
198
|
+
Map<String, Optional<WordLocation>> actualLocations = wordSearcher.search(
|
199
|
+
searchWords,
|
200
|
+
new char[][]{
|
201
|
+
{'j', 'e', 'f', 'b', 'l', 'p', 'e', 'p', 'r', 'e'},
|
202
|
+
{'c', 'a', 'm', 'd', 'c', 'i', 'm', 'g', 't', 'c'},
|
203
|
+
{'o', 'i', 'v', 'o', 'k', 'p', 'r', 'j', 's', 'm'},
|
204
|
+
{'p', 'b', 'w', 'a', 's', 'q', 'r', 'o', 'u', 'a'},
|
205
|
+
{'r', 'i', 'x', 'i', 'l', 'e', 'l', 'h', 'r', 's'},
|
206
|
+
{'w', 'o', 'l', 'c', 'q', 'l', 'i', 'r', 'p', 'c'},
|
207
|
+
{'s', 'c', 'r', 'e', 'e', 'a', 'u', 'm', 'g', 'r'},
|
208
|
+
{'a', 'l', 'x', 'h', 'p', 'b', 'u', 'r', 'y', 'i'},
|
209
|
+
{'j', 'a', 'l', 'a', 'y', 'c', 'a', 'l', 'm', 'p'},
|
210
|
+
{'c', 'l', 'o', 'j', 'u', 'r', 'e', 'r', 'm', 't'}});
|
211
|
+
|
212
|
+
assertEquals(expectedLocations, actualLocations);
|
213
|
+
}
|
214
|
+
|
215
|
+
@Test
|
216
|
+
public void testLocatesWordsWrittenTopRightToBottomLeft() {
|
217
|
+
Map<String, Optional<WordLocation>> expectedLocations = new HashMap<>();
|
218
|
+
expectedLocations.put("clojure", Optional.of(new WordLocation(new Pair( 1, 10), new Pair( 7, 10))));
|
219
|
+
expectedLocations.put("elixir", Optional.of(new WordLocation(new Pair( 6, 5), new Pair( 1, 5))));
|
220
|
+
expectedLocations.put("ecmascript", Optional.of(new WordLocation(new Pair(10, 1), new Pair(10, 10))));
|
221
|
+
expectedLocations.put("rust", Optional.of(new WordLocation(new Pair( 9, 5), new Pair( 9, 2))));
|
222
|
+
expectedLocations.put("java", Optional.of(new WordLocation(new Pair( 1, 1), new Pair( 4, 4))));
|
223
|
+
expectedLocations.put("lua", Optional.of(new WordLocation(new Pair( 8, 9), new Pair( 6, 7))));
|
224
|
+
expectedLocations.put("lisp", Optional.of(new WordLocation(new Pair( 3, 6), new Pair( 6, 3))));
|
225
|
+
expectedLocations.put("ruby", Optional.of(new WordLocation(new Pair( 8, 6), new Pair( 5, 9))));
|
226
|
+
|
227
|
+
Set<String> searchWords = expectedLocations.keySet();
|
228
|
+
|
229
|
+
Map<String, Optional<WordLocation>> actualLocations = wordSearcher.search(
|
230
|
+
searchWords,
|
231
|
+
new char[][]{
|
232
|
+
{'j', 'e', 'f', 'b', 'l', 'p', 'e', 'p', 'r', 'e'},
|
233
|
+
{'c', 'a', 'm', 'd', 'c', 'i', 'm', 'g', 't', 'c'},
|
234
|
+
{'o', 'i', 'v', 'o', 'k', 'p', 'r', 'j', 's', 'm'},
|
235
|
+
{'p', 'b', 'w', 'a', 's', 'q', 'r', 'o', 'u', 'a'},
|
236
|
+
{'r', 'i', 'x', 'i', 'l', 'e', 'l', 'h', 'r', 's'},
|
237
|
+
{'w', 'o', 'l', 'c', 'q', 'l', 'i', 'r', 'p', 'c'},
|
238
|
+
{'s', 'c', 'r', 'e', 'e', 'a', 'u', 'm', 'g', 'r'},
|
239
|
+
{'a', 'l', 'x', 'h', 'p', 'b', 'u', 'r', 'y', 'i'},
|
240
|
+
{'j', 'a', 'l', 'a', 'y', 'c', 'a', 'l', 'm', 'p'},
|
241
|
+
{'c', 'l', 'o', 'j', 'u', 'r', 'e', 'r', 'm', 't'}});
|
242
|
+
|
243
|
+
assertEquals(expectedLocations, actualLocations);
|
244
|
+
}
|
245
|
+
|
246
|
+
@Test
|
247
|
+
public void testFailsToLocateAWordsThatIsNotInThePuzzle() {
|
248
|
+
Map<String, Optional<WordLocation>> expectedLocations = new HashMap<>();
|
249
|
+
expectedLocations.put("clojure", Optional.of(new WordLocation(new Pair( 1, 10), new Pair( 7, 10))));
|
250
|
+
expectedLocations.put("elixir", Optional.of(new WordLocation(new Pair( 6, 5), new Pair( 1, 5))));
|
251
|
+
expectedLocations.put("ecmascript", Optional.of(new WordLocation(new Pair(10, 1), new Pair(10, 10))));
|
252
|
+
expectedLocations.put("rust", Optional.of(new WordLocation(new Pair( 9, 5), new Pair( 9, 2))));
|
253
|
+
expectedLocations.put("java", Optional.of(new WordLocation(new Pair( 1, 1), new Pair( 4, 4))));
|
254
|
+
expectedLocations.put("lua", Optional.of(new WordLocation(new Pair( 8, 9), new Pair( 6, 7))));
|
255
|
+
expectedLocations.put("lisp", Optional.of(new WordLocation(new Pair( 3, 6), new Pair( 6, 3))));
|
256
|
+
expectedLocations.put("ruby", Optional.of(new WordLocation(new Pair( 8, 6), new Pair( 5, 9))));
|
257
|
+
expectedLocations.put("haskell", Optional.empty());
|
258
|
+
|
259
|
+
Set<String> searchWords = expectedLocations.keySet();
|
260
|
+
|
261
|
+
Map<String, Optional<WordLocation>> actualLocations = wordSearcher.search(
|
262
|
+
searchWords,
|
263
|
+
new char[][]{
|
264
|
+
{'j', 'e', 'f', 'b', 'l', 'p', 'e', 'p', 'r', 'e'},
|
265
|
+
{'c', 'a', 'm', 'd', 'c', 'i', 'm', 'g', 't', 'c'},
|
266
|
+
{'o', 'i', 'v', 'o', 'k', 'p', 'r', 'j', 's', 'm'},
|
267
|
+
{'p', 'b', 'w', 'a', 's', 'q', 'r', 'o', 'u', 'a'},
|
268
|
+
{'r', 'i', 'x', 'i', 'l', 'e', 'l', 'h', 'r', 's'},
|
269
|
+
{'w', 'o', 'l', 'c', 'q', 'l', 'i', 'r', 'p', 'c'},
|
270
|
+
{'s', 'c', 'r', 'e', 'e', 'a', 'u', 'm', 'g', 'r'},
|
271
|
+
{'a', 'l', 'x', 'h', 'p', 'b', 'u', 'r', 'y', 'i'},
|
272
|
+
{'j', 'a', 'l', 'a', 'y', 'c', 'a', 'l', 'm', 'p'},
|
273
|
+
{'c', 'l', 'o', 'j', 'u', 'r', 'e', 'r', 'm', 't'}});
|
274
|
+
|
275
|
+
assertEquals(expectedLocations, actualLocations);
|
276
|
+
}
|
277
|
+
|
278
|
+
}
|
data/tracks/scala/README.md
CHANGED
@@ -17,18 +17,15 @@ suite generators are named in the form `ProblemNameTestGenerator.scala`. Where
|
|
17
17
|
|
18
18
|
[the shared problem metadata](https://github.com/exercism/x-common).
|
19
19
|
|
20
|
-
For example, take a look at the `
|
20
|
+
For example, take a look at the `bob/canonical-data.json` file in the x-common repository, as well
|
21
21
|
as the following files in the xscala repository:
|
22
22
|
|
23
|
-
1. `testgen/src/main/scala/
|
24
|
-
1. `exercises/
|
23
|
+
1. `testgen/src/main/scala/BobTestGenerator.scala` - test suite generator for bob
|
24
|
+
1. `exercises/bob/src/test/scala/BobTest.scala`- generated test suite
|
25
25
|
|
26
|
-
Since a generator was used, the`exercises/
|
26
|
+
Since a generator was used, the`exercises/bob/src/test/scala/BobTest.scala` will never be edited directly.
|
27
27
|
If there's a missing test case, then additional inputs/outputs should be submitted to the x-common repository.
|
28
28
|
|
29
|
-
Note that the the test suite generators do not format the test suite source code. The generated test suite should be
|
30
|
-
formatted before being submitted.
|
31
|
-
|
32
29
|
When submitting new exercises we encourage that a test suite generator and generated test suite is
|
33
30
|
included.
|
34
31
|
|
data/tracks/scala/config.json
CHANGED
@@ -95,16 +95,7 @@
|
|
95
95
|
"Logic",
|
96
96
|
"Transforming"
|
97
97
|
]
|
98
|
-
},
|
99
|
-
{
|
100
|
-
"slug":"perfect-numbers",
|
101
|
-
"difficulty":2,
|
102
|
-
"topics":[
|
103
|
-
"Enumerations",
|
104
|
-
"Integers",
|
105
|
-
"Mathematics"
|
106
|
-
]
|
107
|
-
},
|
98
|
+
},
|
108
99
|
{
|
109
100
|
"slug":"hamming",
|
110
101
|
"difficulty":3,
|
@@ -185,6 +176,16 @@
|
|
185
176
|
"Mathematics"
|
186
177
|
]
|
187
178
|
},
|
179
|
+
{
|
180
|
+
"slug":"perfect-numbers",
|
181
|
+
"difficulty":3,
|
182
|
+
"topics":[
|
183
|
+
"Discriminated unions",
|
184
|
+
"Enumerations",
|
185
|
+
"Integers",
|
186
|
+
"Mathematics"
|
187
|
+
]
|
188
|
+
},
|
188
189
|
{
|
189
190
|
"slug":"binary-search",
|
190
191
|
"difficulty":3,
|
@@ -1,17 +1,21 @@
|
|
1
1
|
import NumberType.NumberType
|
2
2
|
|
3
3
|
object PerfectNumbers {
|
4
|
-
def classify(n: Int): NumberType = {
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
def classify(n: Int): Either[String, NumberType] = {
|
5
|
+
if (n <= 0)
|
6
|
+
Left("Classification is only possible for natural numbers.")
|
7
|
+
else {
|
8
|
+
val sumOfFactors
|
9
|
+
= (1 until n)
|
10
|
+
.foldLeft(0)((acc, i) => if (n % i == 0) acc + i else acc)
|
8
11
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
if (sumOfFactors < n)
|
13
|
+
Right(NumberType.Deficient)
|
14
|
+
else if (sumOfFactors > n)
|
15
|
+
Right(NumberType.Abundant)
|
16
|
+
else
|
17
|
+
Right(NumberType.Perfect)
|
18
|
+
}
|
15
19
|
}
|
16
20
|
}
|
17
21
|
|
@@ -1,62 +1,69 @@
|
|
1
|
-
import org.scalatest.{
|
1
|
+
import org.scalatest.{Matchers, FunSuite}
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
/** @version 1.0.1 */
|
4
|
+
class PerfectNumbersTest extends FunSuite with Matchers {
|
5
|
+
|
6
|
+
test("Smallest perfect number is classified correctly") {
|
7
|
+
PerfectNumbers.classify(6) should be (Right(NumberType.Perfect))
|
8
|
+
}
|
9
|
+
|
10
|
+
test("Medium perfect number is classified correctly") {
|
11
|
+
pending
|
12
|
+
PerfectNumbers.classify(28) should be (Right(NumberType.Perfect))
|
6
13
|
}
|
7
14
|
|
8
|
-
|
15
|
+
test("Large perfect number is classified correctly") {
|
9
16
|
pending
|
10
|
-
PerfectNumbers.classify(
|
17
|
+
PerfectNumbers.classify(33550336) should be (Right(NumberType.Perfect))
|
11
18
|
}
|
12
19
|
|
13
|
-
|
20
|
+
test("Smallest abundant number is classified correctly") {
|
14
21
|
pending
|
15
|
-
PerfectNumbers.classify(
|
22
|
+
PerfectNumbers.classify(12) should be (Right(NumberType.Abundant))
|
16
23
|
}
|
17
24
|
|
18
|
-
|
25
|
+
test("Medium abundant number is classified correctly") {
|
19
26
|
pending
|
20
|
-
PerfectNumbers.classify(
|
27
|
+
PerfectNumbers.classify(30) should be (Right(NumberType.Abundant))
|
21
28
|
}
|
22
29
|
|
23
|
-
|
30
|
+
test("Large abundant number is classified correctly") {
|
24
31
|
pending
|
25
|
-
PerfectNumbers.classify(
|
32
|
+
PerfectNumbers.classify(33550335) should be (Right(NumberType.Abundant))
|
26
33
|
}
|
27
34
|
|
28
|
-
|
35
|
+
test("Smallest prime deficient number is classified correctly") {
|
29
36
|
pending
|
30
|
-
PerfectNumbers.classify(
|
37
|
+
PerfectNumbers.classify(2) should be (Right(NumberType.Deficient))
|
31
38
|
}
|
32
39
|
|
33
|
-
|
40
|
+
test("Smallest non-prime deficient number is classified correctly") {
|
34
41
|
pending
|
35
|
-
PerfectNumbers.classify(
|
42
|
+
PerfectNumbers.classify(4) should be (Right(NumberType.Deficient))
|
36
43
|
}
|
37
44
|
|
38
|
-
|
45
|
+
test("Medium deficient number is classified correctly") {
|
39
46
|
pending
|
40
|
-
PerfectNumbers.classify(
|
47
|
+
PerfectNumbers.classify(32) should be (Right(NumberType.Deficient))
|
41
48
|
}
|
42
49
|
|
43
|
-
|
50
|
+
test("Large deficient number is classified correctly") {
|
44
51
|
pending
|
45
|
-
PerfectNumbers.classify(
|
52
|
+
PerfectNumbers.classify(33550337) should be (Right(NumberType.Deficient))
|
46
53
|
}
|
47
54
|
|
48
|
-
|
55
|
+
test("Edge case (no factors other than itself) is classified correctly") {
|
49
56
|
pending
|
50
|
-
PerfectNumbers.classify(
|
57
|
+
PerfectNumbers.classify(1) should be (Right(NumberType.Deficient))
|
51
58
|
}
|
52
59
|
|
53
|
-
|
60
|
+
test("Zero is rejected (not a natural number)") {
|
54
61
|
pending
|
55
|
-
PerfectNumbers.classify(
|
62
|
+
PerfectNumbers.classify(0) should be (Left("Classification is only possible for natural numbers."))
|
56
63
|
}
|
57
64
|
|
58
|
-
|
65
|
+
test("Negative integer is rejected (not a natural number)") {
|
59
66
|
pending
|
60
|
-
PerfectNumbers.classify(
|
67
|
+
PerfectNumbers.classify(-1) should be (Left("Classification is only possible for natural numbers."))
|
61
68
|
}
|
62
|
-
}
|
69
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import java.io.File
|
2
|
+
|
3
|
+
import testgen.TestSuiteBuilder.{toString, _}
|
4
|
+
import testgen._
|
5
|
+
|
6
|
+
object PerfectNumbersTestGenerator {
|
7
|
+
def main(args: Array[String]): Unit = {
|
8
|
+
val file = new File("src/main/resources/perfect-numbers.json")
|
9
|
+
|
10
|
+
def toEnumStr(str: String): String = {
|
11
|
+
str match {
|
12
|
+
case "perfect" => "NumberType.Perfect"
|
13
|
+
case "abundant" => "NumberType.Abundant"
|
14
|
+
case "deficient" => "NumberType.Deficient"
|
15
|
+
case _ => throw new IllegalStateException("Invalid NumberType -" + str)
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
def toString(expected: CanonicalDataParser.Expected): String = {
|
20
|
+
expected match {
|
21
|
+
case Left(error) => s"Left(${TestSuiteBuilder.toString(error)})"
|
22
|
+
case Right(exp) => s"Right(${toEnumStr(exp.toString)})"
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
def fromLabeledTest(argNames: String*): ToTestCaseData =
|
27
|
+
withLabeledTest { sut =>
|
28
|
+
labeledTest =>
|
29
|
+
val args = sutArgs(labeledTest.result, argNames: _*)
|
30
|
+
val property = labeledTest.property
|
31
|
+
val sutCall =
|
32
|
+
s"""PerfectNumbers.$property($args)"""
|
33
|
+
val expected = toString(labeledTest.expected)
|
34
|
+
TestCaseData(labeledTest.description, sutCall, expected)
|
35
|
+
}
|
36
|
+
|
37
|
+
val code = TestSuiteBuilder.build(file, fromLabeledTest("input"))
|
38
|
+
println(s"-------------")
|
39
|
+
println(code)
|
40
|
+
println(s"-------------")
|
41
|
+
}
|
42
|
+
}
|
@@ -66,7 +66,7 @@ object Exercise {
|
|
66
66
|
private def flattenCases(cases: Cases): Cases =
|
67
67
|
cases match {
|
68
68
|
case Seq() => Seq()
|
69
|
-
case (ltg: LabeledTestGroup) +: xs => ltg.cases ++ flattenCases(xs)
|
69
|
+
case (ltg: LabeledTestGroup) +: xs => flattenCases(ltg.cases) ++ flattenCases(xs)
|
70
70
|
case (lt: LabeledTest) +: xs => lt +: flattenCases(xs)
|
71
71
|
}
|
72
72
|
}
|
@@ -86,7 +86,7 @@ object TestSuiteBuilder {
|
|
86
86
|
private def toString(expected: CanonicalDataParser.Expected): String =
|
87
87
|
expected.fold(error => s"Left(${toString(error)})", toString)
|
88
88
|
|
89
|
-
|
89
|
+
def toString(any: Any): String = {
|
90
90
|
def quote(str: String): String =
|
91
91
|
if ("\"\n" exists (str.contains(_:Char))) "\"\"\"" else "\""
|
92
92
|
|
@@ -98,7 +98,7 @@ object TestSuiteBuilder {
|
|
98
98
|
}
|
99
99
|
}
|
100
100
|
|
101
|
-
def
|
101
|
+
def writeToFile(text: String, dest: File): Unit = {
|
102
102
|
val fileWriter = new FileWriter(dest)
|
103
103
|
try { fileWriter.write(text) } finally fileWriter.close
|
104
104
|
}
|
@@ -73,8 +73,7 @@
|
|
73
73
|
{
|
74
74
|
"slug": "allergies",
|
75
75
|
"difficulty": 1,
|
76
|
-
"topics": [
|
77
|
-
]
|
76
|
+
"topics": []
|
78
77
|
},
|
79
78
|
{
|
80
79
|
"slug": "scrabble-score",
|
@@ -85,6 +84,11 @@
|
|
85
84
|
"slug": "triangle",
|
86
85
|
"difficulty": 1,
|
87
86
|
"topics": []
|
87
|
+
},
|
88
|
+
{
|
89
|
+
"slug": "etl",
|
90
|
+
"difficulty": 1,
|
91
|
+
"topics": []
|
88
92
|
}
|
89
93
|
],
|
90
94
|
"deprecated": [],
|
@@ -0,0 +1,27 @@
|
|
1
|
+
"
|
2
|
+
" Version: 1.0.0
|
3
|
+
"
|
4
|
+
|
5
|
+
Before:
|
6
|
+
unlet! input expected
|
7
|
+
|
8
|
+
Execute (a single letter):
|
9
|
+
let input = {'1': ['A']}
|
10
|
+
let expected = {'a': 1}
|
11
|
+
AssertEqual expected, Transform(input)
|
12
|
+
|
13
|
+
Execute (single score with multiple letters):
|
14
|
+
let input = {'1': ['A', 'E', 'I', 'O', 'U']}
|
15
|
+
let expected = {'a': 1, 'e': 1, 'i': 1, 'u': 1, 'o': 1}
|
16
|
+
AssertEqual expected, Transform(input)
|
17
|
+
|
18
|
+
Execute (multiple scores with multiple letters):
|
19
|
+
let input = {'1': ['A', 'E'], '2': ['D', 'G']}
|
20
|
+
let expected = {'a': 1, 'd': 2, 'e': 1, 'g': 2}
|
21
|
+
AssertEqual expected, Transform(input)
|
22
|
+
|
23
|
+
Execute (multiple scores with differing numbers of letters):
|
24
|
+
let input = {'1': ['A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T'], '2': ['D', 'G'], '3': ['B', 'C', 'M', 'P'], '4': ['F', 'H', 'V', 'W', 'Y'], '5': ['K'], '8': ['J', 'X'], '10': ['Q', 'Z']}
|
25
|
+
let expected = {'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10}
|
26
|
+
AssertEqual expected, Transform(input)
|
27
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
"
|
2
|
+
" We are going to do the Transform step of an Extract-Transform-Load.
|
3
|
+
"
|
4
|
+
" Example:
|
5
|
+
"
|
6
|
+
" :echo Transform({'1': ['a', 'b'], '2': ['c']})
|
7
|
+
" {'a': 1, 'b': 1, 'c': 2}
|
8
|
+
"
|
9
|
+
|
10
|
+
function! Transform(scores) abort
|
11
|
+
" your code goes here
|
12
|
+
endfunction
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trackler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.0.
|
4
|
+
version: 2.1.0.29
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Katrina Owen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-06-
|
11
|
+
date: 2017-06-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubyzip
|
@@ -4743,6 +4743,13 @@ files:
|
|
4743
4743
|
- tracks/java/exercises/word-count/src/example/java/WordCount.java
|
4744
4744
|
- tracks/java/exercises/word-count/src/main/java/WordCount.java
|
4745
4745
|
- tracks/java/exercises/word-count/src/test/java/WordCountTest.java
|
4746
|
+
- tracks/java/exercises/word-search/build.gradle
|
4747
|
+
- tracks/java/exercises/word-search/src/example/java/Pair.java
|
4748
|
+
- tracks/java/exercises/word-search/src/example/java/WordLocation.java
|
4749
|
+
- tracks/java/exercises/word-search/src/example/java/WordSearcher.java
|
4750
|
+
- tracks/java/exercises/word-search/src/main/java/Pair.java
|
4751
|
+
- tracks/java/exercises/word-search/src/main/java/WordLocation.java
|
4752
|
+
- tracks/java/exercises/word-search/src/test/java/WordSearcherTest.java
|
4746
4753
|
- tracks/java/exercises/wordy/build.gradle
|
4747
4754
|
- tracks/java/exercises/wordy/src/example/java/WordProblemSolver.java
|
4748
4755
|
- tracks/java/exercises/wordy/src/main/java/WordProblemSolver.java
|
@@ -8321,7 +8328,6 @@ files:
|
|
8321
8328
|
- tracks/scala/exercises/pascals-triangle/src/test/scala/PascalsTriangleTest.scala
|
8322
8329
|
- tracks/scala/exercises/perfect-numbers/build.sbt
|
8323
8330
|
- tracks/scala/exercises/perfect-numbers/example.scala
|
8324
|
-
- tracks/scala/exercises/perfect-numbers/src/main/scala/PerfectNumbers.scala
|
8325
8331
|
- tracks/scala/exercises/perfect-numbers/src/test/scala/PerfectNumbersTest.scala
|
8326
8332
|
- tracks/scala/exercises/phone-number/HINTS.md
|
8327
8333
|
- tracks/scala/exercises/phone-number/build.sbt
|
@@ -8484,6 +8490,7 @@ files:
|
|
8484
8490
|
- tracks/scala/testgen/src/main/scala/LeapTestGenerator.scala
|
8485
8491
|
- tracks/scala/testgen/src/main/scala/NucleotideCountTestGenerator.scala
|
8486
8492
|
- tracks/scala/testgen/src/main/scala/PangramsTestGenerator.scala
|
8493
|
+
- tracks/scala/testgen/src/main/scala/PerfectNumbersTestGenerator.scala
|
8487
8494
|
- tracks/scala/testgen/src/main/scala/RailFenceCipherTestGenerator.scala
|
8488
8495
|
- tracks/scala/testgen/src/main/scala/RaindropsTestGenerator.scala
|
8489
8496
|
- tracks/scala/testgen/src/main/scala/SumOfMultiplesTestGenerator.scala
|
@@ -9275,6 +9282,9 @@ files:
|
|
9275
9282
|
- tracks/vimscript/exercises/difference-of-squares/difference_of_squares.vader
|
9276
9283
|
- tracks/vimscript/exercises/difference-of-squares/difference_of_squares.vim
|
9277
9284
|
- tracks/vimscript/exercises/difference-of-squares/example.vim
|
9285
|
+
- tracks/vimscript/exercises/etl/etl.vader
|
9286
|
+
- tracks/vimscript/exercises/etl/etl.vim
|
9287
|
+
- tracks/vimscript/exercises/etl/example.vim
|
9278
9288
|
- tracks/vimscript/exercises/hamming/example.vim
|
9279
9289
|
- tracks/vimscript/exercises/hamming/hamming.vader
|
9280
9290
|
- tracks/vimscript/exercises/hamming/hamming.vim
|
File without changes
|