trackler 2.2.1.60 → 2.2.1.61
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/problem-specifications/exercises/beer-song/canonical-data.json +366 -31
- data/problem-specifications/exercises/beer-song/description.md +1 -1
- data/problem-specifications/exercises/pascals-triangle/canonical-data.json +19 -1
- data/problem-specifications/exercises/proverb/canonical-data.json +91 -0
- data/problem-specifications/exercises/proverb/description.md +5 -3
- data/tracks/c/README.md +0 -10
- data/tracks/c/config/maintainers.json +45 -0
- data/tracks/c/config.json +1 -2
- data/tracks/c/docs/TESTS.md +43 -44
- data/tracks/d/docs/INSTALLATION.md +1 -1
- data/tracks/delphi/exercises/beer-song/README.md +1 -1
- data/tracks/delphi/exercises/beer-song/inputdata.txt +3 -1
- data/tracks/delphi/exercises/beer-song/uBeerSongExample.pas +14 -5
- data/tracks/delphi/exercises/beer-song/uBeerSongTests.pas +58 -42
- data/tracks/delphi/exercises/nucleotide-count/README.md +2 -2
- data/tracks/ecmascript/config.json +14 -0
- data/tracks/ecmascript/exercises/house/README.md +146 -0
- data/tracks/ecmascript/exercises/house/example.js +62 -0
- data/tracks/ecmascript/exercises/house/house.spec.js +292 -0
- data/tracks/ecmascript/exercises/house/package.json +71 -0
- data/tracks/go/exercises/allergies/example.go +3 -2
- data/tracks/go/exercises/custom-set/cases_test.go +7 -2
- data/tracks/go/exercises/isogram/.meta/gen.go +55 -0
- data/tracks/go/exercises/isogram/cases_test.go +57 -0
- data/tracks/go/exercises/isogram/isogram_test.go +4 -20
- data/tracks/java/config.json +7 -1
- data/tracks/java/exercises/luhn/src/test/java/LuhnValidatorTest.java +6 -1
- data/tracks/javascript/.eslintignore +0 -3
- data/tracks/javascript/exercises/acronym/example.js +2 -1
- data/tracks/javascript/exercises/diamond/diamond.spec.js +3 -3
- data/tracks/javascript/exercises/diamond/example.js +2 -2
- data/tracks/javascript/exercises/sum-of-multiples/sum-of-multiples.spec.js +9 -9
- data/tracks/python/config.json +33 -11
- data/tracks/python/exercises/dominoes/README.md +28 -0
- data/tracks/python/exercises/dominoes/dominoes.py +2 -0
- data/tracks/python/exercises/dominoes/dominoes_test.py +114 -0
- data/tracks/python/exercises/dominoes/example.py +30 -0
- data/tracks/python/exercises/grains/grains_test.py +5 -7
- data/tracks/python/exercises/phone-number/example.py +7 -13
- data/tracks/python/exercises/phone-number/phone_number_test.py +15 -15
- data/tracks/python/exercises/poker/poker_test.py +93 -52
- data/tracks/python/exercises/react/README.md +30 -0
- data/tracks/python/exercises/react/example.py +65 -0
- data/tracks/python/exercises/react/react.py +17 -0
- data/tracks/python/exercises/react/react_test.py +136 -0
- data/tracks/rust/exercises/pascals-triangle/Cargo.toml +1 -1
- data/tracks/rust/exercises/pascals-triangle/tests/pascals-triangle.rs +56 -0
- data/tracks/swift/Package.swift +1 -1
- data/tracks/swift/config.json +11 -0
- data/tracks/swift/exercises/atbash-cipher/Sources/AtbashExample.swift +1 -1
- data/tracks/swift/exercises/bracket-push/Sources/BracketPushExample.swift +1 -1
- data/tracks/swift/exercises/collatz-conjecture/Package.swift +5 -0
- data/tracks/swift/exercises/collatz-conjecture/README.md +41 -0
- data/tracks/swift/exercises/collatz-conjecture/Sources/CollatzConjecture.swift +1 -0
- data/tracks/swift/exercises/collatz-conjecture/Sources/CollatzConjectureExample.swift +27 -0
- data/tracks/swift/exercises/collatz-conjecture/Tests/CollatzConjectureTests/CollatzConjectureTests.swift +40 -0
- data/tracks/swift/exercises/collatz-conjecture/Tests/LinuxMain.swift +6 -0
- data/tracks/swift/exercises/dominoes/Sources/DominoesExample.swift +3 -3
- data/tracks/swift/exercises/grains/Tests/GrainsTests/GrainsTests.swift +3 -3
- data/tracks/swift/exercises/kindergarten-garden/Sources/KindergartenGardenExample.swift +2 -2
- data/tracks/swift/exercises/meetup/Sources/MeetupExample.swift +1 -1
- data/tracks/swift/exercises/nucleotide-count/Sources/NucleotideCountExample.swift +2 -2
- data/tracks/swift/exercises/poker/Sources/PokerExample.swift +137 -131
- data/tracks/swift/exercises/rna-transcription/Sources/RnaTranscriptionExample.swift +2 -2
- data/tracks/swift/exercises/rotational-cipher/Sources/RotationalCipherExample.swift +12 -12
- metadata +24 -2
@@ -0,0 +1,30 @@
|
|
1
|
+
# React
|
2
|
+
|
3
|
+
Implement a basic reactive system.
|
4
|
+
|
5
|
+
Reactive programming is a programming paradigm that focuses on how values
|
6
|
+
are computed in terms of each other to allow a change to one value to
|
7
|
+
automatically propagate to other values, like in a spreadsheet.
|
8
|
+
|
9
|
+
Implement a basic reactive system with cells with settable values ("input"
|
10
|
+
cells) and cells with values computed in terms of other cells ("compute"
|
11
|
+
cells). Implement updates so that when an input value is changed, values
|
12
|
+
propagate to reach a new stable system state.
|
13
|
+
|
14
|
+
In addition, compute cells should allow for registering change notification
|
15
|
+
callbacks. Call a cell’s callbacks when the cell’s value in a new stable
|
16
|
+
state has changed from the previous stable state.
|
17
|
+
|
18
|
+
## Submitting Exercises
|
19
|
+
|
20
|
+
Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
|
21
|
+
|
22
|
+
For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`.
|
23
|
+
|
24
|
+
|
25
|
+
For more detailed information about running tests, code style and linting,
|
26
|
+
please see the [help page](http://exercism.io/languages/python).
|
27
|
+
|
28
|
+
|
29
|
+
## Submitting Incomplete Solutions
|
30
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class Cell(object):
|
2
|
+
def __init__(self, reactor, value=0, dependencies=set(),
|
3
|
+
updater=None):
|
4
|
+
self.reactor = reactor
|
5
|
+
self.index = len(reactor.cells)
|
6
|
+
reactor.cells.append(self)
|
7
|
+
self.value = value
|
8
|
+
self.dirty = False
|
9
|
+
self.dependencies = dependencies
|
10
|
+
self.dependents = set()
|
11
|
+
self.updater = updater
|
12
|
+
self.watchers = set()
|
13
|
+
if updater is not None:
|
14
|
+
self.update()
|
15
|
+
self.notify()
|
16
|
+
|
17
|
+
def add_watcher(self, watcher):
|
18
|
+
self.watchers.add(watcher)
|
19
|
+
|
20
|
+
def remove_watcher(self, watcher):
|
21
|
+
self.watchers.remove(watcher)
|
22
|
+
|
23
|
+
def set_value(self, value, top=True):
|
24
|
+
self.value = value
|
25
|
+
for d in self.dependents:
|
26
|
+
d.update()
|
27
|
+
if top:
|
28
|
+
self.reactor.notify()
|
29
|
+
|
30
|
+
def update(self):
|
31
|
+
if self.updater is not None:
|
32
|
+
values = [d.value for d in self.dependencies]
|
33
|
+
value = self.updater(values)
|
34
|
+
if self.value != value:
|
35
|
+
self.set_value(value, False)
|
36
|
+
self.dirty = True
|
37
|
+
|
38
|
+
def notify(self):
|
39
|
+
if self.dirty:
|
40
|
+
for watcher in self.watchers:
|
41
|
+
watcher(self, self.value)
|
42
|
+
self.dirty = False
|
43
|
+
|
44
|
+
def __hash__(self):
|
45
|
+
return self.index
|
46
|
+
|
47
|
+
|
48
|
+
class Reactor(object):
|
49
|
+
def __init__(self):
|
50
|
+
self.cells = []
|
51
|
+
|
52
|
+
def create_input_cell(self, value):
|
53
|
+
return Cell(self, value=value)
|
54
|
+
|
55
|
+
def create_compute_cell(self, dependencies, updater):
|
56
|
+
cell = Cell(self,
|
57
|
+
dependencies=dependencies,
|
58
|
+
updater=updater)
|
59
|
+
for d in dependencies:
|
60
|
+
d.dependents.add(cell)
|
61
|
+
return cell
|
62
|
+
|
63
|
+
def notify(self):
|
64
|
+
for cell in self.cells:
|
65
|
+
cell.notify()
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Cell(object):
|
2
|
+
def set_value(value):
|
3
|
+
pass
|
4
|
+
|
5
|
+
def add_watcher(self, watcher_callback):
|
6
|
+
pass
|
7
|
+
|
8
|
+
def remove_watcher(self, watcher_callback):
|
9
|
+
pass
|
10
|
+
|
11
|
+
|
12
|
+
class Reactor(object):
|
13
|
+
def create_input_cell(self, value):
|
14
|
+
pass
|
15
|
+
|
16
|
+
def create_compute_cell(self, dependencies, updater_callback):
|
17
|
+
pass
|
@@ -0,0 +1,136 @@
|
|
1
|
+
import unittest
|
2
|
+
|
3
|
+
from react import Reactor
|
4
|
+
|
5
|
+
|
6
|
+
class CallbackManager(object):
|
7
|
+
counter = 0
|
8
|
+
observed1 = []
|
9
|
+
observed2 = []
|
10
|
+
|
11
|
+
@staticmethod
|
12
|
+
def reset():
|
13
|
+
CallbackManager.counter = 0
|
14
|
+
CallbackManager.observed1 = []
|
15
|
+
CallbackManager.observed2 = []
|
16
|
+
|
17
|
+
@staticmethod
|
18
|
+
def count(sender, value):
|
19
|
+
CallbackManager.counter += 1
|
20
|
+
|
21
|
+
@staticmethod
|
22
|
+
def observe1(sender, value):
|
23
|
+
CallbackManager.observed1.append(value)
|
24
|
+
|
25
|
+
@staticmethod
|
26
|
+
def observe2(sender, value):
|
27
|
+
CallbackManager.observed2.append(value)
|
28
|
+
|
29
|
+
|
30
|
+
def increment(values):
|
31
|
+
return values[0] + 1
|
32
|
+
|
33
|
+
|
34
|
+
def decrement(values):
|
35
|
+
return values[0] - 1
|
36
|
+
|
37
|
+
|
38
|
+
def product(values):
|
39
|
+
return values[0] * values[1]
|
40
|
+
|
41
|
+
|
42
|
+
def minimum_of_2(values):
|
43
|
+
return values[0] + 1 if values[0] > 2 else 2
|
44
|
+
|
45
|
+
|
46
|
+
class ReactTest(unittest.TestCase):
|
47
|
+
def test_setting_input_changes_value(self):
|
48
|
+
reactor = Reactor()
|
49
|
+
inputCell1 = reactor.create_input_cell(1)
|
50
|
+
self.assertEqual(inputCell1.value, 1)
|
51
|
+
inputCell1.set_value(2)
|
52
|
+
self.assertEqual(inputCell1.value, 2)
|
53
|
+
|
54
|
+
def test_computed_cell_determined_by_dependencies(self):
|
55
|
+
reactor = Reactor()
|
56
|
+
inputCell1 = reactor.create_input_cell(1)
|
57
|
+
computeCell1 = reactor.create_compute_cell({inputCell1}, increment)
|
58
|
+
|
59
|
+
self.assertEqual(computeCell1.value, 2)
|
60
|
+
inputCell1.set_value(2)
|
61
|
+
self.assertEqual(computeCell1.value, 3)
|
62
|
+
|
63
|
+
def test_compute_cells_determined_by_other_compute_cells(self):
|
64
|
+
reactor = Reactor()
|
65
|
+
inputCell1 = reactor.create_input_cell(1)
|
66
|
+
computeCell1 = reactor.create_compute_cell({inputCell1}, increment)
|
67
|
+
computeCell2 = reactor.create_compute_cell({inputCell1}, decrement)
|
68
|
+
computeCell3 = reactor.create_compute_cell({computeCell1,
|
69
|
+
computeCell2},
|
70
|
+
product)
|
71
|
+
self.assertEqual(computeCell3.value, 0)
|
72
|
+
inputCell1.set_value(3)
|
73
|
+
self.assertEqual(computeCell3.value, 8)
|
74
|
+
|
75
|
+
def test_compute_cells_can_have_callbacks(self):
|
76
|
+
reactor = Reactor()
|
77
|
+
inputCell1 = reactor.create_input_cell(1)
|
78
|
+
computeCell1 = reactor.create_compute_cell({inputCell1}, increment)
|
79
|
+
observed = []
|
80
|
+
computeCell1.add_watcher(lambda sender, value: observed.append(value))
|
81
|
+
self.assertEqual(observed, [])
|
82
|
+
inputCell1.set_value(2)
|
83
|
+
self.assertEqual(observed, [3])
|
84
|
+
|
85
|
+
def test_callbacks__only_trigger_on_change(self):
|
86
|
+
reactor = Reactor()
|
87
|
+
inputCell1 = reactor.create_input_cell(1)
|
88
|
+
computeCell1 = reactor.create_compute_cell({inputCell1}, minimum_of_2)
|
89
|
+
|
90
|
+
CallbackManager.reset()
|
91
|
+
computeCell1.add_watcher(CallbackManager.count)
|
92
|
+
|
93
|
+
inputCell1.set_value(1)
|
94
|
+
self.assertEqual(CallbackManager.counter, 0)
|
95
|
+
inputCell1.set_value(2)
|
96
|
+
self.assertEqual(CallbackManager.counter, 0)
|
97
|
+
inputCell1.set_value(3)
|
98
|
+
self.assertEqual(CallbackManager.counter, 1)
|
99
|
+
|
100
|
+
def test_callbacks_can_be_removed(self):
|
101
|
+
reactor = Reactor()
|
102
|
+
inputCell1 = reactor.create_input_cell(1)
|
103
|
+
computeCell1 = reactor.create_compute_cell({inputCell1}, increment)
|
104
|
+
|
105
|
+
CallbackManager.reset()
|
106
|
+
computeCell1.add_watcher(CallbackManager.observe1)
|
107
|
+
computeCell1.add_watcher(CallbackManager.observe2)
|
108
|
+
|
109
|
+
inputCell1.set_value(2)
|
110
|
+
self.assertEqual(CallbackManager.observed1, [3])
|
111
|
+
self.assertEqual(CallbackManager.observed2, [3])
|
112
|
+
|
113
|
+
computeCell1.remove_watcher(CallbackManager.observe1)
|
114
|
+
inputCell1.set_value(3)
|
115
|
+
self.assertEqual(CallbackManager.observed1, [3])
|
116
|
+
self.assertEqual(CallbackManager.observed2, [3, 4])
|
117
|
+
|
118
|
+
def test_callbacks_only_called_once(self):
|
119
|
+
reactor = Reactor()
|
120
|
+
inputCell1 = reactor.create_input_cell(1)
|
121
|
+
computeCell1 = reactor.create_compute_cell({inputCell1}, increment)
|
122
|
+
computeCell2 = reactor.create_compute_cell({inputCell1}, decrement)
|
123
|
+
computeCell3 = reactor.create_compute_cell({computeCell2}, decrement)
|
124
|
+
computeCell4 = reactor.create_compute_cell({computeCell1,
|
125
|
+
computeCell3},
|
126
|
+
product)
|
127
|
+
|
128
|
+
CallbackManager.reset()
|
129
|
+
computeCell4.add_watcher(CallbackManager.count)
|
130
|
+
|
131
|
+
inputCell1.set_value(3)
|
132
|
+
self.assertEqual(CallbackManager.counter, 1)
|
133
|
+
|
134
|
+
|
135
|
+
if __name__ == '__main__':
|
136
|
+
unittest.main()
|
@@ -40,3 +40,59 @@ fn last_of_four_rows() {
|
|
40
40
|
let expected: Vec<u32> = vec![1, 3, 3, 1];
|
41
41
|
assert_eq!(Some(expected), pt.rows().pop());
|
42
42
|
}
|
43
|
+
|
44
|
+
#[test]
|
45
|
+
#[ignore]
|
46
|
+
fn five_rows() {
|
47
|
+
let pt = PascalsTriangle::new(5);
|
48
|
+
let expected: Vec<Vec<u32>> = vec![vec![1],
|
49
|
+
vec![1, 1],
|
50
|
+
vec![1, 2, 1],
|
51
|
+
vec![1, 3, 3, 1],
|
52
|
+
vec![1, 4, 6, 4, 1]];
|
53
|
+
assert_eq!(expected, pt.rows());
|
54
|
+
}
|
55
|
+
|
56
|
+
#[test]
|
57
|
+
#[ignore]
|
58
|
+
fn six_rows() {
|
59
|
+
let pt = PascalsTriangle::new(6);
|
60
|
+
let expected: Vec<Vec<u32>> = vec![vec![1],
|
61
|
+
vec![1, 1],
|
62
|
+
vec![1, 2, 1],
|
63
|
+
vec![1, 3, 3, 1],
|
64
|
+
vec![1, 4, 6, 4, 1],
|
65
|
+
vec![1, 5, 10, 10, 5, 1]];
|
66
|
+
assert_eq!(expected, pt.rows());
|
67
|
+
}
|
68
|
+
|
69
|
+
#[test]
|
70
|
+
#[ignore]
|
71
|
+
fn seven_rows() {
|
72
|
+
let pt = PascalsTriangle::new(7);
|
73
|
+
let expected: Vec<Vec<u32>> = vec![vec![1],
|
74
|
+
vec![1, 1],
|
75
|
+
vec![1, 2, 1],
|
76
|
+
vec![1, 3, 3, 1],
|
77
|
+
vec![1, 4, 6, 4, 1],
|
78
|
+
vec![1, 5, 10, 10, 5, 1],
|
79
|
+
vec![1, 6, 15, 20, 15, 6, 1]];
|
80
|
+
assert_eq!(expected, pt.rows());
|
81
|
+
}
|
82
|
+
|
83
|
+
#[test]
|
84
|
+
#[ignore]
|
85
|
+
fn ten_rows() {
|
86
|
+
let pt = PascalsTriangle::new(10);
|
87
|
+
let expected: Vec<Vec<u32>> = vec![vec![1],
|
88
|
+
vec![1, 1],
|
89
|
+
vec![1, 2, 1],
|
90
|
+
vec![1, 3, 3, 1],
|
91
|
+
vec![1, 4, 6, 4, 1],
|
92
|
+
vec![1, 5, 10, 10, 5, 1],
|
93
|
+
vec![1, 6, 15, 20, 15, 6, 1],
|
94
|
+
vec![1, 7, 21, 35, 35, 21, 7, 1],
|
95
|
+
vec![1, 8, 28, 56, 70, 56, 28, 8, 1],
|
96
|
+
vec![1, 9, 36, 84, 126, 126, 84, 36, 9, 1]];
|
97
|
+
assert_eq!(expected, pt.rows());
|
98
|
+
}
|
data/tracks/swift/Package.swift
CHANGED
@@ -8,7 +8,7 @@ if
|
|
8
8
|
let jsonData = try? Data(contentsOf: URL(fileURLWithPath: path), options: Data.ReadingOptions.mappedIfSafe) ,
|
9
9
|
let json = try? JSONSerialization.jsonObject(with: jsonData, options: []) ,
|
10
10
|
let jsonDict = json as? [String: Any],
|
11
|
-
let exercisesDict = jsonDict["exercises"] as? [[String:Any]],
|
11
|
+
let exercisesDict = jsonDict["exercises"] as? [[String: Any]],
|
12
12
|
let exercises = exercisesDict.map({ $0["slug"] }) as? [String],
|
13
13
|
let deprecated = jsonDict["deprecated"] as? [String] {
|
14
14
|
|
data/tracks/swift/config.json
CHANGED
@@ -337,6 +337,17 @@
|
|
337
337
|
"unlocked_by": null,
|
338
338
|
"uuid": "ea9feed8-481a-4bd0-9af8-7ca44433c266"
|
339
339
|
},
|
340
|
+
{
|
341
|
+
"core": false,
|
342
|
+
"difficulty": 3,
|
343
|
+
"slug": "collatz-conjecture",
|
344
|
+
"topics": [
|
345
|
+
"integers",
|
346
|
+
"mathematics"
|
347
|
+
],
|
348
|
+
"unlocked_by": null,
|
349
|
+
"uuid": "899bd49a-0970-9a80-5e6b-2adf5bfd0bf79f480ba"
|
350
|
+
},
|
340
351
|
{
|
341
352
|
"core": false,
|
342
353
|
"difficulty": 4,
|
@@ -13,7 +13,7 @@ struct Atbash {
|
|
13
13
|
return returnString
|
14
14
|
}
|
15
15
|
|
16
|
-
static let cipherDictApply: [Character
|
16
|
+
static let cipherDictApply: [Character: Character] = ["a": "z", "b": "y", "c": "x", "d": "w", "e": "v", "f": "u", "g": "t", "h": "s", "i": "r", "j": "q", "k": "p", "l": "o", "m": "n", "n": "m", "o": "l", "p": "k", "q": "j", "r": "i", "s": "h", "t": "g", "u": "f", "v": "e", "w": "d", "x": "c", "y": "b", "z": "a"]
|
17
17
|
|
18
18
|
static func encode( _ valueIn: String) -> String {
|
19
19
|
let value = stripWhiteSpaceAndPunctuations(valueIn.lowercased() )
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Collatz Conjecture
|
2
|
+
|
3
|
+
The Collatz Conjecture or 3x+1 problem can be summarized as follows:
|
4
|
+
|
5
|
+
Take any positive integer n. If n is even, divide n by 2 to get n / 2. If n is
|
6
|
+
odd, multiply n by 3 and add 1 to get 3n + 1. Repeat the process indefinitely.
|
7
|
+
The conjecture states that no matter which number you start with, you will
|
8
|
+
always reach 1 eventually.
|
9
|
+
|
10
|
+
Given a number n, return the number of steps required to reach 1.
|
11
|
+
|
12
|
+
## Examples
|
13
|
+
|
14
|
+
Starting with n = 12, the steps would be as follows:
|
15
|
+
|
16
|
+
0. 12
|
17
|
+
1. 6
|
18
|
+
2. 3
|
19
|
+
3. 10
|
20
|
+
4. 5
|
21
|
+
5. 16
|
22
|
+
6. 8
|
23
|
+
7. 4
|
24
|
+
8. 2
|
25
|
+
9. 1
|
26
|
+
|
27
|
+
Resulting in 9 steps. So for input n = 12, the return value would be 9.
|
28
|
+
|
29
|
+
## Setup
|
30
|
+
|
31
|
+
Go through the project setup instructions for Xcode using Swift:
|
32
|
+
|
33
|
+
http://exercism.io/languages/swift
|
34
|
+
|
35
|
+
## Source
|
36
|
+
|
37
|
+
An unsolved problem in mathematics named after mathematician Lothar Collatz [https://en.wikipedia.org/wiki/3x_%2B_1_problem](https://en.wikipedia.org/wiki/3x_%2B_1_problem)
|
38
|
+
|
39
|
+
## Submitting Incomplete Solutions
|
40
|
+
|
41
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
@@ -0,0 +1 @@
|
|
1
|
+
//Solution goes in Sources
|
@@ -0,0 +1,27 @@
|
|
1
|
+
enum CollatzConjectureError: Error {
|
2
|
+
case numberNotPositive
|
3
|
+
}
|
4
|
+
|
5
|
+
struct CollatzConjecture {
|
6
|
+
|
7
|
+
static func steps(_ number: Int) throws -> Int? {
|
8
|
+
guard number > 0 else {
|
9
|
+
throw CollatzConjectureError.numberNotPositive
|
10
|
+
}
|
11
|
+
|
12
|
+
var number = number
|
13
|
+
var steps = 0
|
14
|
+
|
15
|
+
while number > 1 {
|
16
|
+
steps += 1
|
17
|
+
|
18
|
+
if number % 2 == 0 {
|
19
|
+
number /= 2
|
20
|
+
} else {
|
21
|
+
number = number * 3 + 1
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
return steps
|
26
|
+
}
|
27
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import XCTest
|
2
|
+
@testable import CollatzConjecture
|
3
|
+
|
4
|
+
class CollatzConjectureTests: XCTestCase {
|
5
|
+
|
6
|
+
func testZeroStepsForOne() {
|
7
|
+
XCTAssertEqual(0, try CollatzConjecture.steps(1))
|
8
|
+
}
|
9
|
+
|
10
|
+
func testDivideIfEven() {
|
11
|
+
XCTAssertEqual(4, try CollatzConjecture.steps(16))
|
12
|
+
}
|
13
|
+
|
14
|
+
func testEvenAndOddSteps() {
|
15
|
+
XCTAssertEqual(9, try CollatzConjecture.steps(12))
|
16
|
+
}
|
17
|
+
|
18
|
+
func testLargeNumberOfEvenAndOddSteps() {
|
19
|
+
XCTAssertEqual(152, try CollatzConjecture.steps(1_000_000))
|
20
|
+
}
|
21
|
+
|
22
|
+
func testZeroIsAnError() {
|
23
|
+
XCTAssertThrowsError(try CollatzConjecture.steps(0))
|
24
|
+
}
|
25
|
+
|
26
|
+
func testNegativeValueIsAnError() {
|
27
|
+
XCTAssertThrowsError(try CollatzConjecture.steps(-15))
|
28
|
+
}
|
29
|
+
|
30
|
+
static var allTests: [(String, (CollatzConjectureTests) -> () throws -> Void)] {
|
31
|
+
return [
|
32
|
+
("testZeroStepsForOne", testZeroStepsForOne),
|
33
|
+
("testDivideIfEven", testDivideIfEven),
|
34
|
+
("testEvenAndOddSteps", testEvenAndOddSteps),
|
35
|
+
("testLargeNumberOfEvenAndOddSteps", testLargeNumberOfEvenAndOddSteps),
|
36
|
+
("testZeroIsAnError", testZeroIsAnError),
|
37
|
+
("testNegativeValueIsAnError", testNegativeValueIsAnError),
|
38
|
+
]
|
39
|
+
}
|
40
|
+
}
|
@@ -69,7 +69,7 @@ class Bone: CustomStringConvertible, Equatable {
|
|
69
69
|
var available: Int?
|
70
70
|
var connectedTo: Bone?
|
71
71
|
var description: String {
|
72
|
-
return "\(value)|\(connected)|\(available) "
|
72
|
+
return "\(value)|\(connected)|\(String(describing: available)) "
|
73
73
|
}
|
74
74
|
@discardableResult
|
75
75
|
func connect(_ input: Bone) -> Bool {
|
@@ -146,10 +146,10 @@ class Bone: CustomStringConvertible, Equatable {
|
|
146
146
|
|
147
147
|
switch (connected, input.connected) {
|
148
148
|
case (1, 0):
|
149
|
-
guard
|
149
|
+
guard available != nil else { return false }
|
150
150
|
oneZero()
|
151
151
|
case (0, 1):
|
152
|
-
guard
|
152
|
+
guard input.available != nil else { return false }
|
153
153
|
zeroOne()
|
154
154
|
case (1, 1):
|
155
155
|
oneOne()
|
@@ -8,7 +8,7 @@ class GrainsTests: XCTestCase {
|
|
8
8
|
if case let Grains.GrainsError.inputTooHigh(message) = error {
|
9
9
|
XCTAssertTrue(message == "Input[65] invalid. Input should be between 1 and 64 (inclusive)")
|
10
10
|
} else {
|
11
|
-
XCTFail()
|
11
|
+
XCTFail("Expected error not thrown")
|
12
12
|
}
|
13
13
|
}
|
14
14
|
}
|
@@ -18,7 +18,7 @@ class GrainsTests: XCTestCase {
|
|
18
18
|
if case let Grains.GrainsError.inputTooLow(message) = error {
|
19
19
|
XCTAssertTrue(message == "Input[0] invalid. Input should be between 1 and 64 (inclusive)")
|
20
20
|
} else {
|
21
|
-
XCTFail()
|
21
|
+
XCTFail("Expected error not thrown")
|
22
22
|
}
|
23
23
|
}
|
24
24
|
}
|
@@ -28,7 +28,7 @@ class GrainsTests: XCTestCase {
|
|
28
28
|
if case let Grains.GrainsError.inputTooLow(message) = error {
|
29
29
|
XCTAssertTrue(message == "Input[-1] invalid. Input should be between 1 and 64 (inclusive)")
|
30
30
|
} else {
|
31
|
-
XCTFail()
|
31
|
+
XCTFail("Expected error not thrown")
|
32
32
|
}
|
33
33
|
}
|
34
34
|
}
|
@@ -10,7 +10,7 @@ enum Plant: String {
|
|
10
10
|
struct Garden {
|
11
11
|
static private let defaultChildren = ["Alice", "Bob", "Charlie", "David", "Eve", "Fred", "Ginny", "Harriet", "Ileana", "Joseph", "Kincaid", "Larry"]
|
12
12
|
|
13
|
-
private let pots: [String
|
13
|
+
private let pots: [String: [Plant]]
|
14
14
|
|
15
15
|
init(_ diagram: String, children: [String] = defaultChildren) {
|
16
16
|
self.pots = Garden.parse(diagram, children: children)
|
@@ -23,7 +23,7 @@ struct Garden {
|
|
23
23
|
return plants
|
24
24
|
}
|
25
25
|
|
26
|
-
private static func parse(_ diagram: String, children: [String]) -> [String
|
26
|
+
private static func parse(_ diagram: String, children: [String]) -> [String: [Plant]] {
|
27
27
|
let sortedChildren = children.sorted(by: <)
|
28
28
|
let lines = diagram.components(separatedBy: CharacterSet.newlines)
|
29
29
|
var result = [String: [Plant]]()
|
@@ -7,7 +7,7 @@ enum Nucleobase: Character {
|
|
7
7
|
|
8
8
|
struct DNA {
|
9
9
|
|
10
|
-
var nucleotideCounts: [Nucleobase:Int] = [ .adenine: 0, .thymine: 0, .cytosine: 0, .guanine: 0 ]
|
10
|
+
var nucleotideCounts: [Nucleobase: Int] = [ .adenine: 0, .thymine: 0, .cytosine: 0, .guanine: 0 ]
|
11
11
|
|
12
12
|
init?(strand: String) {
|
13
13
|
let enumarated = strand.characters.enumerated()
|
@@ -26,7 +26,7 @@ struct DNA {
|
|
26
26
|
}
|
27
27
|
|
28
28
|
func counts() -> [String: Int] {
|
29
|
-
var nCounts: [String:Int] = [:]
|
29
|
+
var nCounts: [String: Int] = [:]
|
30
30
|
for (k, v) in nucleotideCounts {
|
31
31
|
nCounts[String(k.rawValue)] = v
|
32
32
|
}
|