trackler 2.2.1.127 → 2.2.1.128

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/tracks/c/docs/RESOURCES.md +0 -1
  4. data/tracks/delphi/exercises/isbn-verifier/uTestISBNVerifier.pas +2 -2
  5. data/tracks/ecmascript/config.json +2 -2
  6. data/tracks/elm/config/maintainers.json +11 -11
  7. data/tracks/elm/config.json +170 -245
  8. data/tracks/fsharp/exercises/pov/PovTest.fs +1 -1
  9. data/tracks/java/exercises/queen-attack/.meta/src/reference/java/Queen.java +38 -0
  10. data/tracks/java/exercises/queen-attack/.meta/src/reference/java/QueenAttackCalculator.java +11 -12
  11. data/tracks/java/exercises/queen-attack/.meta/version +1 -1
  12. data/tracks/java/exercises/queen-attack/src/test/java/QueenAttackCalculatorTest.java +50 -44
  13. data/tracks/python/config.json +26 -0
  14. data/tracks/python/exercises/bank-account/README.md +53 -0
  15. data/tracks/python/exercises/bank-account/bank_account.py +18 -0
  16. data/tracks/python/exercises/bank-account/bank_account_test.py +120 -0
  17. data/tracks/python/exercises/bank-account/example.py +35 -0
  18. data/tracks/python/exercises/go-counting/example.py +6 -6
  19. data/tracks/python/exercises/go-counting/go_counting.py +3 -2
  20. data/tracks/python/exercises/go-counting/go_counting_test.py +58 -51
  21. data/tracks/python/exercises/house/example.py +7 -13
  22. data/tracks/python/exercises/house/house_test.py +79 -204
  23. data/tracks/python/exercises/meetup/example.py +10 -1
  24. data/tracks/python/exercises/meetup/meetup_test.py +1 -6
  25. data/tracks/python/exercises/pascals-triangle/example.py +12 -14
  26. data/tracks/python/exercises/pascals-triangle/pascals_triangle.py +1 -9
  27. data/tracks/python/exercises/pascals-triangle/pascals_triangle_test.py +43 -29
  28. data/tracks/python/exercises/sgf-parsing/README.md +110 -0
  29. data/tracks/python/exercises/sgf-parsing/example.py +100 -0
  30. data/tracks/python/exercises/sgf-parsing/sgf_parsing.py +26 -0
  31. data/tracks/python/exercises/sgf-parsing/sgf_parsing_test.py +94 -0
  32. data/tracks/typescript/config.json +1 -1
  33. data/tracks/typescript/exercises/pangram/pangram.example.ts +2 -2
  34. data/tracks/typescript/exercises/pangram/pangram.test.ts +0 -2
  35. data/tracks/typescript/exercises/pangram/pangram.ts +0 -11
  36. metadata +11 -3
  37. data/tracks/java/exercises/queen-attack/.meta/src/reference/java/BoardCoordinate.java +0 -39
@@ -1,37 +1,51 @@
1
1
  import unittest
2
2
 
