trackler 2.0.8.2 → 2.0.8.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 628be9992a422198cd22ca843fb2037ba6c03d72
4
- data.tar.gz: 2ee76fac59c86929d2224dcaa3b4ca3843dc7f4b
3
+ metadata.gz: f0c444d7b94d362ffd61d031a2c19aa0648aec67
4
+ data.tar.gz: b89e89a7208130f5c3609cdfc7d489b9049ceb7e
5
5
  SHA512:
6
- metadata.gz: 950598d86876b07601a68378108358eeeceb09dac2a380d8d5cc607eaa8b6282d0ef2dcd660900dcede06a36b1e5d3fed69ae5ed8c522715b3320c68df20b75b
7
- data.tar.gz: 1c2ba152ea54815a1be22d9224f210cfc0b6d0dd402020481666c914569f02b69a36417f7307dddd5ca342fd6ad6df6ea45bce30e9e4b87fb2ba4a4604caee2f
6
+ metadata.gz: 04579958808938ab72cb8921a7c432c814a219a283b375a732da663b2060cf688640a7cd7ca0f185af4d8c5d2874fcd88c51be3ec0db0f39dde08c46f8203e4a
7
+ data.tar.gz: 4b4b7d1cde0197fba10b59031fb9355ee2fa4e4a36f5a131b198df6129516e7891ef05f10f3d4117b909a71d6c3ef27b5b91b1bed520d4288159c294427779cb
@@ -1,134 +1,172 @@
1
1
  {
2
- "#": [
2
+ "exercise": "bowling",
3
+ "version": "1",
4
+ "comments": [
3
5
  "Students should implement roll and score methods.",
4
6
  "Roll should accept a single integer.",
5
7
  "Score should return the game's final score, when possible",
6
- "For brevity the tests display all the rolls in an array;",
7
- "each element of the rolls array should be passed to the roll method",
8
- "The final tests define situations where the score can not be returned",
9
- "The expection for these tests is -1, indicating an error",
10
- "In these cases you should expect an error as is idiomatic for your language",
11
- "When to error is also left up to your implementation. There are two options",
12
- " - Error as soon as an invalid roll is made",
13
- " - Error when scoring a game with an invalid roll",
14
- "You can also error in both cases."
8
+ "For brevity the tests display all the previous rolls in an array;",
9
+ "each element of the previous_rolls array should be passed to the roll method",
10
+ "and each of those previous rolls is expected to succeed.",
11
+ "",
12
+ "Two properties are tested:",
13
+ "",
14
+ "`score`: All rolls succeed, and taking the score gives the expected result.",
15
+ "The expected result may be an integer score or an error.",
16
+ "",
17
+ "`roll`: All previous_rolls succeed, and rolling the number of pins in `roll` produces the expected result.",
18
+ "Currently, all cases of this type result in errors.",
19
+ "",
20
+ "In all error cases you should expect an error as is idiomatic for your language",
21
+ "whether that be via exceptions, optional values, or otherwise."
15
22
  ],
16
- "score": {
17
- "description": [
18
- "returns the final score of a bowling game"
19
- ],
20
- "cases": [{
21
- "description": "should be able to score a game with all zeros",
22
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
23
- "expected": 0
24
- }, {
25
- "description": "should be able to score a game with no strikes or spares",
26
- "rolls": [3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6],
27
- "expected": 90
28
- }, {
29
- "description": "a spare followed by zeros is worth ten points",
30
- "rolls": [6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
31
- "expected": 10
32
- }, {
33
- "description": "points scored in the roll after a spare are counted twice",
34
- "rolls": [6, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
35
- "expected": 16
36
- }, {
37
- "description": "consecutive spares each get a one roll bonus",
38
- "rolls": [5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
39
- "expected": 31
40
- }, {
41
- "description": "a spare in the last frame gets a one roll bonus that is counted once",
42
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 7],
43
- "expected": 17
44
- }, {
45
- "description": "a strike earns ten points in a frame with a single roll",
46
- "rolls": [10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
47
- "expected": 10
48
- }, {
49
- "description": "points scored in the two rolls after a strike are counted twice as a bonus",
50
- "rolls": [10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
51
- "expected": 26
52
- }, {
53
- "description": "consecutive strikes each get the two roll bonus",
54
- "rolls": [10, 10, 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
55
- "expected": 81
56
- }, {
57
- "description": "a strike in the last frame gets a two roll bonus that is counted once",
58
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 1],
59
- "expected": 18
60
- }, {
61
- "description": "rolling a spare with the two roll bonus does not get a bonus roll",
62
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 3],
63
- "expected": 20
64
- }, {
65
- "description": "strikes with the two roll bonus do not get bonus rolls",
66
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10],
67
- "expected": 30
68
- }, {
69
- "description": "a strike with the one roll bonus after a spare in the last frame does not get a bonus",
70
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 10],
71
- "expected": 20
72
- }, {
73
- "description": "all strikes is a perfect game",
74
- "rolls": [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10],
75
- "expected": 300
76
- }, {
77
- "description": "rolls can not score negative points",
78
- "rolls": [-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
79
- "expected": -1
80
- }, {
81
- "description": "a roll can not score more than 10 points",
82
- "rolls": [11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
83
- "expected": -1
84
- }, {
85
- "description": "two rolls in a frame can not score more than 10 points",
86
- "rolls": [5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
87
- "expected": -1
88
- }, {
89
- "description": "bonus roll after a strike in the last frame can not score more than 10 points",
90
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11],
91
- "expected": -1
92
- }, {
93
- "description": "two bonus rolls after a strike in the last frame can not score more than 10 points",
94
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5, 6],
95
- "expected": -1
96
- }, {
97
- "description": "two bonus rolls after a strike in the last frame can score more than 10 points if one is a strike",
98
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 6],
99
- "expected": 26
100
- }, {
101
- "description": "the second bonus rolls after a strike in the last frame can not be a strike if the first one is not a strike",
102
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 6, 10],
103
- "expected": -1
104
- }, {
105
- "description": "second bonus roll after a strike in the last frame can not score than 10 points",
106
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 11],
107
- "expected": -1
108
- }, {
109
- "description": "an unstarted game can not be scored",
110
- "rolls": [],
111
- "expected": -1
112
- }, {
113
- "description": "an incomplete game can not be scored",
114
- "rolls": [0, 0],
115
- "expected": -1
116
- }, {
117
- "description": "a game with more than ten frames can not be scored",
118
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
119
- "expected": -1
120
- }, {
121
- "description": "bonus rolls for a strike in the last frame must be rolled before score can be calculated",
122
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
123
- "expected": -1
124
- }, {
125
- "description": "both bonus rolls for a strike in the last frame must be rolled before score can be calculated",
126
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10],
127
- "expected": -1
128
- }, {
129
- "description": "bonus roll for a spare in the last frame must be rolled before score can be calculated",
130
- "rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3],
131
- "expected": -1
132
- }]
133
- }
23
+ "cases": [{
24
+ "description": "should be able to score a game with all zeros",
25
+ "property": "score",
26
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
27
+ "expected": 0
28
+ }, {
29
+ "description": "should be able to score a game with no strikes or spares",
30
+ "property": "score",
31
+ "previous_rolls": [3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6],
32
+ "expected": 90
33
+ }, {
34
+ "description": "a spare followed by zeros is worth ten points",
35
+ "property": "score",
36
+ "previous_rolls": [6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
37
+ "expected": 10
38
+ }, {
39
+ "description": "points scored in the roll after a spare are counted twice",
40
+ "property": "score",
41
+ "previous_rolls": [6, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
42
+ "expected": 16
43
+ }, {
44
+ "description": "consecutive spares each get a one roll bonus",
45
+ "property": "score",
46
+ "previous_rolls": [5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
47
+ "expected": 31
48
+ }, {
49
+ "description": "a spare in the last frame gets a one roll bonus that is counted once",
50
+ "property": "score",
51
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 7],
52
+ "expected": 17
53
+ }, {
54
+ "description": "a strike earns ten points in a frame with a single roll",
55
+ "property": "score",
56
+ "previous_rolls": [10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
57
+ "expected": 10
58
+ }, {
59
+ "description": "points scored in the two rolls after a strike are counted twice as a bonus",
60
+ "property": "score",
61
+ "previous_rolls": [10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
62
+ "expected": 26
63
+ }, {
64
+ "description": "consecutive strikes each get the two roll bonus",
65
+ "property": "score",
66
+ "previous_rolls": [10, 10, 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
67
+ "expected": 81
68
+ }, {
69
+ "description": "a strike in the last frame gets a two roll bonus that is counted once",
70
+ "property": "score",
71
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 1],
72
+ "expected": 18
73
+ }, {
74
+ "description": "rolling a spare with the two roll bonus does not get a bonus roll",
75
+ "property": "score",
76
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 3],
77
+ "expected": 20
78
+ }, {
79
+ "description": "strikes with the two roll bonus do not get bonus rolls",
80
+ "property": "score",
81
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10],
82
+ "expected": 30
83
+ }, {
84
+ "description": "a strike with the one roll bonus after a spare in the last frame does not get a bonus",
85
+ "property": "score",
86
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 10],
87
+ "expected": 20
88
+ }, {
89
+ "description": "all strikes is a perfect game",
90
+ "property": "score",
91
+ "previous_rolls": [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10],
92
+ "expected": 300
93
+ }, {
94
+ "description": "rolls can not score negative points",
95
+ "property": "roll",
96
+ "previous_rolls": [],
97
+ "roll": -1,
98
+ "expected": {"error": "Negative roll is invalid"}
99
+ }, {
100
+ "description": "a roll can not score more than 10 points",
101
+ "property": "roll",
102
+ "previous_rolls": [],
103
+ "roll": 11,
104
+ "expected": {"error": "Pin count exceeds pins on the lane"}
105
+ }, {
106
+ "description": "two rolls in a frame can not score more than 10 points",
107
+ "property": "roll",
108
+ "previous_rolls": [5],
109
+ "roll": 6,
110
+ "expected": {"error": "Pin count exceeds pins on the lane"}
111
+ }, {
112
+ "description": "bonus roll after a strike in the last frame can not score more than 10 points",
113
+ "property": "roll",
114
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
115
+ "roll": 11,
116
+ "expected": {"error": "Pin count exceeds pins on the lane"}
117
+ }, {
118
+ "description": "two bonus rolls after a strike in the last frame can not score more than 10 points",
119
+ "property": "roll",
120
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5],
121
+ "roll": 6,
122
+ "expected": {"error": "Pin count exceeds pins on the lane"}
123
+ }, {
124
+ "description": "two bonus rolls after a strike in the last frame can score more than 10 points if one is a strike",
125
+ "property": "score",
126
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 6],
127
+ "expected": 26
128
+ }, {
129
+ "description": "the second bonus rolls after a strike in the last frame can not be a strike if the first one is not a strike",
130
+ "property": "roll",
131
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 6],
132
+ "roll": 10,
133
+ "expected": {"error": "Pin count exceeds pins on the lane"}
134
+ }, {
135
+ "description": "second bonus roll after a strike in the last frame can not score than 10 points",
136
+ "property": "roll",
137
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10],
138
+ "roll": 11,
139
+ "expected": {"error": "Pin count exceeds pins on the lane"}
140
+ }, {
141
+ "description": "an unstarted game can not be scored",
142
+ "property": "score",
143
+ "previous_rolls": [],
144
+ "expected": {"error": "Score cannot be taken until the end of the game"}
145
+ }, {
146
+ "description": "an incomplete game can not be scored",
147
+ "property": "score",
148
+ "previous_rolls": [0, 0],
149
+ "expected": {"error": "Score cannot be taken until the end of the game"}
150
+ }, {
151
+ "description": "cannot roll if game already has ten frames",
152
+ "property": "roll",
153
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
154
+ "roll": 0,
155
+ "expected": {"error": "Cannot roll after game is over"}
156
+ }, {
157
+ "description": "bonus rolls for a strike in the last frame must be rolled before score can be calculated",
158
+ "property": "score",
159
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
160
+ "expected": {"error": "Score cannot be taken until the end of the game"}
161
+ }, {
162
+ "description": "both bonus rolls for a strike in the last frame must be rolled before score can be calculated",
163
+ "property": "score",
164
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10],
165
+ "expected": {"error": "Score cannot be taken until the end of the game"}
166
+ }, {
167
+ "description": "bonus roll for a spare in the last frame must be rolled before score can be calculated",
168
+ "property": "score",
169
+ "previous_rolls": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3],
170
+ "expected": {"error": "Score cannot be taken until the end of the game"}
171
+ }]
134
172
  }
