trackler 2.1.0.0 → 2.1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/common/exercises/connect/description.md +2 -1
  3. data/common/exercises/crypto-square/canonical-data.json +2 -2
  4. data/common/exercises/two-bucket/canonical-data.json +27 -1
  5. data/lib/trackler/version.rb +1 -1
  6. data/tracks/c/exercises/perfect-numbers/src/example.c +8 -4
  7. data/tracks/clojure/config.json +5 -0
  8. data/tracks/clojure/exercises/secret-handshake/project.clj +4 -0
  9. data/tracks/clojure/exercises/secret-handshake/src/example.clj +19 -0
  10. data/tracks/clojure/exercises/secret-handshake/test/secret_handshake_test.clj +55 -0
  11. data/tracks/cpp/.travis.yml +4 -3
  12. data/tracks/cpp/README.md +1 -1
  13. data/tracks/cpp/config.json +171 -67
  14. data/tracks/cpp/docs/ABOUT.md +2 -2
  15. data/tracks/cpp/docs/INSTALLATION.md +22 -28
  16. data/tracks/cpp/docs/TESTS.md +1 -1
  17. data/tracks/cpp/exercises/anagram/CMakeLists.txt +2 -9
  18. data/tracks/cpp/exercises/beer-song/CMakeLists.txt +2 -9
  19. data/tracks/cpp/exercises/binary/CMakeLists.txt +2 -9
  20. data/tracks/cpp/exercises/bob/CMakeLists.txt +2 -9
  21. data/tracks/cpp/exercises/clock/CMakeLists.txt +2 -9
  22. data/tracks/cpp/exercises/clock/clock_test.cpp +188 -64
  23. data/tracks/cpp/exercises/clock/example.cpp +17 -12
  24. data/tracks/cpp/exercises/clock/example.h +1 -0
  25. data/tracks/cpp/exercises/crypto-square/CMakeLists.txt +2 -9
  26. data/tracks/cpp/exercises/difference-of-squares/CMakeLists.txt +2 -9
  27. data/tracks/cpp/exercises/etl/CMakeLists.txt +2 -9
  28. data/tracks/cpp/exercises/etl/etl_test.cpp +5 -5
  29. data/tracks/cpp/exercises/food-chain/CMakeLists.txt +2 -9
  30. data/tracks/cpp/exercises/gigasecond/CMakeLists.txt +2 -9
  31. data/tracks/cpp/exercises/gigasecond/example.cpp +2 -6
  32. data/tracks/cpp/exercises/gigasecond/example.h +2 -2
  33. data/tracks/cpp/exercises/gigasecond/gigasecond_test.cpp +26 -8
  34. data/tracks/cpp/exercises/grade-school/CMakeLists.txt +2 -9
  35. data/tracks/cpp/exercises/grade-school/grade_school_test.cpp +5 -6
  36. data/tracks/cpp/exercises/grains/CMakeLists.txt +2 -9
  37. data/tracks/cpp/exercises/hamming/CMakeLists.txt +2 -9
  38. data/tracks/cpp/exercises/hello-world/CMakeLists.txt +2 -9
  39. data/tracks/cpp/exercises/hexadecimal/CMakeLists.txt +2 -9
  40. data/tracks/cpp/exercises/leap/CMakeLists.txt +2 -9
  41. data/tracks/cpp/exercises/meetup/CMakeLists.txt +2 -9
  42. data/tracks/cpp/exercises/meetup/meetup_test.cpp +1 -1
  43. data/tracks/cpp/exercises/nth-prime/CMakeLists.txt +2 -9
  44. data/tracks/cpp/exercises/nucleotide-count/CMakeLists.txt +2 -9
  45. data/tracks/cpp/exercises/nucleotide-count/nucleotide_count_test.cpp +3 -4
  46. data/tracks/cpp/exercises/phone-number/CMakeLists.txt +2 -9
  47. data/tracks/cpp/exercises/prime-factors/CMakeLists.txt +2 -9
  48. data/tracks/cpp/exercises/queen-attack/CMakeLists.txt +2 -9
  49. data/tracks/cpp/exercises/raindrops/CMakeLists.txt +2 -9
  50. data/tracks/cpp/exercises/rna-transcription/CMakeLists.txt +2 -9
  51. data/tracks/cpp/exercises/robot-name/CMakeLists.txt +2 -9
  52. data/tracks/cpp/exercises/roman-numerals/CMakeLists.txt +2 -9
  53. data/tracks/cpp/exercises/say/CMakeLists.txt +2 -9
  54. data/tracks/cpp/exercises/scrabble-score/CMakeLists.txt +2 -9
  55. data/tracks/cpp/exercises/series/CMakeLists.txt +2 -9
  56. data/tracks/cpp/exercises/series/series_test.cpp +11 -11
  57. data/tracks/cpp/exercises/sieve/CMakeLists.txt +2 -9
  58. data/tracks/cpp/exercises/space-age/CMakeLists.txt +2 -9
  59. data/tracks/cpp/exercises/sum-of-multiples/CMakeLists.txt +2 -9
  60. data/tracks/cpp/exercises/triangle/CMakeLists.txt +2 -9
  61. data/tracks/cpp/exercises/trinary/CMakeLists.txt +2 -9
  62. data/tracks/cpp/exercises/word-count/CMakeLists.txt +2 -9
  63. data/tracks/cpp/exercises/word-count/word_count_test.cpp +14 -15
  64. data/tracks/go/README.md +27 -13
  65. data/tracks/go/config.json +1 -0
  66. data/tracks/go/exercises/connect/.meta/gen.go +1 -3
  67. data/tracks/go/exercises/connect/cases_test.go +2 -1
  68. data/tracks/go/exercises/custom-set/.meta/gen.go +122 -101
  69. data/tracks/go/exercises/custom-set/cases_test.go +13 -4
  70. data/tracks/go/exercises/custom-set/custom_set_test.go +2 -2
  71. data/tracks/go/exercises/hamming/.meta/gen.go +1 -3
  72. data/tracks/go/exercises/hamming/cases_test.go +7 -1
  73. data/tracks/go/exercises/hamming/example.go +1 -1
  74. data/tracks/go/exercises/hamming/hamming_test.go +1 -1
  75. data/tracks/go/exercises/hello-world/{hello_example_test.go → example_helloworld_test.go} +0 -0
  76. data/tracks/go/exercises/house/house_test.go +8 -8
  77. data/tracks/go/exercises/meetup/.meta/gen.go +1 -3
  78. data/tracks/go/exercises/meetup/cases_test.go +2 -1
  79. data/tracks/go/exercises/palindrome-products/example.go +1 -1
  80. data/tracks/go/exercises/palindrome-products/palindrome_products_test.go +1 -1
  81. data/tracks/go/exercises/pascals-triangle/pascals_triangle_test.go +24 -4
  82. data/tracks/go/exercises/rna-transcription/.meta/gen.go +1 -3
  83. data/tracks/go/exercises/rna-transcription/cases_test.go +2 -1
  84. data/tracks/go/exercises/roman-numerals/.meta/gen.go +1 -3
  85. data/tracks/go/exercises/roman-numerals/cases_test.go +2 -1
  86. data/tracks/go/exercises/roman-numerals/example.go +1 -1
  87. data/tracks/go/exercises/transpose/.meta/gen.go +1 -3
  88. data/tracks/go/exercises/transpose/cases_test.go +2 -1
  89. data/tracks/go/exercises/transpose/transpose_test.go +5 -0
  90. data/tracks/go/exercises/word-count/.meta/gen.go +1 -3
  91. data/tracks/go/exercises/word-count/cases_test.go +2 -1
  92. data/tracks/go/gen/gen.go +3 -2
  93. data/tracks/java/config.json +5 -0
  94. data/tracks/java/exercises/saddle-points/build.gradle +17 -0
  95. data/tracks/java/exercises/saddle-points/src/example/java/Matrix.java +44 -0
  96. data/tracks/java/exercises/saddle-points/src/example/java/MatrixCoordinate.java +31 -0
  97. data/tracks/java/exercises/saddle-points/src/main/java/Matrix.java +5 -0
  98. data/tracks/java/exercises/saddle-points/src/main/java/MatrixCoordinate.java +31 -0
  99. data/tracks/java/exercises/saddle-points/src/test/java/MatrixTest.java +82 -0
  100. data/tracks/java/exercises/settings.gradle +1 -0
  101. data/tracks/javascript/.travis.yml +3 -1
  102. data/tracks/javascript/Makefile +2 -8
  103. data/tracks/javascript/SETUP.md +1 -2
  104. data/tracks/javascript/docs/INSTALLATION.md +3 -4
  105. data/tracks/javascript/docs/TESTS.md +14 -26
  106. data/tracks/javascript/exercises/hamming/example.js +7 -11
  107. data/tracks/javascript/exercises/hello-world/HINTS.md +3 -3
  108. data/tracks/javascript/exercises/robot-simulator/example.js +72 -73
  109. data/tracks/perl6/config.json +5 -0
  110. data/tracks/perl6/exercises/clock/Clock.pm6 +4 -0
  111. data/tracks/perl6/exercises/clock/Example.pm6 +12 -0
  112. data/tracks/perl6/exercises/clock/clock.t +534 -0
  113. data/tracks/perl6/exercises/clock/example.yaml +16 -0
  114. data/tracks/perl6/exercises/robot-name/Example.pm +11 -4
  115. data/tracks/php/exercises/hello-world/hello-world.php +1 -1
  116. data/tracks/php/exercises/hello-world/hello-world_test.php +1 -11
  117. data/tracks/php/exercises/robot-name/robot-name_test.php +1 -0
  118. data/tracks/purescript/config.json +7 -0
  119. data/tracks/purescript/exercises/largest-series-product/bower.json +16 -0
  120. data/tracks/purescript/exercises/largest-series-product/examples/src/LargestSeriesProduct.purs +31 -0
  121. data/tracks/purescript/exercises/largest-series-product/src/LargestSeriesProduct.purs +3 -0
  122. data/tracks/purescript/exercises/largest-series-product/test/Main.purs +73 -0
  123. data/tracks/python/exercises/sublist/sublist_test.py +94 -55
  124. data/tracks/ruby/README.md +38 -25
  125. data/tracks/ruby/exercises/hamming/example.tt +6 -4
  126. data/tracks/ruby/exercises/hamming/hamming_test.rb +4 -5
  127. data/tracks/ruby/exercises/linked-list/linked_list_test.rb +16 -0
  128. data/tracks/ruby/exercises/luhn/luhn_test.rb +5 -5
  129. data/tracks/ruby/exercises/ocr-numbers/.meta/.version +1 -0
  130. data/tracks/ruby/exercises/ocr-numbers/example.rb +42 -61
  131. data/tracks/ruby/exercises/ocr-numbers/example.tt +21 -0
  132. data/tracks/ruby/exercises/ocr-numbers/ocr_numbers_test.rb +63 -138
  133. data/tracks/ruby/lib/generator/exercise_cases.rb +43 -0
  134. data/tracks/ruby/lib/generator/underscore.rb +9 -0
  135. data/tracks/ruby/lib/hamming_cases.rb +9 -14
  136. data/tracks/ruby/lib/luhn_cases.rb +2 -18
  137. data/tracks/ruby/lib/ocr_numbers_cases.rb +20 -0
  138. data/tracks/ruby/lib/pig_latin_cases.rb +2 -12
  139. data/tracks/ruby/test/generator/underscore_test.rb +23 -0
  140. data/tracks/scala/config.json +316 -316
  141. metadata +26 -10
  142. data/tracks/cpp/exercises/etl/require_equal_containers.h +0 -88
  143. data/tracks/cpp/exercises/grade-school/require_equal_containers.h +0 -88
  144. data/tracks/cpp/exercises/nucleotide-count/require_equal_containers.h +0 -88
  145. data/tracks/cpp/exercises/series/require_equal_containers.h +0 -88
  146. data/tracks/cpp/exercises/word-count/require_equal_containers.h +0 -88
  147. data/tracks/javascript/exercises/acronym/package.json +0 -12
  148. data/tracks/javascript/package.json +0 -12
