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.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/tracks/c/docs/RESOURCES.md +0 -1
- data/tracks/delphi/exercises/isbn-verifier/uTestISBNVerifier.pas +2 -2
- data/tracks/ecmascript/config.json +2 -2
- data/tracks/elm/config/maintainers.json +11 -11
- data/tracks/elm/config.json +170 -245
- data/tracks/fsharp/exercises/pov/PovTest.fs +1 -1
- data/tracks/java/exercises/queen-attack/.meta/src/reference/java/Queen.java +38 -0
- data/tracks/java/exercises/queen-attack/.meta/src/reference/java/QueenAttackCalculator.java +11 -12
- data/tracks/java/exercises/queen-attack/.meta/version +1 -1
- data/tracks/java/exercises/queen-attack/src/test/java/QueenAttackCalculatorTest.java +50 -44
- data/tracks/python/config.json +26 -0
- data/tracks/python/exercises/bank-account/README.md +53 -0
- data/tracks/python/exercises/bank-account/bank_account.py +18 -0
- data/tracks/python/exercises/bank-account/bank_account_test.py +120 -0
- data/tracks/python/exercises/bank-account/example.py +35 -0
- data/tracks/python/exercises/go-counting/example.py +6 -6
- data/tracks/python/exercises/go-counting/go_counting.py +3 -2
- data/tracks/python/exercises/go-counting/go_counting_test.py +58 -51
- data/tracks/python/exercises/house/example.py +7 -13
- data/tracks/python/exercises/house/house_test.py +79 -204
- data/tracks/python/exercises/meetup/example.py +10 -1
- data/tracks/python/exercises/meetup/meetup_test.py +1 -6
- data/tracks/python/exercises/pascals-triangle/example.py +12 -14
- data/tracks/python/exercises/pascals-triangle/pascals_triangle.py +1 -9
- data/tracks/python/exercises/pascals-triangle/pascals_triangle_test.py +43 -29
- data/tracks/python/exercises/sgf-parsing/README.md +110 -0
- data/tracks/python/exercises/sgf-parsing/example.py +100 -0
- data/tracks/python/exercises/sgf-parsing/sgf_parsing.py +26 -0
- data/tracks/python/exercises/sgf-parsing/sgf_parsing_test.py +94 -0
- data/tracks/typescript/config.json +1 -1
- data/tracks/typescript/exercises/pangram/pangram.example.ts +2 -2
- data/tracks/typescript/exercises/pangram/pangram.test.ts +0 -2
- data/tracks/typescript/exercises/pangram/pangram.ts +0 -11
- metadata +11 -3
- 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
|
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
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
self.assertEqual(
|
15
|
-
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
self.assertEqual(
|
27
|
-
|
28
|
-
def
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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()
|
@@ -2,7 +2,7 @@ const aToZ = [...Array<string>(26)].map( ( _ , index) => {
|
|
2
2
|
return String.fromCharCode(index + 65)
|
3
3
|
})
|
4
4
|
|
5
|
-
class
|
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
|
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
|
})
|
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.
|
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-
|
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/
|
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
|
-
}
|