@@ -1,3 +1,3 @@
1
1
  module Trackler
2
- VERSION = "2.0.8.2"
2
+ VERSION = "2.0.8.3"
3
3
  end
@@ -8,62 +8,62 @@ public class PangramsTest {
8
8
 
9
9
 
10
10
  @Test
11
- public void sentenceEmpty() {
11
+ public void emptySentenceIsNotPangram() {
12
12
  assertFalse(Pangrams.isPangram(""));
13
13
  }
14
14
 
15
15
  @Ignore
16
16
  @Test
17
- public void pangramWithOnlyLowerCase() {
17
+ public void pangramWithOnlyLowerCaseLettersIsRecognizedAsPangram() {
18
18
  assertTrue(Pangrams.isPangram("the quick brown fox jumps over the lazy dog"));
19
19
  }
20
20
 
21
21
  @Ignore
22
22
  @Test
23
- public void missingCharacterX() {
23
+ public void phraseMissingCharacterXIsNotPangram() {
24
24
  assertFalse(Pangrams.isPangram("a quick movement of the enemy will jeopardize five gunboats"));
25
25
  }
26
26
 
27
27
  @Ignore
28
28
  @Test
29
- public void anotherMissingCharacterX() {
29
+ public void anotherPhraseMissingCharacterXIsNotPangram() {
30
30
  assertFalse(Pangrams.isPangram("the quick brown fish jumps over the lazy dog"));
31
31
  }
32
32
 
33
33
  @Ignore
34
34
  @Test
35
- public void pangramWithUnderscores() {
35
+ public void pangramWithUnderscoresIsRecognizedAsPangram() {
36
36
  assertTrue(Pangrams.isPangram("\"the_quick_brown_fox_jumps_over_the_lazy_dog\""));
37
37
  }
38
38
 
39
39
  @Ignore
40
40
  @Test
41
- public void pangramWithNumbers() {
41
+ public void pangramWithNumbersIsRecognizedAsPangram() {
42
42
  assertTrue(Pangrams.isPangram("\"the 1 quick brown fox jumps over the 2 lazy dogs\""));
43
43
  }
44
44
 
45
45
  @Ignore
46
46
  @Test
47
- public void missingLettersReplacedByNumbers() {
47
+ public void phraseWithMissingLettersReplacedByNumbersIsNotPangram() {
48
48
  assertFalse(Pangrams.isPangram("\"7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog\""));
49
49
  }
50
50
 
51
51
  @Ignore
52
52
  @Test
53
- public void pangramWithMixedCaseAndPunctuation() {
53
+ public void pangramWithMixedCaseAndPunctuationIsRecognizedAsPangram() {
54
54
  assertTrue(Pangrams.isPangram("\"Five quacking Zephyrs jolt my wax bed.\""));
55
55
  }
56
56
 
57
57
  @Ignore
58
58
  @Test
59
- public void pangramWithNonAsciiCharacters() {
59
+ public void pangramWithNonAsciiCharactersIsRecognizedAsPangram() {
60
60
  assertTrue(Pangrams.isPangram("Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich."));
61
61
  }
62
62
 
63
63
 
64
64
  @Ignore
65
65
  @Test
66
- public void panagramInAlphabetOtherThanAscii() {
66
+ public void panagramInAlphabetOtherThanAsciiIsNotRecognizedAsPangram() {
67
67
  assertFalse(Pangrams.isPangram("Широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства."));
68
68
  }
69
69
 
@@ -228,6 +228,11 @@
228
228
  "slug": "change",
229
229
  "topics": []
230
230
  },
231
+ {
232
+ "difficulty": 1,
233
+ "slug": "triangle",
234
+ "topics": []
235
+ },
231
236
  {
232
237
  "difficulty": 10,
233
238
  "slug": "react",
@@ -40,4 +40,5 @@ include 'isogram'
40
40
  include 'bracket-push'
41
41
  include 'largest-series-product'
42
42
  include 'change'
43
- include 'binary-search'
43
+ include 'binary-search'
44
+ include 'triangle'
@@ -0,0 +1,29 @@
1
+ buildscript {
2
+ ext.kotlin_version = '1.0.6'
3
+ repositories {
4
+ mavenCentral()
5
+ }
6
+ dependencies {
7
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
8
+ }
9
+ }
10
+
11
+ apply plugin: 'kotlin'
12
+
13
+ repositories {
14
+ mavenCentral()
15
+ }
16
+
17
+ dependencies {
18
+ compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
19
+
20
+ testCompile 'junit:junit:4.12'
21
+ testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
22
+ }
23
+
24
+ test {
25
+ testLogging {
26
+ exceptionFormat = 'full'
27
+ events = ["passed", "failed", "skipped"]
28
+ }
29
+ }
@@ -0,0 +1,15 @@
1
+ class Triangle<out T: Number>(val a: T, val b: T, val c: T) {
2
+
3
+ init {
4
+ require(a > 0 && b > 0 && c > 0, {"Sides must be > 0"})
5
+ require(a + b >= c && b + c >= a && c + a >= b, { "Sides must satisfy triangle inequality"})
6
+ }
7
+
8
+ val isEquilateral = a == b && b == c
9
+ val isIsosceles = a == b || b == c || c == a
10
+ val isScalene = !isIsosceles
11
+
12
+ private infix operator fun <T: Number> T.compareTo(other: T): Int = this.toDouble().compareTo(other.toDouble())
13
+ private infix operator fun <T: Number> T.plus(b: T): Double = this.toDouble().plus(b.toDouble())
14
+
15
+ }
@@ -0,0 +1,109 @@
1
+ import org.junit.Ignore
2
+ import org.junit.Test
3
+ import kotlin.test.assertFalse
4
+ import kotlin.test.assertTrue
5
+
6
+ class TriangleTest {
7
+
8
+ @Test
9
+ fun equilateralIfAllSidesAreEqual() {
10
+ assertTrue(Triangle(2, 2, 2).isEquilateral)
11
+ }
12
+
13
+ @Ignore
14
+ @Test
15
+ fun notEquilateralIfAnySideIsUnequal() {
16
+ assertFalse(Triangle(2, 3, 2).isEquilateral)
17
+ }
18
+
19
+ @Ignore
20
+ @Test
21
+ fun notEquilateralIfNoSidesAreEqual() {
22
+ assertFalse(Triangle(5, 4, 6).isEquilateral)
23
+ }
24
+
25
+ @Ignore
26
+ @Test(expected = IllegalArgumentException::class)
27
+ fun allZeroSidesAreIllegalSoNotEquilateral() {
28
+ assertFalse(Triangle(0, 0, 0).isEquilateral)
29
+ }
30
+
31
+ @Ignore
32
+ @Test
33
+ fun equilateralSidesMayBeFloatingPoint() {
34
+ assertTrue(Triangle(0.5, 0.5, 0.5).isEquilateral)
35
+ }
36
+
37
+ @Ignore
38
+ @Test
39
+ fun isoscelesIfLastTwoSidesAreEqual() {
40
+ assertTrue(Triangle(3, 4, 4).isIsosceles)
41
+ }
42
+
43
+ @Ignore
44
+ @Test
45
+ fun isoscelesIfFirstTwoSidesAreEqual() {
46
+ assertTrue(Triangle(4, 4, 3).isIsosceles)
47
+ }
48
+
49
+ @Ignore
50
+ @Test
51
+ fun isoscelesIfFirstAndLastSidesAreEqual() {
52
+ assertTrue(Triangle(4, 3, 4).isIsosceles)
53
+ }
54
+
55
+ @Ignore
56
+ @Test
57
+ fun equilateralIsAlsoIsosceles() {
58
+ assertTrue(Triangle(4, 4, 4).isIsosceles)
59
+ }
60
+
61
+ @Ignore
62
+ @Test
63
+ fun notIsoscelesIfNoSidesAreEqual() {
64
+ assertFalse(Triangle(2, 3, 4).isIsosceles)
65
+ }
66
+
67
+ @Ignore
68
+ @Test(expected = IllegalArgumentException::class)
69
+ fun sidesViolateTriangleInequalitySoNotIsosceles() {
70
+ assertFalse(Triangle(1, 1, 3).isIsosceles)
71
+ }
72
+
73
+ @Ignore
74
+ @Test
75
+ fun isoscelesSidesMayBeFloatingPoint() {
76
+ assertTrue(Triangle(0.5, 0.4, 0.5).isIsosceles)
77
+ }
78
+
79
+ @Ignore
80
+ @Test
81
+ fun scaleneIfNoSidesAreEqual() {
82
+ assertTrue(Triangle(5, 4, 6).isScalene)
83
+ }
84
+
85
+ @Ignore
86
+ @Test
87
+ fun notScaleneIfAllSidesAreEqual() {
88
+ assertFalse(Triangle(4, 4, 4).isScalene)
89
+ }
90
+
91
+ @Ignore
92
+ @Test
93
+ fun notScaleneIfTwoSidesAreEqual() {
94
+ assertFalse(Triangle(4, 4, 3).isScalene)
95
+ }
96
+
97
+ @Ignore
98
+ @Test(expected = IllegalArgumentException::class)
99
+ fun sidesViolateTriangleInequalitySoNotScalene() {
100
+ assertFalse(Triangle(7, 3, 2).isScalene)
101
+ }
102
+
103
+ @Ignore
104
+ @Test
105
+ fun scaleneSidesMayBeFloatingPoint() {
106
+ assertTrue(Triangle(0.5, 0.4, 0.6).isScalene)
107
+ }
108
+
109
+ }
@@ -318,6 +318,14 @@
318
318
  "Tuples"
319
319
  ]
320
320
  },
321
+ {
322
+ "slug":"isogram",
323
+ "difficulty":1,
324
+ "topics":[
325
+ "Strings",
326
+ "Filtering"
327
+ ]
328
+ },
321
329
  {
322
330
  "slug":"bracket-push",
323
331
  "difficulty":1,
@@ -0,0 +1,3 @@
1
+ scalaVersion := "2.12.1"
2
+
3
+ libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1" % "test"
@@ -0,0 +1,8 @@
1
+ object Isogram {
2
+ def isIsogram(s: String): Boolean =
3
+ !s.filter(_.isLetter)
4
+ .map(_.toLower)
5
+ .groupBy(identity)
6
+ .values
7
+ .exists(_.length > 1)
8
+ }
@@ -0,0 +1,52 @@
1
+ import org.scalatest.{FunSuite, Matchers}
2
+
3
+ class IsogramTest extends FunSuite with Matchers {
4
+
5
+ test("empty string") {
6
+ val result = Isogram.isIsogram("")
7
+ result should be (true)
8
+ }
9
+
10
+ test("isogram with only lower case characters") {
11
+ pending
12
+ val result = Isogram.isIsogram("isogram")
13
+ result should be (true)
14
+ }
15
+
16
+ test("word with one duplicated character") {
17
+ pending
18
+ val result = Isogram.isIsogram("eleven")
19
+ result should be (false)
20
+ }
21
+
22
+ test("longest reported english isogram") {
23
+ pending
24
+ val result = Isogram.isIsogram("subdermatoglyphic")
25
+ result should be (true)
26
+ }
27
+
28
+ test("word with duplicated character in mixed case") {
29
+ pending
30
+ val result = Isogram.isIsogram("Alphabet")
31
+ result should be (false)
32
+ }
33
+
34
+ test("hypothetical isogrammic word with hyphen") {
35
+ pending
36
+ val result = Isogram.isIsogram("thumbscrew-japingly")
37
+ result should be (true)
38
+ }
39
+
40
+ test("isogram with duplicated non letter character") {
41
+ pending
42
+ val result = Isogram.isIsogram("Hjelmqvist-Gryb-Zock-Pfund-Wax")
43
+ result should be (true)
44
+ }
45
+
46
+ test("made-up name that is an isogram") {
47
+ pending
48
+ val result = Isogram.isIsogram("Emily Jung Schwartzkopf")
49
+ result should be (true)
50
+ }
51
+
52
+ }
@@ -0,0 +1,37 @@
1
+ import play.api.libs.json.Json
2
+
3
+ import scala.io.Source
4
+
5
+ class IsogramTestGenerator {
6
+ implicit val testCaseReader = Json.reads[IsogramTestCase]
7
+
8
+ private val filename = "isogram.json"
9
+ private val fileContents = Source.fromFile(filename).getLines.mkString
10
+ private val json = Json.parse(fileContents)
11
+
12
+ def write {
13
+ val testCases = (json \ "cases").get.as[List[IsogramTestCase]]
14
+
15
+ implicit def testCaseToGen(tc: IsogramTestCase): TestCaseGen = {
16
+ val callSUT =
17
+ s"""Isogram.isIsogram("${tc.input}")"""
18
+ val expected = tc.expected.toString
19
+
20
+ TestCaseGen(tc.description, callSUT, expected)
21
+ }
22
+
23
+ val testBuilder = new TestBuilder("IsogramTest")
24
+ testBuilder.addTestCases(testCases)
25
+ testBuilder.toFile
26
+ }
27
+ }
28
+
29
+ case class IsogramTestCase(description: String,
30
+ input: String,
31
+ expected: Boolean)
32
+
33
+ object IsogramTestGenerator {
34
+ def main(args: Array[String]): Unit = {
35
+ new IsogramTestGenerator().write
36
+ }
37
+ }
@@ -44,11 +44,7 @@ moveAllIntoCommonDir:
44
44
  moveCommonIntoSubDir:
45
45
  @for assignment in $(ASSIGNMENTS); do ASSIGNMENT=$$assignment $(MAKE) moveAssigmentToSub || exit 1; done
46
46
 
47
- <<<<<<< HEAD
48
- all: replacePackageFileFromCommonToSubFolders
49
- =======
50
47
  all: replacePackageFilesFromCommonToSubFolders
51
- >>>>>>> f5528ecd7751462ac6590cc77304a7ac2489c895
52
48
 
53
49
  copyPackageFilesToSubFolder:
54
50
  @cp ./common/package.json exercises/$(ASSIGNMENT)/package.json
@@ -56,10 +52,6 @@ copyPackageFilesToSubFolder:
56
52
  @cp ./common/tslint.json exercises/$(ASSIGNMENT)/tslint.json
57
53
  @cp ./common/yarn.lock exercises/$(ASSIGNMENT)/yarn.lock
58
54
 
59
- <<<<<<< HEAD
60
- replacePackageFileFromCommonToSubFolders:
61
- =======
62
55
  replacePackageFilesFromCommonToSubFolders:
63
- >>>>>>> f5528ecd7751462ac6590cc77304a7ac2489c895
64
56
  @for assignment in $(ASSIGNMENTS); do ASSIGNMENT=$$assignment $(MAKE) copyPackageFilesToSubFolder || exit 1; done
65
57
 
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.0.8.2
4
+ version: 2.0.8.3
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-02-22 00:00:00.000000000 Z
11
+ date: 2017-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyzip
@@ -4602,6 +4602,10 @@ files:
4602
4602
  - tracks/kotlin/exercises/strain/src/example/kotlin/Strain.kt
4603
4603
  - tracks/kotlin/exercises/strain/src/main/kotlin/.keep
4604
4604
  - tracks/kotlin/exercises/strain/src/test/kotlin/StrainTest.kt
4605
+ - tracks/kotlin/exercises/triangle/build.gradle
4606
+ - tracks/kotlin/exercises/triangle/src/example/kotlin/Triangle.kt
4607
+ - tracks/kotlin/exercises/triangle/src/main/kotlin/.keep
4608
+ - tracks/kotlin/exercises/triangle/src/test/kotlin/TriangleTest.kt
4605
4609
  - tracks/kotlin/exercises/word-count/build.gradle
4606
4610
  - tracks/kotlin/exercises/word-count/src/example/kotlin/WordCount.kt
4607
4611
  - tracks/kotlin/exercises/word-count/src/main/kotlin/.keep
@@ -7175,6 +7179,10 @@ files:
7175
7179
  - tracks/scala/exercises/house/example.scala
7176
7180
  - tracks/scala/exercises/house/src/main/scala/.keep
7177
7181
  - tracks/scala/exercises/house/src/test/scala/HouseTest.scala
7182
+ - tracks/scala/exercises/isogram/build.sbt
7183
+ - tracks/scala/exercises/isogram/example.scala
7184
+ - tracks/scala/exercises/isogram/src/main/scala/Isogram.scala
7185
+ - tracks/scala/exercises/isogram/src/test/scala/IsogramTest.scala
7178
7186
  - tracks/scala/exercises/kindergarten-garden/build.sbt
7179
7187
  - tracks/scala/exercises/kindergarten-garden/example.scala
7180
7188
  - tracks/scala/exercises/kindergarten-garden/src/main/scala/.keep
@@ -7388,6 +7396,7 @@ files:
7388
7396
  - tracks/scala/testgen/src/main/scala/BowlingTestGenerator.scala
7389
7397
  - tracks/scala/testgen/src/main/scala/BracketPushTestGenerator.scala
7390
7398
  - tracks/scala/testgen/src/main/scala/CustomSetTestGenerator.scala
7399
+ - tracks/scala/testgen/src/main/scala/IsogramTestGenerator.scala
7391
7400
  - tracks/scala/testgen/src/main/scala/PangramsTestGenerator.scala
7392
7401
  - tracks/scala/testgen/src/main/scala/RailFenceCipherTestGenerator.scala
7393
7402
  - tracks/scala/testgen/src/main/scala/TestBuilder.scala