trackler 2.2.1.48 → 2.2.1.49
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/grains/canonical-data.json +1 -1
- data/problem-specifications/exercises/isbn-verifier/description.md +1 -1
- data/tracks/dart/exercises/anagram/pubspec.lock +10 -10
- data/tracks/dart/exercises/bob/pubspec.lock +4 -4
- data/tracks/dart/exercises/difference-of-squares/pubspec.lock +4 -4
- data/tracks/dart/exercises/gigasecond/pubspec.lock +4 -4
- data/tracks/dart/exercises/hamming/pubspec.lock +4 -4
- data/tracks/dart/exercises/hello-world/pubspec.lock +4 -4
- data/tracks/dart/exercises/leap/pubspec.lock +4 -4
- data/tracks/dart/exercises/phone-number/pubspec.lock +4 -4
- data/tracks/dart/exercises/raindrops/pubspec.lock +17 -5
- data/tracks/dart/exercises/rna-transcription/pubspec.lock +4 -4
- data/tracks/dart/exercises/word-count/pubspec.lock +4 -4
- data/tracks/dart/pubspec.lock +3 -3
- data/tracks/fsharp/exercises/largest-series-product/Example.fs +18 -4
- data/tracks/fsharp/exercises/largest-series-product/LargestSeriesProduct.fs +1 -1
- data/tracks/fsharp/exercises/largest-series-product/LargestSeriesProductTest.fs +80 -36
- data/tracks/fsharp/generators/Exercise.fs +1 -1
- data/tracks/fsharp/generators/Generators.fs +10 -0
- data/tracks/gnu-apl/config.json +14 -0
- data/tracks/gnu-apl/exercises/difference-of-squares/README.md +19 -0
- data/tracks/gnu-apl/exercises/difference-of-squares/difference-of-squares-example.apl +13 -0
- data/tracks/gnu-apl/exercises/difference-of-squares/difference-of-squares.tc +38 -0
- data/tracks/gnu-apl/exercises/pangram/README.md +15 -0
- data/tracks/gnu-apl/exercises/pangram/pangram-example.apl +14 -0
- data/tracks/gnu-apl/exercises/pangram/pangram.tc +40 -0
- data/tracks/gnu-apl/exercises/raindrops/raindrops.tc +1 -1
- data/tracks/java/exercises/bracket-push/.meta/version +1 -0
- data/tracks/java/exercises/complex-numbers/.meta/version +1 -0
- data/tracks/java/exercises/ocr-numbers/.meta/version +1 -0
- data/tracks/java/exercises/queen-attack/.meta/version +1 -0
- data/tracks/java/exercises/rectangles/.meta/version +1 -0
- data/tracks/java/exercises/robot-simulator/.meta/version +1 -0
- data/tracks/java/exercises/secret-handshake/.meta/version +1 -0
- data/tracks/java/exercises/sublist/.meta/version +1 -0
- data/tracks/perl6/exercises/accumulate/accumulate.t +1 -6
- data/tracks/perl6/exercises/all-your-base/all-your-base.t +14 -19
- data/tracks/perl6/exercises/allergies/Allergies.pm6 +1 -1
- data/tracks/perl6/exercises/allergies/Example.pm6 +1 -1
- data/tracks/perl6/exercises/allergies/allergies.t +25 -29
- data/tracks/perl6/exercises/allergies/example.yaml +11 -10
- data/tracks/perl6/exercises/anagram/anagram.t +14 -19
- data/tracks/perl6/exercises/atbash-cipher/atbash-cipher.t +14 -19
- data/tracks/perl6/exercises/bob/bob.t +16 -23
- data/tracks/perl6/exercises/bob/example.yaml +1 -3
- data/tracks/perl6/exercises/clock/clock.t +14 -19
- data/tracks/perl6/exercises/flatten-array/flatten-array.t +14 -19
- data/tracks/perl6/exercises/grade-school/grade-school.t +1 -6
- data/tracks/perl6/exercises/grains/grains.t +15 -20
- data/tracks/perl6/exercises/hello-world/example.yaml +1 -3
- data/tracks/perl6/exercises/hello-world/hello-world.t +16 -23
- data/tracks/perl6/exercises/leap/leap.t +14 -19
- data/tracks/perl6/exercises/linked-list/example.yaml +59 -59
- data/tracks/perl6/exercises/linked-list/linked-list.t +59 -64
- data/tracks/perl6/exercises/luhn/luhn.t +14 -19
- data/tracks/perl6/exercises/phone-number/phone-number.t +14 -19
- data/tracks/perl6/exercises/raindrops/raindrops.t +14 -19
- data/tracks/perl6/exercises/rna-transcription/rna-transcription.t +14 -19
- data/tracks/perl6/exercises/robot-name/robot-name.t +1 -6
- data/tracks/perl6/exercises/scrabble-score/scrabble-score.t +14 -19
- data/tracks/perl6/exercises/space-age/space-age.t +14 -19
- data/tracks/perl6/exercises/word-count/word-count.t +14 -19
- data/tracks/perl6/exercises/wordy/wordy.t +14 -19
- data/tracks/perl6/templates/test.mustache +19 -25
- data/tracks/purescript/config.json +12 -0
- data/tracks/purescript/exercises/sum-of-multiples/README.md +15 -0
- data/tracks/purescript/exercises/sum-of-multiples/bower.json +26 -0
- data/tracks/purescript/exercises/sum-of-multiples/examples/src/SumOfMultiples.purs +16 -0
- data/tracks/purescript/exercises/sum-of-multiples/src/SumOfMultiples.purs +3 -0
- data/tracks/purescript/exercises/sum-of-multiples/test/Main.purs +63 -0
- data/tracks/python/README.md +5 -1
- data/tracks/python/config.json +52 -9
- data/tracks/python/exercises/allergies/allergies_test.py +7 -7
- data/tracks/python/exercises/allergies/example.py +1 -1
- data/tracks/python/exercises/binary-search/binary_search_test.py +8 -5
- data/tracks/python/exercises/binary/binary_test.py +8 -4
- data/tracks/python/exercises/book-store/example.py +1 -1
- data/tracks/python/exercises/clock/clock.py +3 -0
- data/tracks/python/exercises/clock/clock_test.py +16 -16
- data/tracks/python/exercises/clock/example.py +1 -1
- data/tracks/python/exercises/list-ops/example.py +10 -29
- data/tracks/python/exercises/list-ops/list_ops.py +8 -12
- data/tracks/python/exercises/list-ops/list_ops_test.py +55 -86
- data/tracks/python/exercises/meetup/meetup_test.py +2 -2
- data/tracks/python/exercises/minesweeper/minesweeper_test.py +6 -3
- data/tracks/python/exercises/ocr-numbers/ocr_numbers_test.py +11 -8
- data/tracks/python/exercises/pangram/pangram_test.py +25 -16
- data/tracks/python/exercises/point-mutations/point_mutations.py +1 -1
- data/tracks/python/exercises/pythagorean-triplet/pythagorean_triplet_test.py +2 -1
- data/tracks/python/exercises/saddle-points/saddle_points_test.py +2 -1
- data/tracks/python/exercises/simple-cipher/simple_cipher_test.py +4 -2
- data/tracks/python/exercises/triangle/triangle_test.py +10 -5
- data/tracks/python/exercises/wordy/wordy_test.py +8 -5
- data/tracks/python/exercises/zipper/README.md +43 -0
- data/tracks/python/exercises/zipper/example.py +41 -0
- data/tracks/python/exercises/zipper/zipper.py +28 -0
- data/tracks/python/exercises/zipper/zipper_test.py +82 -0
- data/tracks/racket/.travis.yml +1 -1
- data/tracks/racket/config.json +14 -0
- data/tracks/racket/exercises/meetup/README.md +54 -0
- data/tracks/racket/exercises/meetup/example.rkt +45 -0
- data/tracks/racket/exercises/meetup/meetup-test.rkt +39 -0
- data/tracks/racket/exercises/meetup/meetup.rkt +3 -0
- metadata +29 -2
@@ -68,8 +68,10 @@ class CipherTest(unittest.TestCase):
|
|
68
68
|
'All items in the key must be chars and lowercase!')
|
69
69
|
|
70
70
|
def test_cipher_wrong_key(self):
|
71
|
-
self.assertRaises(ValueError
|
72
|
-
|
71
|
+
with self.assertRaises(ValueError):
|
72
|
+
Cipher('a1cde')
|
73
|
+
with self.assertRaises(ValueError):
|
74
|
+
Cipher('aBcde')
|
73
75
|
|
74
76
|
|
75
77
|
if __name__ == '__main__':
|
@@ -34,19 +34,24 @@ class TriangleTests(unittest.TestCase):
|
|
34
34
|
self.assertEqual(Triangle(0.4, 0.6, 0.3).kind(), "scalene")
|
35
35
|
|
36
36
|
def test_triangles_with_no_size_are_illegal(self):
|
37
|
-
self.assertRaises(TriangleError
|
37
|
+
with self.assertRaises(TriangleError):
|
38
|
+
Triangle(0, 0, 0)
|
38
39
|
|
39
40
|
def test_triangles_with_negative_sides_are_illegal(self):
|
40
|
-
self.assertRaises(TriangleError
|
41
|
+
with self.assertRaises(TriangleError):
|
42
|
+
Triangle(3, 4, -5)
|
41
43
|
|
42
44
|
def test_triangles_violating_triangle_inequality_are_illegal(self):
|
43
|
-
self.assertRaises(TriangleError
|
45
|
+
with self.assertRaises(TriangleError):
|
46
|
+
Triangle(1, 1, 3)
|
44
47
|
|
45
48
|
def test_triangles_violating_triangle_inequality_are_illegal_2(self):
|
46
|
-
self.assertRaises(TriangleError
|
49
|
+
with self.assertRaises(TriangleError):
|
50
|
+
Triangle(2, 4, 2)
|
47
51
|
|
48
52
|
def test_triangles_violating_triangle_inequality_are_illegal_3(self):
|
49
|
-
self.assertRaises(TriangleError
|
53
|
+
with self.assertRaises(TriangleError):
|
54
|
+
Triangle(7, 3, 2)
|
50
55
|
|
51
56
|
|
52
57
|
if __name__ == '__main__':
|
@@ -49,17 +49,20 @@ class WordyTest(unittest.TestCase):
|
|
49
49
|
calculate("What is -12000 divided by 25 divided by -30?"), 16)
|
50
50
|
|
51
51
|
def test_invalid_operation(self):
|
52
|
-
self.assertRaises(ValueError
|
52
|
+
with self.assertRaises(ValueError):
|
53
|
+
calculate("What is 4 xor 7?")
|
53
54
|
|
54
55
|
def test_missing_operation(self):
|
55
|
-
self.assertRaises(ValueError
|
56
|
+
with self.assertRaises(ValueError):
|
57
|
+
calculate("What is 2 2 minus 3?")
|
56
58
|
|
57
59
|
def test_missing_number(self):
|
58
|
-
self.assertRaises(ValueError
|
59
|
-
|
60
|
+
with self.assertRaises(ValueError):
|
61
|
+
calculate("What is 7 plus multiplied by -2?")
|
60
62
|
|
61
63
|
def test_irrelevant_question(self):
|
62
|
-
self.assertRaises(ValueError
|
64
|
+
with self.assertRaises(ValueError):
|
65
|
+
calculate("Which is greater, 3 or 2?")
|
63
66
|
|
64
67
|
|
65
68
|
if __name__ == '__main__':
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Zipper
|
2
|
+
|
3
|
+
Creating a zipper for a binary tree.
|
4
|
+
|
5
|
+
[Zippers](https://en.wikipedia.org/wiki/Zipper_%28data_structure%29) are
|
6
|
+
a purely functional way of navigating within a data structure and
|
7
|
+
manipulating it. They essentially contain a data structure and a
|
8
|
+
pointer into that data structure (called the focus).
|
9
|
+
|
10
|
+
For example given a rose tree (where each node contains a value and a
|
11
|
+
list of child nodes) a zipper might support these operations:
|
12
|
+
|
13
|
+
- `from_tree` (get a zipper out of a rose tree, the focus is on the root node)
|
14
|
+
- `to_tree` (get the rose tree out of the zipper)
|
15
|
+
- `value` (get the value of the focus node)
|
16
|
+
- `prev` (move the focus to the previous child of the same parent,
|
17
|
+
returns a new zipper)
|
18
|
+
- `next` (move the focus to the next child of the same parent, returns a
|
19
|
+
new zipper)
|
20
|
+
- `up` (move the focus to the parent, returns a new zipper)
|
21
|
+
- `set_value` (set the value of the focus node, returns a new zipper)
|
22
|
+
- `insert_before` (insert a new subtree before the focus node, it
|
23
|
+
becomes the `prev` of the focus node, returns a new zipper)
|
24
|
+
- `insert_after` (insert a new subtree after the focus node, it becomes
|
25
|
+
the `next` of the focus node, returns a new zipper)
|
26
|
+
- `delete` (removes the focus node and all subtrees, focus moves to the
|
27
|
+
`next` node if possible otherwise to the `prev` node if possible,
|
28
|
+
otherwise to the parent node, returns a new zipper)
|
29
|
+
|
30
|
+
### Submitting Exercises
|
31
|
+
|
32
|
+
Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
|
33
|
+
|
34
|
+
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`.
|
35
|
+
|
36
|
+
|
37
|
+
For more detailed information about running tests, code style and linting,
|
38
|
+
please see the [help page](http://exercism.io/languages/python).
|
39
|
+
|
40
|
+
|
41
|
+
## Submitting Incomplete Solutions
|
42
|
+
|
43
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Zipper(object):
|
2
|
+
@staticmethod
|
3
|
+
def from_tree(tree):
|
4
|
+
return Zipper(dict(tree), [])
|
5
|
+
|
6
|
+
def __init__(self, tree, ancestors):
|
7
|
+
self.tree = tree
|
8
|
+
self.ancestors = ancestors
|
9
|
+
|
10
|
+
def value(self):
|
11
|
+
return self.tree['value']
|
12
|
+
|
13
|
+
def set_value(self, value):
|
14
|
+
self.tree['value'] = value
|
15
|
+
return self
|
16
|
+
|
17
|
+
def left(self):
|
18
|
+
if self.tree['left'] is None:
|
19
|
+
return None
|
20
|
+
return Zipper(self.tree['left'], self.ancestors + [self.tree])
|
21
|
+
|
22
|
+
def set_left(self, tree):
|
23
|
+
self.tree['left'] = tree
|
24
|
+
return self
|
25
|
+
|
26
|
+
def right(self):
|
27
|
+
if self.tree['right'] is None:
|
28
|
+
return None
|
29
|
+
return Zipper(self.tree['right'], self.ancestors + [self.tree])
|
30
|
+
|
31
|
+
def set_right(self, tree):
|
32
|
+
self.tree['right'] = tree
|
33
|
+
return self
|
34
|
+
|
35
|
+
def up(self):
|
36
|
+
return Zipper(self.ancestors[-1], self.ancestors[:-1])
|
37
|
+
|
38
|
+
def to_tree(self):
|
39
|
+
if any(self.ancestors):
|
40
|
+
return self.ancestors[0]
|
41
|
+
return self.tree
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Zipper(object):
|
2
|
+
@staticmethod
|
3
|
+
def from_tree(tree):
|
4
|
+
pass
|
5
|
+
|
6
|
+
def value(self):
|
7
|
+
pass
|
8
|
+
|
9
|
+
def set_value(self):
|
10
|
+
pass
|
11
|
+
|
12
|
+
def left(self):
|
13
|
+
pass
|
14
|
+
|
15
|
+
def set_left(self):
|
16
|
+
pass
|
17
|
+
|
18
|
+
def right(self):
|
19
|
+
pass
|
20
|
+
|
21
|
+
def set_right(self):
|
22
|
+
pass
|
23
|
+
|
24
|
+
def up(self):
|
25
|
+
pass
|
26
|
+
|
27
|
+
def to_tree(self):
|
28
|
+
pass
|
@@ -0,0 +1,82 @@
|
|
1
|
+
import unittest
|
2
|
+
|
3
|
+
from zipper import Zipper
|
4
|
+
|
5
|
+
# Tests adapted from `problem-specifications//canonical-data.json` @ v1.0.0
|
6
|
+
|
7
|
+
|
8
|
+
def bt(value, left, right):
|
9
|
+
return {
|
10
|
+
'value': value,
|
11
|
+
'left': left,
|
12
|
+
'right': right
|
13
|
+
}
|
14
|
+
|
15
|
+
|
16
|
+
def leaf(value):
|
17
|
+
return bt(value, None, None)
|
18
|
+
|
19
|
+
|
20
|
+
EMPTY_TREE = None
|
21
|
+
|
22
|
+
|
23
|
+
def create_trees():
|
24
|
+
t1 = bt(1, bt(2, EMPTY_TREE, leaf(3)), leaf(4))
|
25
|
+
t2 = bt(1, bt(5, EMPTY_TREE, leaf(3)), leaf(4))
|
26
|
+
t3 = bt(1, bt(2, leaf(5), leaf(3)), leaf(4))
|
27
|
+
t4 = bt(1, leaf(2), leaf(4))
|
28
|
+
return (t1, t2, t3, t4)
|
29
|
+
|
30
|
+
|
31
|
+
class ZipperTest(unittest.TestCase):
|
32
|
+
def test_data_is_retained(self):
|
33
|
+
t1, _, _, _ = create_trees()
|
34
|
+
zipper = Zipper.from_tree(t1)
|
35
|
+
tree = zipper.to_tree()
|
36
|
+
self.assertEqual(tree, t1)
|
37
|
+
|
38
|
+
def test_left_and_right_value(self):
|
39
|
+
t1, _, _, _ = create_trees()
|
40
|
+
zipper = Zipper.from_tree(t1)
|
41
|
+
self.assertEqual(zipper.left().right().value(), 3)
|
42
|
+
|
43
|
+
def test_dead_end(self):
|
44
|
+
t1, _, _, _ = create_trees()
|
45
|
+
zipper = Zipper.from_tree(t1)
|
46
|
+
self.assertIsNone(zipper.left().left())
|
47
|
+
|
48
|
+
def test_tree_from_deep_focus(self):
|
49
|
+
t1, _, _, _ = create_trees()
|
50
|
+
zipper = Zipper.from_tree(t1)
|
51
|
+
self.assertEqual(zipper.left().right().to_tree(), t1)
|
52
|
+
|
53
|
+
def test_set_value(self):
|
54
|
+
t1, t2, _, _ = create_trees()
|
55
|
+
zipper = Zipper.from_tree(t1)
|
56
|
+
updatedZipper = zipper.left().set_value(5)
|
57
|
+
tree = updatedZipper.to_tree()
|
58
|
+
self.assertEqual(tree, t2)
|
59
|
+
|
60
|
+
def test_set_left_with_value(self):
|
61
|
+
t1, _, t3, _ = create_trees()
|
62
|
+
zipper = Zipper.from_tree(t1)
|
63
|
+
updatedZipper = zipper.left().set_left(leaf(5))
|
64
|
+
tree = updatedZipper.to_tree()
|
65
|
+
self.assertEqual(tree, t3)
|
66
|
+
|
67
|
+
def test_set_right_to_none(self):
|
68
|
+
t1, _, _, t4 = create_trees()
|
69
|
+
zipper = Zipper.from_tree(t1)
|
70
|
+
updatedZipper = zipper.left().set_right(None)
|
71
|
+
tree = updatedZipper.to_tree()
|
72
|
+
self.assertEqual(tree, t4)
|
73
|
+
|
74
|
+
def test_different_paths_to_same_zipper(self):
|
75
|
+
t1, _, _, _ = create_trees()
|
76
|
+
zipper = Zipper.from_tree(t1)
|
77
|
+
self.assertEqual(zipper.left().up().right().to_tree(),
|
78
|
+
zipper.right().to_tree())
|
79
|
+
|
80
|
+
|
81
|
+
if __name__ == '__main__':
|
82
|
+
unittest.main()
|
data/tracks/racket/.travis.yml
CHANGED
data/tracks/racket/config.json
CHANGED
@@ -113,6 +113,20 @@
|
|
113
113
|
|
114
114
|
]
|
115
115
|
},
|
116
|
+
{
|
117
|
+
"uuid": "d330a93f-063f-0d80-f35b-02cc2f9da754e0be296",
|
118
|
+
"slug": "meetup",
|
119
|
+
"core": false,
|
120
|
+
"unlocked_by": null,
|
121
|
+
"difficulty": 1,
|
122
|
+
"topics": [
|
123
|
+
"strings",
|
124
|
+
"conditionals",
|
125
|
+
"dates",
|
126
|
+
"parsing",
|
127
|
+
"pattern_recognition"
|
128
|
+
]
|
129
|
+
},
|
116
130
|
{
|
117
131
|
"uuid": "67b41645-7a02-4c45-af55-86401db69eee",
|
118
132
|
"slug": "anagram",
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Meetup
|
2
|
+
|
3
|
+
Calculate the date of meetups.
|
4
|
+
|
5
|
+
Typically meetups happen on the same day of the week. In this exercise, you will take
|
6
|
+
a description of a meetup date, and return the actual meetup date.
|
7
|
+
|
8
|
+
Examples of general descriptions are:
|
9
|
+
|
10
|
+
- the first Monday of January 2017
|
11
|
+
- the third Tuesday of January 2017
|
12
|
+
- the Wednesteenth of January 2017
|
13
|
+
- the last Thursday of January 2017
|
14
|
+
|
15
|
+
Note that "Monteenth", "Tuesteenth", etc are all made up words. There
|
16
|
+
was a meetup whose members realized that there are exactly 7 numbered days in a month that
|
17
|
+
end in '-teenth'. Therefore, one is guaranteed that each day of the week
|
18
|
+
(Monday, Tuesday, ...) will have exactly one date that is named with '-teenth'
|
19
|
+
in every month.
|
20
|
+
|
21
|
+
Given examples of a meetup dates, each containing a month, day, year, and descriptor
|
22
|
+
(first, second, teenth, etc), calculate the date of the actual meetup.
|
23
|
+
For example, if given "First Monday of January 2017", the correct meetup date is 2017/1/2
|
24
|
+
|
25
|
+
* * * *
|
26
|
+
|
27
|
+
For installation and learning resources, refer to the
|
28
|
+
[exercism Racket page](http://exercism.io/languages/racket).
|
29
|
+
|
30
|
+
You can run the provided tests through DrRacket, or via the command line.
|
31
|
+
|
32
|
+
To run the test through DrRacket, simply open the test file and click the 'Run' button in the upper right.
|
33
|
+
|
34
|
+
To run the test from the command line, simply run the test from the exercise directory. For example, if the test suite is called `hello-world-test.rkt`, you can run the following command:
|
35
|
+
|
36
|
+
```
|
37
|
+
raco test hello-world-test.rkt
|
38
|
+
```
|
39
|
+
|
40
|
+
which will display the following:
|
41
|
+
|
42
|
+
```
|
43
|
+
raco test: (submod "hello-world-test.rkt" test)
|
44
|
+
2 success(es) 0 failure(s) 0 error(s) 2 test(s) run
|
45
|
+
0
|
46
|
+
2 tests passed
|
47
|
+
```
|
48
|
+
|
49
|
+
## Source
|
50
|
+
|
51
|
+
Jeremy Hinegardner mentioned a Boulder meetup that happens on the Wednesteenth of every month [https://twitter.com/copiousfreetime](https://twitter.com/copiousfreetime)
|
52
|
+
|
53
|
+
## Submitting Incomplete Solutions
|
54
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#lang racket
|
2
|
+
|
3
|
+
(require racket/date)
|
4
|
+
|
5
|
+
(define (leap-year? year)
|
6
|
+
(or (and (zero? (modulo year 4))
|
7
|
+
(not (zero? (modulo year 100))))
|
8
|
+
(zero? (modulo year 400))))
|
9
|
+
|
10
|
+
(define (days-in-month year month)
|
11
|
+
(case month
|
12
|
+
[(1 3 5 7 8 10 12) 31]
|
13
|
+
[(4 6 9 11) 30]
|
14
|
+
[(2) (if (leap-year? year) 29 28)]))
|
15
|
+
|
16
|
+
(define (make-date year month day)
|
17
|
+
(seconds->date (find-seconds 0 0 0 day month year #f) #f))
|
18
|
+
|
19
|
+
(define (meetup-day year month weekday week)
|
20
|
+
(let ([first-of-week
|
21
|
+
(case week
|
22
|
+
[(first) 1]
|
23
|
+
[(second) 8]
|
24
|
+
[(teenth) 13]
|
25
|
+
[(third) 15]
|
26
|
+
[(fourth) 22]
|
27
|
+
[(last) (- (days-in-month year month) 6)]
|
28
|
+
[else (raise-argument-error 'meetup-day "week" 3 year month weekday week)])]
|
29
|
+
[weekday
|
30
|
+
(case weekday
|
31
|
+
[(Sunday) 0]
|
32
|
+
[(Monday) 1]
|
33
|
+
[(Tuesday) 2]
|
34
|
+
[(Wednesday) 3]
|
35
|
+
[(Thursday) 4]
|
36
|
+
[(Friday) 5]
|
37
|
+
[(Saturday) 6]
|
38
|
+
[else (raise-argument-error 'meetup-day "weekday" 3 year month weekday week)])])
|
39
|
+
(make-date year month
|
40
|
+
(+ first-of-week
|
41
|
+
(modulo
|
42
|
+
(- weekday
|
43
|
+
(date-week-day (make-date year month first-of-week))) 7)))))
|
44
|
+
|
45
|
+
(provide meetup-day)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#lang racket
|
2
|
+
|
3
|
+
(module+ test
|
4
|
+
(require rackunit rackunit/text-ui)
|
5
|
+
(require racket/date)
|
6
|
+
(require "meetup.rkt")
|
7
|
+
|
8
|
+
(define (make-date year month day)
|
9
|
+
(seconds->date (find-seconds 0 0 0 day month year #f) #f))
|
10
|
+
|
11
|
+
(define suite
|
12
|
+
(test-suite
|
13
|
+
"Tests for the meetup exercise"
|
14
|
+
|
15
|
+
(check-equal? (meetup-day 2013 5 'Monday 'teenth)
|
16
|
+
(make-date 2013 5 13))
|
17
|
+
|
18
|
+
(check-equal? (meetup-day 2013 2 'Saturday 'teenth)
|
19
|
+
(make-date 2013 2 16))
|
20
|
+
|
21
|
+
(check-equal? (meetup-day 2013 5 'Tuesday 'first)
|
22
|
+
(make-date 2013 5 7))
|
23
|
+
|
24
|
+
(check-equal? (meetup-day 2013 4 'Monday 'second)
|
25
|
+
(make-date 2013 4 8))
|
26
|
+
|
27
|
+
(check-equal? (meetup-day 2013 9 'Thursday 'third)
|
28
|
+
(make-date 2013 9 19))
|
29
|
+
|
30
|
+
(check-equal? (meetup-day 2013 3 'Sunday 'fourth)
|
31
|
+
(make-date 2013 3 24))
|
32
|
+
|
33
|
+
(check-equal? (meetup-day 2013 10 'Thursday 'last)
|
34
|
+
(make-date 2013 10 31))
|
35
|
+
|
36
|
+
(check-equal? (meetup-day 2012 2 'Wednesday 'last)
|
37
|
+
(make-date 2012 2 29))))
|
38
|
+
|
39
|
+
(run-tests suite))
|