3
- from pascals_triangle import triangle, row, is_triangle
3
+ from pascals_triangle import rows
4
+
5
+
6
+ # Tests adapted from `problem-specifications//canonical-data.json` @ v1.2.0
7
+
8
+ TRIANGLE = [
9
+ [1],
10
+ [1, 1],
11
+ [1, 2, 1],
12
+ [1, 3, 3, 1],
13
+ [1, 4, 6, 4, 1],
14
+ [1, 5, 10, 10, 5, 1],
15
+ [1, 6, 15, 20, 15, 6, 1],
16
+ [1, 7, 21, 35, 35, 21, 7, 1],
17
+ [1, 8, 28, 56, 70, 56, 28, 8, 1],
18
+ [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
19
+ ]
4
20
 
5
21
 
6
22
  class PascalsTriangleTest(unittest.TestCase):
7
- def test_triangle1(self):
8
- ans = ['1', '1 1', '1 2 1', '1 3 3 1', '1 4 6 4 1']
9
- self.assertEqual(triangle(4), ans)
10
-
11
- def test_triangle2(self):
12
- ans = ['1', '1 1', '1 2 1', '1 3 3 1', '1 4 6 4 1', '1 5 10 10 5 1',
13
- '1 6 15 20 15 6 1']
14
- self.assertEqual(triangle(6), ans)
15
-
16
- def test_is_triangle_true(self):
17
- inp = ['1', '1 1', '1 2 1', '1 3 3 1', '1 4 6 4 1', '1 5 10 10 5 1']
18
- self.assertIs(is_triangle(inp), True)
19
-
20
- def test_is_triangle_false(self):
21
- inp = ['1', '1 1', '1 2 1', '1 4 4 1']
22
- self.assertIs(is_triangle(inp), False)
23
-
24
- def test_row1(self):
25
- ans = '1'
26
- self.assertEqual(row(0), ans)
27
-
28
- def test_row2(self):
29
- ans = '1 2 1'
30
- self.assertEqual(row(2), ans)
31
-
32
- def test_row3(self):
33
- ans = '1 7 21 35 35 21 7 1'
34
- self.assertEqual(row(7), ans)
23
+ def test_zero_rows(self):
24
+ self.assertEqual(rows(0), [])
25
+
26
+ def test_single_row(self):
27
+ self.assertEqual(rows(1), TRIANGLE[:1])
28
+
29
+ def test_two_rows(self):
30
+ self.assertEqual(rows(2), TRIANGLE[:2])
31
+
32
+ def test_three_rows(self):
33
+ self.assertEqual(rows(3), TRIANGLE[:3])
34
+
35
+ def test_four_rows(self):
36
+ self.assertEqual(rows(4), TRIANGLE[:4])
37
+
38
+ def test_five_rows(self):
39
+ self.assertEqual(rows(5), TRIANGLE[:5])
40
+
41
+ def test_six_rows(self):
42
+ self.assertEqual(rows(6), TRIANGLE[:6])
43
+
44
+ def test_ten_rows(self):
45
+ self.assertEqual(rows(10), TRIANGLE[:10])
46
+
47
+ def test_negative_rows(self):
48
+ self.assertEqual(rows(-1), None)
35
49
 
36
50
 
37
51
  if __name__ == '__main__':
@@ -0,0 +1,110 @@
1
+ # SGF Parsing
2
+
3
+ Parsing a Smart Game Format string.
4
+
5
+ [SGF](https://en.wikipedia.org/wiki/Smart_Game_Format) is a standard format for
6
+ storing board game files, in particular go.
7
+
8
+ SGF is a fairly simple format. An SGF file usually contains a single
9
+ tree of nodes where each node is a property list. The property list
10
+ contains key value pairs, each key can only occur once but may have
11
+ multiple values.
12
+
13
+ An SGF file may look like this:
14
+
15
+ ```text
16
+ (;FF[4]C[root]SZ[19];B[aa];W[ab])
17
+ ```
18
+
19
+ This is a tree with three nodes:
20
+
21
+ - The top level node has two properties: FF\[4\] (key = "FF", value =
22
+ "4") and C\[root\](key = "C", value = "root"). (FF indicates the
23
+ version of SGF and C is a comment.)
24
+ - The top level node has a single child which has a single property:
25
+ B\[aa\]. (Black plays on the point encoded as "aa", which is the
26
+ 1-1 point (which is a stupid place to play)).
27
+ - The B\[aa\] node has a single child which has a single property:
28
+ W\[ab\].
29
+
30
+ As you can imagine an SGF file contains a lot of nodes with a single
31
+ child, which is why there's a shorthand for it.
32
+
33
+ SGF can encode variations of play. Go players do a lot of backtracking
34
+ in their reviews (let's try this, doesn't work, let's try that) and SGF
35
+ supports variations of play sequences. For example:
36
+
37
+ ```text
38
+ (;FF[4](;B[aa];W[ab])(;B[dd];W[ee]))
39
+ ```
40
+
41
+ Here the root node has two variations. The first (which by convention
42
+ indicates what's actually played) is where black plays on 1-1. Black was
43
+ sent this file by his teacher who pointed out a more sensible play in
44
+ the second child of the root node: `B[dd]` (4-4 point, a very standard
45
+ opening to take the corner).
46
+
47
+ A key can have multiple values associated with it. For example:
48
+
49
+ ```text
50
+ (;FF[4];AB[aa][ab][ba])
51
+ ```
52
+
53
+ Here `AB` (add black) is used to add three black stones to the board.
54
+
55
+ There are a few more complexities to SGF (and parsing in general), which
56
+ you can mostly ignore. You should assume that the input is encoded in
57
+ UTF-8, the tests won't contain a charset property, so don't worry about
58
+ that. Furthermore you may assume that all newlines are unix style (`\n`,
59
+ no `\r` or `\r\n` will be in the tests) and that no optional whitespace
60
+ between properties, nodes, etc will be in the tests.
61
+
62
+ The exercise will have you parse an SGF string and return a tree
63
+ structure of properties. You do not need to encode knowledge about the
64
+ data types of properties, just use the rules for the
65
+ [text](http://www.red-bean.com/sgf/sgf4.html#text) type everywhere.
66
+
67
+ ## Exception messages
68
+
69
+ Sometimes it is necessary to raise an exception. When you do this, you should include a meaningful error message to
70
+ indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. Not
71
+ every exercise will require you to raise an exception, but for those that do, the tests will only pass if you include
72
+ a message.
73
+
74
+ To raise a message with an exception, just write it as an argument to the exception type. For example, instead of
75
+ `raise Exception`, you should write:
76
+
77
+ ```python
78
+ raise Exception("Meaningful message indicating the source of the error")
79
+ ```
80
+
81
+ ## Running the tests
82
+
83
+ To run the tests, run the appropriate command below ([why they are different](https://github.com/pytest-dev/pytest/issues/1629#issue-161422224)):
84
+
85
+ - Python 2.7: `py.test sgf_parsing_test.py`
86
+ - Python 3.3+: `pytest sgf_parsing_test.py`
87
+
88
+ Alternatively, you can tell Python to run the pytest module (allowing the same command to be used regardless of Python version):
89
+ `python -m pytest sgf_parsing_test.py`
90
+
91
+ ### Common `pytest` options
92
+
93
+ - `-v` : enable verbose output
94
+ - `-x` : stop running tests on first failure
95
+ - `--ff` : run failures from previous test before running other test cases
96
+
97
+ For other options, see `python -m pytest -h`
98
+
99
+ ## Submitting Exercises
100
+
101
+ Note that, when trying to submit an exercise, make sure the solution is in the `$EXERCISM_WORKSPACE/python/sgf-parsing` directory.
102
+
103
+ You can find your Exercism workspace by running `exercism debug` and looking for the line that starts with `Workspace`.
104
+
105
+ For more detailed information about running tests, code style and linting,
106
+ please see the [help page](http://exercism.io/languages/python).
107
+
108
+ ## Submitting Incomplete Solutions
109
+
110
+ It's possible to submit an incomplete solution so you can see how others have completed the exercise.
@@ -0,0 +1,100 @@
1
+ class SgfTree(object):
2
+ def __init__(self, properties=None, children=None):
3
+ self.properties = properties or {}
4
+ self.children = children or []
5
+
6
+ def __eq__(self, other):
7
+ if not isinstance(other, SgfTree):
8
+ return False
9
+ for k, v in self.properties.items():
10
+ if k not in other.properties:
11
+ return False
12
+ if other.properties[k] != v:
13
+ return False
14
+ for k in other.properties.keys():
15
+ if k not in self.properties:
16
+ return False
17
+ if len(self.children) != len(other.children):
18
+ return False
19
+ for a, b in zip(self.children, other.children):
20
+ if not (a == b):
21
+ return False
22
+ return True
23
+
24
+ def __repr__(self):
25
+ """Ironically, encoding to SGF is much easier"""
26
+ rep = '(;'
27
+ for k, vs in self.properties.items():
28
+ rep += k
29
+ for v in vs:
30
+ rep += '[{}]'.format(v)
31
+ if self.children:
32
+ if len(self.children) > 1:
33
+ rep += '('
34
+ for c in self.children:
35
+ rep += repr(c)[1:-1]
36
+ if len(self.children) > 1:
37
+ rep += ')'
38
+ return rep + ')'
39
+
40
+
41
+ def is_upper(s):
42
+ a, z = map(ord, 'AZ')
43
+ return all(
44
+ a <= o and o <= z
45
+ for o in map(ord, s)
46
+ )
47
+
48
+
49
+ def parse(input_string):
50
+ root = None
51
+ current = None
52
+ stack = list(input_string)
53
+
54
+ def assert_that(condition):
55
+ if not condition:
56
+ raise ValueError(
57
+ 'invalid format at {}:{}: {}'.format(
58
+ repr(input_string),
59
+ len(input_string) - len(stack),
60
+ repr(''.join(stack))
61
+ )
62
+ )
63
+ assert_that(stack)
64
+
65
+ def pop():
66
+ if stack[0] == '\\':
67
+ stack.pop(0)
68
+ ch = stack.pop(0)
69
+ return ' ' if ch in '\n\t' else ch
70
+
71
+ def peek():
72
+ return stack[0]
73
+
74
+ def pop_until(ch):
75
+ v = ''
76
+ while peek() != ch:
77
+ v += pop()
78
+ return v
79
+ while stack:
80
+ assert_that(pop() == '(' and peek() == ';')
81
+ while pop() == ';':
82
+ properties = {}
83
+ while is_upper(peek()):
84
+ key = pop_until('[')
85
+ assert_that(is_upper(key))
86
+ values = []
87
+ while peek() == '[':
88
+ pop()
89
+ values.append(pop_until(']'))
90
+ pop()
91
+ properties[key] = values
92
+ if root is None:
93
+ current = root = SgfTree(properties)
94
+ else:
95
+ current = SgfTree(properties)
96
+ root.children.append(current)
97
+ while peek() == '(':
98
+ child_input = pop() + pop_until(')') + pop()
99
+ current.children.append(parse(child_input))
100
+ return root
@@ -0,0 +1,26 @@
1
+ class SgfTree(object):
2
+ def __init__(self, properties=None, children=None):
3
+ self.properties = properties or {}
4
+ self.children = children or []
5
+
6
+ def __eq__(self, other):
7
+ if not isinstance(other, SgfTree):
8
+ return False
9
+ for k, v in self.properties.items():
10
+ if k not in other.properties:
11
+ return False
12
+ if other.properties[k] != v:
13
+ return False
14
+ for k in other.properties.keys():
15
+ if k not in self.properties:
16
+ return False
17
+ if len(self.children) != len(other.children):
18
+ return False
19
+ for a, b in zip(self.children, other.children):
20
+ if a != b:
21
+ return False
22
+ return True
23
+
24
+
25
+ def parse(input_string):
26
+ pass
@@ -0,0 +1,94 @@
1
+ import unittest
2
+
3
+ from sgf_parsing import parse, SgfTree
4
+
5
+
6
+ class SgfParsingTest(unittest.TestCase):
7
+ def test_empty_input(self):
8
+ input_string = ''
9
+ with self.assertRaisesWithMessage(ValueError):
10
+ parse(input_string)
11
+
12
+ def test_tree_with_no_nodes(self):
13
+ input_string = '()'
14
+ with self.assertRaisesWithMessage(ValueError):
15
+ parse(input_string)
16
+
17
+ def test_node_without_tree(self):
18
+ input_string = ';'
19
+ with self.assertRaisesWithMessage(ValueError):
20
+ parse(input_string)
21
+
22
+ def test_node_without_properties(self):
23
+ input_string = '(;)'
24
+ expected = SgfTree()
25
+ self.assertEqual(parse(input_string), expected)
26
+
27
+ def test_single_node_tree(self):
28
+ input_string = '(;A[B])'
29
+ expected = SgfTree(properties={'A': ['B']})
30
+ self.assertEqual(parse(input_string), expected)
31
+
32
+ def test_properties_without_delimiter(self):
33
+ input_string = '(;a)'
34
+ with self.assertRaisesWithMessage(ValueError):
35
+ parse(input_string)
36
+
37
+ def test_all_lowercase_property(self):
38
+ input_string = '(;a[b])'
39
+ with self.assertRaisesWithMessage(ValueError):
40
+ parse(input_string)
41
+
42
+ def test_upper_and_lowercase_property(self):
43
+ input_string = '(;Aa[b])'
44
+ with self.assertRaisesWithMessage(ValueError):
45
+ parse(input_string)
46
+
47
+ def test_two_nodes(self):
48
+ input_string = '(;A[B];B[C])'
49
+ expected = SgfTree(
50
+ properties={'A': ['B']},
51
+ children=[
52
+ SgfTree({'B': ['C']})
53
+ ]
54
+ )
55
+ self.assertEqual(parse(input_string), expected)
56
+
57
+ def test_two_child_trees(self):
58
+ input_string = '(;A[B](;B[C])(;C[D]))'
59
+ expected = SgfTree(
60
+ properties={'A': ['B']},
61
+ children=[
62
+ SgfTree({'B': ['C']}),
63
+ SgfTree({'C': ['D']}),
64
+ ]
65
+ )
66
+ self.assertEqual(parse(input_string), expected)
67
+
68
+ def test_multiple_property_values(self):
69
+ input_string = '(;A[b][c][d])'
70
+ expected = SgfTree(
71
+ properties={'A': ['b', 'c', 'd']}
72
+ )
73
+ self.assertEqual(parse(input_string), expected)
74
+
75
+ def test_escaped_property(self):
76
+ input_string = '(;A[\]b\nc\nd\t\te \n\]])'
77
+ expected = SgfTree(
78
+ properties={'A': [']b c d e ]']}
79
+ )
80
+ self.assertEqual(parse(input_string), expected)
81
+
82
+ # Utility functions
83
+ def setUp(self):
84
+ try:
85
+ self.assertRaisesRegex
86
+ except AttributeError:
87
+ self.assertRaisesRegex = self.assertRaisesRegexp
88
+
89
+ def assertRaisesWithMessage(self, exception):
90
+ return self.assertRaisesRegex(exception, r".+")
91
+
92
+
93
+ if __name__ == '__main__':
94
+ unittest.main()
@@ -142,7 +142,7 @@
142
142
  "searching",
143
143
  "strings"
144
144
  ],
145
- "uuid": "a2c7abe7-b487-4cc2-a86a-d97cdd61709d"
145
+ "uuid": "721d9c74-cc16-4b32-8f0b-ffab75027539"
146
146
  },
147
147
  {
148
148
  "core": false,
@@ -2,7 +2,7 @@ const aToZ = [...Array<string>(26)].map( ( _ , index) => {
2
2
  return String.fromCharCode(index + 65)
3
3
  })
4
4
 
5
- class Panagram {
5
+ class Pangram {
6
6
  value: string
7
7
  constructor(input: string = "") {
8
8
  this.value = input
@@ -29,4 +29,4 @@ const aToZ = [...Array<string>(26)].map( ( _ , index) => {
29
29
  }
30
30
  }
31
31
 
32
- export default Panagram
32
+ export default Pangram
@@ -1,7 +1,6 @@
1
1
  import Pangram from './pangram'
2
2
 
3
3
  describe('Pangram()', () => {
4
-
5
4
  it('empty sentence', () => {
6
5
  const pangram = new Pangram('')
7
6
  expect(pangram.isPangram()).toBe(false)
@@ -46,5 +45,4 @@ describe('Pangram()', () => {
46
45
  const pangram = new Pangram("Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich.")
47
46
  expect(pangram.isPangram()).toBe(true)
48
47
  })
49
-
50
48
  })
@@ -1,11 +0,0 @@
1
- class Pangram {
2
- constructor( /* Parameters go here */ ) {
3
- // Your code here
4
- }
5
-
6
- isPangram() {
7
- // Your code here
8
- }
9
- }
10
-
11
- export default Pangram
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.2.1.127
4
+ version: 2.2.1.128
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katrina Owen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-02 00:00:00.000000000 Z
11
+ date: 2018-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyzip
@@ -7916,7 +7916,7 @@ files:
7916
7916
  - tracks/java/exercises/pythagorean-triplet/build.gradle
7917
7917
  - tracks/java/exercises/pythagorean-triplet/src/main/java/.keep
7918
7918
  - tracks/java/exercises/pythagorean-triplet/src/test/java/PythagoreanTripletTest.java
7919
- - tracks/java/exercises/queen-attack/.meta/src/reference/java/BoardCoordinate.java
7919
+ - tracks/java/exercises/queen-attack/.meta/src/reference/java/Queen.java
7920
7920
  - tracks/java/exercises/queen-attack/.meta/src/reference/java/QueenAttackCalculator.java
7921
7921
  - tracks/java/exercises/queen-attack/.meta/version
7922
7922
  - tracks/java/exercises/queen-attack/README.md
@@ -11549,6 +11549,10 @@ files:
11549
11549
  - tracks/python/exercises/atbash-cipher/atbash_cipher.py
11550
11550
  - tracks/python/exercises/atbash-cipher/atbash_cipher_test.py
11551
11551
  - tracks/python/exercises/atbash-cipher/example.py
11552
+ - tracks/python/exercises/bank-account/README.md
11553
+ - tracks/python/exercises/bank-account/bank_account.py
11554
+ - tracks/python/exercises/bank-account/bank_account_test.py
11555
+ - tracks/python/exercises/bank-account/example.py
11552
11556
  - tracks/python/exercises/beer-song/README.md
11553
11557
  - tracks/python/exercises/beer-song/beer_song.py
11554
11558
  - tracks/python/exercises/beer-song/beer_song_test.py
@@ -11892,6 +11896,10 @@ files:
11892
11896
  - tracks/python/exercises/series/example.py
11893
11897
  - tracks/python/exercises/series/series.py
11894
11898
  - tracks/python/exercises/series/series_test.py
11899
+ - tracks/python/exercises/sgf-parsing/README.md
11900
+ - tracks/python/exercises/sgf-parsing/example.py
11901
+ - tracks/python/exercises/sgf-parsing/sgf_parsing.py
11902
+ - tracks/python/exercises/sgf-parsing/sgf_parsing_test.py
11895
11903
  - tracks/python/exercises/sieve/README.md
11896
11904
  - tracks/python/exercises/sieve/example.py
11897
11905
  - tracks/python/exercises/sieve/sieve.py
@@ -1,39 +0,0 @@
1
- final class BoardCoordinate {
2
-
3
- private final int row;
4
-
5
- private final int column;
6
-
7
- BoardCoordinate(final int row, final int column) throws IllegalArgumentException {
8
- this.row = row;
9
- this.column = column;
10
-
11
- validateInputs();
12
- }
13
-
14
- int getRow() {
15
- return row;
16
- }
17
-
18
- int getColumn() {
19
- return column;
20
- }
21
-
22
- private void validateInputs() throws IllegalArgumentException {
23
- validateCoordinateComponent(row, "row");
24
- validateCoordinateComponent(column, "column");
25
- }
26
-
27
- private void validateCoordinateComponent(final int value, final String componentName)
28
- throws IllegalArgumentException {
29
-
30
- if (value < 0) {
31
- throw new IllegalArgumentException("Coordinate must have positive " + componentName + ".");
32
- }
33
-
34
- if (value > 7) {
35
- throw new IllegalArgumentException("Coordinate must have " + componentName + " <= 7.");
36
- }
37
- }
38
-
39
- }