@@ -19,7 +19,7 @@ const targetTestVersion = 1
19
19
 
20
20
  var (
21
21
  // song copied from README
22
- song = `This is the house that Jack built.
22
+ expectedSong = `This is the house that Jack built.
23
23
 
24
24
  This is the malt
25
25
  that lay in the house that Jack built.
@@ -109,7 +109,7 @@ that killed the rat
109
109
  that ate the malt
110
110
  that lay in the house that Jack built.`
111
111
 
112
- verses = strings.Split(song, "\n\n")
112
+ expectedVerses = strings.Split(expectedSong, "\n\n")
113
113
  )
114
114
 
115
115
  func TestTestVersion(t *testing.T) {
@@ -119,26 +119,26 @@ func TestTestVersion(t *testing.T) {
119
119
  }
120
120
 
121
121
  func TestVerse(t *testing.T) {
122
- for v := 0; v < len(verses); v++ {
123
- if ret := Verse(v + 1); ret != verses[v] {
124
- t.Fatalf("Verse(%d) =\n%q\n want:\n%q", v+1, ret, verses[v])
122
+ for v := 0; v < len(expectedVerses); v++ {
123
+ if ret := Verse(v + 1); ret != expectedVerses[v] {
124
+ t.Fatalf("Verse(%d) =\n%q\n want:\n%q", v+1, ret, expectedVerses[v])
125
125
  }
126
126
  }
127
127
  }
128
128
 
129
129
  func TestSong(t *testing.T) {
130
130
  s := Song()
131
- if s == song {
131
+ if s == expectedSong {
132
132
  return
133
133
  }
134
134
  // a little help in locating an error
135
135
  gotStanzas := len(strings.Split(s, "\n\n"))
136
- wantStanzas := len(verses)
136
+ wantStanzas := len(expectedVerses)
137
137
  if wantStanzas != gotStanzas {
138
138
  t.Fatalf("Song() has %d verse(s), want %d verses", gotStanzas, wantStanzas)
139
139
  }
140
140
  got := strings.Split(s, "\n")
141
- want := strings.Split(song, "\n")
141
+ want := strings.Split(expectedSong, "\n")
142
142
  var g, w string
143
143
  var i int
144
144
  for i, w = range want {
@@ -37,9 +37,7 @@ type js struct {
37
37
  // template applied to above data structure generates the Go test cases
38
38
  var tmpl = `package meetup
39
39
 
40
- // Source: {{.Ori}}
41
- {{if .Commit}}// Commit: {{.Commit}}
42
- {{end}}
40
+ {{.Header}}
43
41
 
44
42
  import "time"
45
43
 
@@ -1,7 +1,8 @@
1
1
  package meetup
2
2
 
3
3
  // Source: exercism/x-common
4
- // Commit: b237b7b Merge pull request #124 from soniakeys/meetup-common-tests
4
+ // Commit: fe9630e meetup: Fix canonical-data.json formatting
5
+ // x-common version: 1.0.0
5
6
 
6
7
  import "time"
7
8
 
@@ -47,7 +47,7 @@ func Products(fmin, fmax int) (pmin, pmax Product, err error) {
47
47
  }
48
48
  }
