trackler 2.2.1.127 → 2.2.1.128

Sign up to get free protection for your applications and to get access to all the features.
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
- }