49
49
  if len(pmin.Factorizations) == 0 {
50
- err = fmt.Errorf("No palindromes in range [%d, %d].", fmin, fmax)
50
+ err = fmt.Errorf("no palindromes in range [%d, %d]", fmin, fmax)
51
51
  }
52
52
  return
53
53
  }
@@ -38,7 +38,7 @@ var testData = []struct {
38
38
  Product{10201, [][2]int{{101, 101}}},
39
39
  Product{906609, [][2]int{{913, 993}}},
40
40
  ""},
41
- {4, 10, Product{}, Product{}, "No palindromes"},
41
+ {4, 10, Product{}, Product{}, "no palindromes"},
42
42
  {10, 4, Product{}, Product{}, "fmin > fmax"},
43
43
  }
44
44
 
@@ -8,7 +8,7 @@ import (
8
8
 
9
9
  const targetTestVersion = 1
10
10
 
11
- var t20 = [][]int{
11
+ var triangleTestCases = [][]int{
12
12
  {1},
13
13
  {1, 1},
14
14
  {1, 2, 1},
@@ -31,6 +31,8 @@ var t20 = [][]int{
31
31
  {1, 19, 171, 969, 3876, 11628, 27132, 50388, 75582, 92378, 92378, 75582, 50388, 27132, 11628, 3876, 969, 171, 19, 1},
32
32
  }
33
33
 
34
+ var testSize = len(triangleTestCases)
35
+
34
36
  func TestTestVersion(t *testing.T) {
35
37
  if testVersion != targetTestVersion {
36
38
  t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
@@ -38,15 +40,15 @@ func TestTestVersion(t *testing.T) {
38
40
  }
39
41
 
40
42
  func TestTriangle(t *testing.T) {
41
- for n := 1; n <= 20; n++ {
43
+ for n := 1; n <= testSize; n++ {
42
44
  res := Triangle(n)
43
- want := t20[:n]
45
+ want := triangleTestCases[:n]
44
46
  if !reflect.DeepEqual(res, want) {
45
47
  t.Fatalf("Triangle(%d) = %s,\nwant:%s\n",
46
48
  n, format(res), format(want))
47
49
  }
48
50
  }
49
- t.Log(format(Triangle(20)))
51
+ t.Log(format(Triangle(testSize)))
50
52
  }
51
53
 
52
54
  func format(t [][]int) (s string) {
@@ -55,3 +57,21 @@ func format(t [][]int) (s string) {
55
57
  }
56
58
  return
57
59
  }
60
+
61
+ // BenchmarkPascalsTriangleFixed will generate Pascals Triangles against the
62
+ // solution using triangles of fixed size 20.
63
+ func BenchmarkPascalsTriangleFixed(b *testing.B) {
64
+ for i := 0; i < b.N; i++ {
65
+ Triangle(testSize) // same length as the test for correctness above
66
+ }
67
+ }
68
+
69
+ // BenchmarkPascalsTriangleIncreasing will generate Pascals Triangles against the
70
+ // solution using triangles of an increasingly larger size from 1 to 20.
71
+ func BenchmarkPascalsTriangleIncreasing(b *testing.B) {
72
+ for i := 0; i < b.N; i++ {
73
+ for x := 0; x <= testSize; x++ {
74
+ Triangle(x)
75
+ }
76
+ }
77
+ }
@@ -43,9 +43,7 @@ type js struct {
43
43
  // readme and have no biological basis and so are not converted here.
44
44
  var tmpl = `package strand
45
45
 
46
- // Source: {{.Ori}}
47
- {{if .Commit}}// Commit: {{.Commit}}
48
- {{end}}
46
+ {{.Header}}
49
47
 
50
48
  var rnaTests = []struct {
51
49
  input string
@@ -1,7 +1,8 @@
1
1
  package strand
2
2
 
3
3
  // Source: exercism/x-common
4
- // Commit: 6985644 Merge pull request #121 from mikeyjcat/add-roman-numerals-test-definition
4
+ // Commit: 0b20fff rna-transcription: Fix canonical-data.json formatting
5
+ // x-common version: 1.0.0
5
6
 
6
7
  var rnaTests = []struct {
7
8
  input string
@@ -31,9 +31,7 @@ type js struct {
31
31
  // template applied to above data structure generates the Go test cases
32
32
  var tmpl = `package romannumerals
33
33
 
34
- // Source: {{.Ori}}
35
- {{if .Commit}}// Commit: {{.Commit}}
36
- {{end}}
34
+ {{.Header}}
37
35
 
38
36
  type romanNumeralTest struct {
39
37
  arabic int
@@ -1,7 +1,8 @@
1
1
  package romannumerals
2
2
 
3
3
  // Source: exercism/x-common
4
- // Commit: 6985644 Merge pull request #121 from mikeyjcat/add-roman-numerals-test-definition
4
+ // Commit: 070e8d5 roman-numerals: Fix canonical-data.json formatting
5
+ // x-common version: 1.0.0
5
6
 
6
7
  type romanNumeralTest struct {
7
8
  arabic int
@@ -16,7 +16,7 @@ func ToRomanNumeral(input int) (string, error) {
16
16
  buffer := bytes.NewBufferString("")
17
17
 
18
18
  if input <= 0 || input >= 4000 {
19
- return "", fmt.Errorf("The number %d is undefined in the roman numeral system.", input)
19
+ return "", fmt.Errorf("the number %d is undefined in the roman numeral system", input)
20
20
  }
21
21
 
22
22
  mappings := []arabicToRoman{
@@ -32,9 +32,7 @@ type js struct {
32
32
  // template applied to above data structure generates the Go test cases
33
33
  var tmpl = `package transpose
34
34
 
35
- // Source: {{.Ori}}
36
- {{if .Commit}}// Commit: {{.Commit}}
37
- {{end}}
35
+ {{.Header}}
38
36
 
39
37
  var testCases = []struct {
40
38
  description string
@@ -1,7 +1,8 @@
1
1
  package transpose
2
2
 
3
3
  // Source: exercism/x-common
4
- // Commit: cda8f98 Create new exercises structure
4
+ // Commit: 6dba022 transpose: Fix canonical-data.json formatting
5
+ // x-common version: 1.0.0
5
6
 
6
7
  var testCases = []struct {
7
8
  description string
@@ -17,6 +17,11 @@ func TestTranspose(t *testing.T) {
17
17
  for _, test := range testCases {
18
18
  actual := Transpose(test.input)
19
19
  if !reflect.DeepEqual(actual, test.expected) {
20
+ // check for zero length slices
21
+ if len(actual) == 0 || len(test.expected) == 0 {
22
+ t.Fatalf("\n\tTranspose(%q): %s\n\n\tExpected: %q\n\tGot: %q",
23
+ test.input, test.description, test.expected, actual)
24
+ }
20
25
  // let's make the error more specific and find the row it's on
21
26
  min := min(len(test.expected), len(actual))
22
27
  for i := 0; i < min; i++ {
@@ -32,9 +32,7 @@ type js struct {
32
32
  // template applied to above data structure generates the Go test cases
33
33
  var tmpl = `package wordcount
34
34
 
35
- // Source: {{.Ori}}
36
- {{if .Commit}}// Commit: {{.Commit}}
37
- {{end}}
35
+ {{.Header}}
38
36
 
39
37
  var testCases = []struct {
40
38
  description string
@@ -1,7 +1,8 @@
1
1
  package wordcount
2
2
 
3
3
  // Source: exercism/x-common
4
- // Commit: f2ab262 word-count: replace underscore with space in description (#483)
4
+ // Commit: cd26d49 word-count: Make exercise schema-compliant (#634)
5
+ // x-common version: 1.0.0
5
6
 
6
7
  var testCases = []struct {
7
8
  description string
data/tracks/go/gen/gen.go CHANGED
@@ -89,10 +89,11 @@ func Gen(exercise string, j interface{}, t *template.Template) error {
89
89
  // try to find and read the local json source file
90
90
  log.Printf("[LOCAL] fetching %s test data\n", exercise)
91
91
  jPath, jOrigin, jCommit := getLocal(jFile)
92
+ jFilePath := filepath.Join(jPath, jFile)
92
93
  if jPath != "" {
93
- log.Printf("[LOCAL] source: %s\n", jPath)
94
+ log.Printf("[LOCAL] source: %s\n", jFilePath)
94
95
  }
95
- jSrc, err := ioutil.ReadFile(filepath.Join(jPath, jFile))
96
+ jSrc, err := ioutil.ReadFile(jFilePath)
96
97
  if err != nil {
97
98
  // fetch json data remotely if there's no local file
98
99
  log.Println("[LOCAL] No test data found")
@@ -324,6 +324,11 @@
324
324
  "slug": "book-store",
325
325
  "difficulty": 1,
326
326
  "topics": []
327
+ },
328
+ {
329
+ "slug": "saddle-points",
330
+ "difficulty": 1,
331
+ "topics": []
327
332
  }
328
333
  ],
329
334
  "deprecated": [
@@ -0,0 +1,17 @@
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
+ test {
13
+ testLogging {
14
+ exceptionFormat = 'full'
15
+ events = ["passed", "failed", "skipped"]
16
+ }
17
+ }
@@ -0,0 +1,44 @@
1
+ import java.util.ArrayList;
2
+ import java.util.Collections;
3
+ import java.util.List;
4
+
5
+ final class Matrix {
6
+
7
+ private final List<List<Integer>> values;
8
+
9
+ Matrix(final List<List<Integer>> values) {
10
+ this.values = values;
11
+ }
12
+
13
+ List<MatrixCoordinate> getSaddlePoints() {
14
+ final List<MatrixCoordinate> result = new ArrayList<>();
15
+
16
+ if (values.isEmpty()) {
17
+ return result;
18
+ }
19
+
20
+ for (int row = 0; row < values.size(); row++) {
21
+ for (int column = 0; column < values.get(0).size(); column++) {
22
+ final int coordinateValue = values.get(row).get(column);
23
+
24
+ if (coordinateValue == getRowMax(row) && coordinateValue == getColumnMin(column)) {
25
+ result.add(new MatrixCoordinate(row, column));
26
+ }
27
+ }
28
+ }
29
+
30
+ return result;
31
+ }
32
+
33
+ private int getRowMax(final int row) {
34
+ return Collections.max(values.get(row));
35
+ }
36
+
37
+ private int getColumnMin(final int column) {
38
+ return values.stream()
39
+ .map(row -> row.get(column))
40
+ .min(Integer::compareTo)
41
+ .get();
42
+ }
43
+
44
+ }
@@ -0,0 +1,31 @@
1
+ final class MatrixCoordinate {
2
+
3
+ private final int row;
4
+
5
+ private final int column;
6
+
7
+ MatrixCoordinate(final int row, final int column) {
8
+ this.row = row;
9
+ this.column = column;
10
+ }
11
+
12
+ // Generated equals and hashcode.
13
+
14
+ @Override
15
+ public boolean equals(final Object o) {
16
+ if (this == o) return true;
17
+ if (o == null || getClass() != o.getClass()) return false;
18
+
19
+ final MatrixCoordinate that = (MatrixCoordinate) o;
20
+
21
+ return row == that.row && column == that.column;
22
+ }
23
+
24
+ @Override
25
+ public int hashCode() {
26
+ int result = row;
27
+ result = 31 * result + column;
28
+ return result;
29
+ }
30
+
31
+ }
@@ -0,0 +1,5 @@
1
+ final class Matrix {
2
+
3
+
4
+
5
+ }
@@ -0,0 +1,31 @@
1
+ final class MatrixCoordinate {
2
+
3
+ private final int row;
4
+
5
+ private final int column;
6
+
7
+ MatrixCoordinate(final int row, final int column) {
8
+ this.row = row;
9
+ this.column = column;
10
+ }
11
+
12
+ // Generated equals and hashcode.
13
+
14
+ @Override
15
+ public boolean equals(final Object o) {
16
+ if (this == o) return true;
17
+ if (o == null || getClass() != o.getClass()) return false;
18
+
19
+ final MatrixCoordinate that = (MatrixCoordinate) o;
20
+
21
+ return row == that.row && column == that.column;
22
+ }
23
+
24
+ @Override
25
+ public int hashCode() {
26
+ int result = row;
27
+ result = 31 * result + column;
28
+ return result;
29
+ }
30
+
31
+ }
@@ -0,0 +1,82 @@
1
+ import org.junit.Ignore;
2
+ import org.junit.Test;
3
+
4
+ import java.util.ArrayList;
5
+ import java.util.Arrays;
6
+ import java.util.Collections;
7
+ import java.util.List;
8
+
9
+ import static org.junit.Assert.assertEquals;
10
+
11
+ public class MatrixTest {
12
+
13
+ @Test
14
+ public void testCanIdentifySingleSaddlePoint() {
15
+ Matrix matrix = new Matrix(Arrays.asList(
16
+ Arrays.asList(9, 8, 7),
17
+ Arrays.asList(5, 3, 2),
18
+ Arrays.asList(6, 6, 7)
19
+ ));
20
+
21
+ List<MatrixCoordinate> expectedSaddlePoints = Collections.singletonList(new MatrixCoordinate(1, 0));
22
+
23
+ assertEquals(expectedSaddlePoints, matrix.getSaddlePoints());
24
+ }
25
+
26
+ @Ignore
27
+ @Test
28
+ public void testCanIdentifyThatEmptyMatrixHasNoSaddlePoints() {
29
+ Matrix matrix = new Matrix(new ArrayList<>());
30
+
31
+ List<MatrixCoordinate> expectedSaddlePoints = new ArrayList<>();
32
+
33
+ assertEquals(expectedSaddlePoints, matrix.getSaddlePoints());
34
+ }
35
+
36
+ @Ignore
37
+ @Test
38
+ public void testCanIdentifyLackOfSaddlePointsWhenThereAreNone() {
39
+ Matrix matrix = new Matrix(Arrays.asList(
40
+ Arrays.asList(1, 2, 3),
41
+ Arrays.asList(3, 1, 2),
42
+ Arrays.asList(2, 3, 1)
43
+ ));
44
+
45
+ List<MatrixCoordinate> expectedSaddlePoints = new ArrayList<>();
46
+
47
+ assertEquals(expectedSaddlePoints, matrix.getSaddlePoints());
48
+ }
49
+
50
+ @Ignore
51
+ @Test
52
+ public void testCanIdentifyMultipleSaddlePoints() {
53
+ Matrix matrix = new Matrix(Arrays.asList(
54
+ Arrays.asList(4, 5, 4),
55
+ Arrays.asList(3, 5, 5),
56
+ Arrays.asList(1, 5, 4)
57
+ ));
58
+
59
+ List<MatrixCoordinate> expectedSaddlePoints = Arrays.asList(
60
+ new MatrixCoordinate(0, 1),
61
+ new MatrixCoordinate(1, 1),
62
+ new MatrixCoordinate(2, 1)
63
+ );
64
+
65
+ assertEquals(expectedSaddlePoints, matrix.getSaddlePoints());
66
+ }
67
+
68
+ @Ignore
69
+ @Test
70
+ public void testCanIdentifySaddlePointInBottomRightCorner() {
71
+ Matrix matrix = new Matrix(Arrays.asList(
72
+ Arrays.asList(8, 7, 9),
73
+ Arrays.asList(6, 7, 6),
74
+ Arrays.asList(3, 2, 5)
75
+ ));
76
+
77
+ List<MatrixCoordinate> expectedSaddlePoints = Collections.singletonList(new MatrixCoordinate(2, 2));
78
+
79
+ assertEquals(expectedSaddlePoints, matrix.getSaddlePoints());
80
+ }
81
+
82
+ }