trackler 2.2.1.67 → 2.2.1.68
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/README.md +6 -6
- data/tracks/csharp/exercises/all-your-base/AllYourBaseTest.cs +9 -5
- data/tracks/csharp/exercises/all-your-base/Example.cs +7 -3
- data/tracks/csharp/exercises/nth-prime/NthPrimeTest.cs +1 -1
- data/tracks/csharp/generators/Exercises/AllYourBase.cs +2 -1
- data/tracks/csharp/generators/Exercises/NthPrime.cs +2 -1
- data/tracks/fsharp/config.json +11 -0
- data/tracks/fsharp/exercises/Exercises.sln +6 -0
- data/tracks/fsharp/exercises/isbn-verifier/Example.fs +19 -0
- data/tracks/fsharp/exercises/isbn-verifier/IsbnVerifier.fs +3 -0
- data/tracks/fsharp/exercises/isbn-verifier/IsbnVerifier.fsproj +23 -0
- data/tracks/fsharp/exercises/isbn-verifier/IsbnVerifierTest.fs +61 -0
- data/tracks/fsharp/exercises/isbn-verifier/Program.fs +1 -0
- data/tracks/fsharp/exercises/isbn-verifier/README.md +32 -0
- data/tracks/fsharp/generators/Generators.fs +3 -0
- data/tracks/go/exercises/sieve/.meta/gen.go +46 -0
- data/tracks/go/exercises/sieve/cases_test.go +37 -0
- data/tracks/go/exercises/sieve/example.go +5 -5
- data/tracks/go/exercises/sieve/sieve_test.go +12 -21
- data/tracks/java/exercises/anagram/src/test/java/AnagramTest.java +7 -6
- data/tracks/objective-c/config.json +13 -0
- data/tracks/objective-c/exercises/say/SayExample.h +7 -0
- data/tracks/objective-c/exercises/say/SayExample.m +55 -0
- data/tracks/objective-c/exercises/say/SayTest.m +75 -0
- data/tracks/objective-c/xcodeProject/ObjectiveC.xcodeproj/project.pbxproj +18 -0
- data/tracks/ocaml/exercises/grade-school/README.md +1 -14
- data/tracks/ocaml/exercises/grade-school/example.ml +1 -1
- data/tracks/ocaml/exercises/grade-school/grade_school.mli +1 -2
- data/tracks/ocaml/exercises/grade-school/test.ml +15 -25
- data/tracks/swift/config.json +13 -0
- data/tracks/swift/exercises/say/Package.swift +5 -0
- data/tracks/swift/exercises/say/README.md +77 -0
- data/tracks/swift/exercises/say/Sources/Say.swift +1 -0
- data/tracks/swift/exercises/say/Sources/SayExample.swift +48 -0
- data/tracks/swift/exercises/say/Tests/LinuxMain.swift +6 -0
- data/tracks/swift/exercises/say/Tests/SayTests/SayTests.swift +85 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 93727b2027f0b9bb82b47a47508ca7ffcc6ff35d
|
4
|
+
data.tar.gz: 5b5ad9daef87088409e3e8b2c22ad16803cddd8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76aff154bb6cfb996c616f4f77cfd2de03d6029fbf1cab3255bb162310a6b41767576a818b001abeec9f3e875b27bc9118833ba83ae8e65a5ed35df9427be62e
|
7
|
+
data.tar.gz: 361c13c1a88ce84f99c1bfea50d5af3590fc9ee21a85a22e10c3333089f29cba08211a6e703c6eb1d23c5185636170fd7c93603f4ef6b889e28261121e249f6c
|
data/lib/trackler/version.rb
CHANGED
@@ -30,13 +30,13 @@ There are three metadata files:
|
|
30
30
|
|
31
31
|
* `description.md` - the basic problem description
|
32
32
|
* `metadata.yml` - additional information about the problem, such as where it came from
|
33
|
-
* `canonical-data.json`
|
33
|
+
* `canonical-data.json` - standardized test inputs and outputs that can be used to implement the problem
|
34
34
|
|
35
35
|
## Test Data Format (canonical-data.json)
|
36
36
|
|
37
37
|
This data can be incorporated into test programs manually or extracted by a
|
38
38
|
program. The file format is described in `canonical-schema.json`, but it
|
39
|
-
is easier to understand with
|
39
|
+
is easier to understand with an example:
|
40
40
|
|
41
41
|
```json
|
42
42
|
{ "exercise": "foobar"
|
@@ -103,11 +103,11 @@ Keep in mind that the description should not simply explain **what** each case
|
|
103
103
|
is (that is redundant information) but also **why** each case is there. For
|
104
104
|
example, what kinds of implementation mistakes might this case help us find?
|
105
105
|
|
106
|
-
There are also some
|
106
|
+
There are also some conventions that must be followed:
|
107
107
|
|
108
108
|
- All keys should follow the [lowerCamelCase](http://wiki.c2.com/?LowerCamelCase) convention.
|
109
|
-
-
|
110
|
-
-
|
109
|
+
- If the input is valid but there is no result for the input, the value at `"expected"` should be `null`.
|
110
|
+
- If an error is expected (because the input is invalid, or any other reason), the value at `"expected"` should be an object containing exactly one property, `"error"`, whose value is a string.
|
111
111
|
- The string should explain why the error would occur.
|
112
112
|
- A particular track's implementation of the exercise **need not** necessarily check that the error includes that exact string as the cause, depending on what is idiomatic in the language (it may not be idiomatic to check strings for error messages).
|
113
113
|
|
@@ -165,7 +165,7 @@ PATCH changes would never break well-designed test generators, because the test
|
|
165
165
|
|
166
166
|
## Automated Tests
|
167
167
|
|
168
|
-
`canonical-data.json` for each exercise is checked for
|
168
|
+
`canonical-data.json` for each exercise is checked for compliance against the [canonical-schema.json](canonical-schema.json).
|
169
169
|
In order to run these tests, you will need to have `node` and `npm` installed on your system.
|
170
170
|
Install them from [here](https://nodejs.org/en/). (`npm` comes bundled with most installations of `node`).
|
171
171
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
// This file was auto-generated based on version
|
1
|
+
// This file was auto-generated based on version 2.0.0 of the canonical data.
|
2
2
|
|
3
3
|
using Xunit;
|
4
4
|
using System;
|
@@ -91,7 +91,8 @@ public class AllYourBaseTest
|
|
91
91
|
var inputBase = 2;
|
92
92
|
var inputDigits = new int[0];
|
93
93
|
var outputBase = 10;
|
94
|
-
|
94
|
+
var expected = new[] { 0 };
|
95
|
+
Assert.Equal(expected, AllYourBase.Rebase(inputBase, inputDigits, outputBase));
|
95
96
|
}
|
96
97
|
|
97
98
|
[Fact(Skip = "Remove to run test")]
|
@@ -100,7 +101,8 @@ public class AllYourBaseTest
|
|
100
101
|
var inputBase = 10;
|
101
102
|
var inputDigits = new[] { 0 };
|
102
103
|
var outputBase = 2;
|
103
|
-
|
104
|
+
var expected = new[] { 0 };
|
105
|
+
Assert.Equal(expected, AllYourBase.Rebase(inputBase, inputDigits, outputBase));
|
104
106
|
}
|
105
107
|
|
106
108
|
[Fact(Skip = "Remove to run test")]
|
@@ -109,7 +111,8 @@ public class AllYourBaseTest
|
|
109
111
|
var inputBase = 10;
|
110
112
|
var inputDigits = new[] { 0, 0, 0 };
|
111
113
|
var outputBase = 2;
|
112
|
-
|
114
|
+
var expected = new[] { 0 };
|
115
|
+
Assert.Equal(expected, AllYourBase.Rebase(inputBase, inputDigits, outputBase));
|
113
116
|
}
|
114
117
|
|
115
118
|
[Fact(Skip = "Remove to run test")]
|
@@ -118,7 +121,8 @@ public class AllYourBaseTest
|
|
118
121
|
var inputBase = 7;
|
119
122
|
var inputDigits = new[] { 0, 6, 0 };
|
120
123
|
var outputBase = 10;
|
121
|
-
|
124
|
+
var expected = new[] { 4, 2 };
|
125
|
+
Assert.Equal(expected, AllYourBase.Rebase(inputBase, inputDigits, outputBase));
|
122
126
|
}
|
123
127
|
|
124
128
|
[Fact(Skip = "Remove to run test")]
|
@@ -8,16 +8,20 @@ public static class AllYourBase
|
|
8
8
|
{
|
9
9
|
if (inputBase < 2) throw new ArgumentException("Invalid input base.");
|
10
10
|
if (outputBase < 2) throw new ArgumentException("Invalid output base.");
|
11
|
-
if (inputDigits.Length == 0) throw new ArgumentException("Empty input digits.");
|
12
11
|
|
13
|
-
|
12
|
+
var inputDigitsWithoutLeadingZeros = inputDigits.SkipWhile(digit => digit == 0).ToArray();
|
13
|
+
|
14
|
+
if (inputDigitsWithoutLeadingZeros.Length == 0)
|
15
|
+
return new[] { 0 };
|
16
|
+
|
17
|
+
return ToDigits(outputBase, FromDigits(inputBase, inputDigitsWithoutLeadingZeros));
|
14
18
|
}
|
15
19
|
|
16
20
|
private static int FromDigits(int fromBase, int[] fromDigits)
|
17
21
|
{
|
18
22
|
return fromDigits.Aggregate(0, (acc, x) =>
|
19
23
|
{
|
20
|
-
if (x < 0 || x >= fromBase
|
24
|
+
if (x < 0 || x >= fromBase) throw new ArgumentException("Invalid input digit");
|
21
25
|
|
22
26
|
return acc*fromBase + x;
|
23
27
|
});
|
@@ -1,4 +1,5 @@
|
|
1
1
|
using System;
|
2
|
+
using System.Collections.Generic;
|
2
3
|
using Generators.Input;
|
3
4
|
|
4
5
|
namespace Generators.Exercises
|
@@ -9,7 +10,7 @@ namespace Generators.Exercises
|
|
9
10
|
{
|
10
11
|
foreach (var canonicalDataCase in canonicalData.Cases)
|
11
12
|
{
|
12
|
-
canonicalDataCase.ExceptionThrown = canonicalDataCase.Expected is
|
13
|
+
canonicalDataCase.ExceptionThrown = canonicalDataCase.Expected is Dictionary<string, object> ? typeof(ArgumentException) : null;
|
13
14
|
canonicalDataCase.UseVariablesForInput = true;
|
14
15
|
canonicalDataCase.UseVariableForExpected = true;
|
15
16
|
}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
using System;
|
2
|
+
using System.Collections.Generic;
|
2
3
|
using Generators.Input;
|
3
4
|
|
4
5
|
namespace Generators.Exercises
|
@@ -8,7 +9,7 @@ namespace Generators.Exercises
|
|
8
9
|
protected override void UpdateCanonicalData(CanonicalData canonicalData)
|
9
10
|
{
|
10
11
|
foreach (var canonicalDataCase in canonicalData.Cases)
|
11
|
-
canonicalDataCase.ExceptionThrown = canonicalDataCase.Expected is
|
12
|
+
canonicalDataCase.ExceptionThrown = canonicalDataCase.Expected is Dictionary<string, object> ? typeof(ArgumentOutOfRangeException) : null;
|
12
13
|
}
|
13
14
|
}
|
14
15
|
}
|
data/tracks/fsharp/config.json
CHANGED
@@ -642,6 +642,17 @@
|
|
642
642
|
"unlocked_by": "robot-simulator",
|
643
643
|
"uuid": "18652e46-6dd2-4030-84af-be0965c92991"
|
644
644
|
},
|
645
|
+
{
|
646
|
+
"core": false,
|
647
|
+
"difficulty": 4,
|
648
|
+
"slug": "isbn-verifier",
|
649
|
+
"topics": [
|
650
|
+
"loops",
|
651
|
+
"strings"
|
652
|
+
],
|
653
|
+
"unlocked_by": "bob",
|
654
|
+
"uuid": "c339c32c-3310-4b8c-b4e6-0f9f651064b7"
|
655
|
+
},
|
645
656
|
{
|
646
657
|
"core": false,
|
647
658
|
"difficulty": 5,
|
@@ -218,6 +218,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ReverseString", "reverse-st
|
|
218
218
|
EndProject
|
219
219
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "RotationalCipher", "rotational-cipher\RotationalCipher.fsproj", "{91D0A5E0-E39C-472B-87FB-6DD17336AA22}"
|
220
220
|
EndProject
|
221
|
+
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "IsbnVerifier", "isbn-verifier\IsbnVerifier.fsproj", "{531D1AB8-1297-4DE2-9B9B-3742A648EDB7}"
|
222
|
+
EndProject
|
221
223
|
Global
|
222
224
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
223
225
|
Debug|Any CPU = Debug|Any CPU
|
@@ -656,6 +658,10 @@ Global
|
|
656
658
|
{91D0A5E0-E39C-472B-87FB-6DD17336AA22}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
657
659
|
{91D0A5E0-E39C-472B-87FB-6DD17336AA22}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
658
660
|
{91D0A5E0-E39C-472B-87FB-6DD17336AA22}.Release|Any CPU.Build.0 = Release|Any CPU
|
661
|
+
{531D1AB8-1297-4DE2-9B9B-3742A648EDB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
662
|
+
{531D1AB8-1297-4DE2-9B9B-3742A648EDB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
663
|
+
{531D1AB8-1297-4DE2-9B9B-3742A648EDB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
664
|
+
{531D1AB8-1297-4DE2-9B9B-3742A648EDB7}.Release|Any CPU.Build.0 = Release|Any CPU
|
659
665
|
EndGlobalSection
|
660
666
|
GlobalSection(SolutionProperties) = preSolution
|
661
667
|
HideSolutionNode = FALSE
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module IsbnVerifier
|
2
|
+
|
3
|
+
open System.Text.RegularExpressions
|
4
|
+
|
5
|
+
let private digitToInt digit = if digit = 'X' then 10 else int digit - int '0'
|
6
|
+
|
7
|
+
let private checkSum isbn =
|
8
|
+
isbn
|
9
|
+
|> Seq.mapi (fun i digit -> (10 - i) * digitToInt digit)
|
10
|
+
|> Seq.sum
|
11
|
+
|
12
|
+
let private cleanup (isbn: string) = isbn.Replace("-", "")
|
13
|
+
|
14
|
+
let isValid (isbn: string) =
|
15
|
+
let cleanedUpIsbn = cleanup isbn
|
16
|
+
|
17
|
+
match Regex.IsMatch(cleanedUpIsbn, "^[0-9]{9}[0-9X]$") with
|
18
|
+
| false -> false
|
19
|
+
| true -> checkSum cleanedUpIsbn % 11 = 0
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
2
|
+
|
3
|
+
<PropertyGroup>
|
4
|
+
<TargetFramework>netcoreapp2.0</TargetFramework>
|
5
|
+
|
6
|
+
<IsPackable>false</IsPackable>
|
7
|
+
</PropertyGroup>
|
8
|
+
|
9
|
+
<ItemGroup>
|
10
|
+
<Compile Include="IsbnVerifier.fs" />
|
11
|
+
<Compile Include="IsbnVerifierTest.fs" />
|
12
|
+
<Compile Include="Program.fs" />
|
13
|
+
</ItemGroup>
|
14
|
+
|
15
|
+
<ItemGroup>
|
16
|
+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
|
17
|
+
<PackageReference Include="xunit" Version="2.3.1" />
|
18
|
+
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
19
|
+
<PackageReference Include="FsUnit.xUnit" Version="3.0.0" />
|
20
|
+
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
|
21
|
+
</ItemGroup>
|
22
|
+
|
23
|
+
</Project>
|
@@ -0,0 +1,61 @@
|
|
1
|
+
// This file was auto-generated based on version 2.0.0 of the canonical data.
|
2
|
+
|
3
|
+
module IsbnVerifierTest
|
4
|
+
|
5
|
+
open FsUnit.Xunit
|
6
|
+
open Xunit
|
7
|
+
|
8
|
+
open IsbnVerifier
|
9
|
+
|
10
|
+
[<Fact>]
|
11
|
+
let ``Valid isbn number`` () =
|
12
|
+
isValid "3-598-21508-8" |> should equal true
|
13
|
+
|
14
|
+
[<Fact(Skip = "Remove to run test")>]
|
15
|
+
let ``Invalid isbn check digit`` () =
|
16
|
+
isValid "3-598-21508-9" |> should equal false
|
17
|
+
|
18
|
+
[<Fact(Skip = "Remove to run test")>]
|
19
|
+
let ``Valid isbn number with a check digit of 10`` () =
|
20
|
+
isValid "3-598-21507-X" |> should equal true
|
21
|
+
|
22
|
+
[<Fact(Skip = "Remove to run test")>]
|
23
|
+
let ``Check digit is a character other than X`` () =
|
24
|
+
isValid "3-598-21507-A" |> should equal false
|
25
|
+
|
26
|
+
[<Fact(Skip = "Remove to run test")>]
|
27
|
+
let ``Invalid character in isbn`` () =
|
28
|
+
isValid "3-598-2K507-0" |> should equal false
|
29
|
+
|
30
|
+
[<Fact(Skip = "Remove to run test")>]
|
31
|
+
let ``X is only valid as a check digit`` () =
|
32
|
+
isValid "3-598-2X507-9" |> should equal false
|
33
|
+
|
34
|
+
[<Fact(Skip = "Remove to run test")>]
|
35
|
+
let ``Valid isbn without separating dashes`` () =
|
36
|
+
isValid "3598215088" |> should equal true
|
37
|
+
|
38
|
+
[<Fact(Skip = "Remove to run test")>]
|
39
|
+
let ``Isbn without separating dashes and X as check digit`` () =
|
40
|
+
isValid "359821507X" |> should equal true
|
41
|
+
|
42
|
+
[<Fact(Skip = "Remove to run test")>]
|
43
|
+
let ``Isbn without check digit and dashes`` () =
|
44
|
+
isValid "359821507" |> should equal false
|
45
|
+
|
46
|
+
[<Fact(Skip = "Remove to run test")>]
|
47
|
+
let ``Too long isbn and no dashes`` () =
|
48
|
+
isValid "3598215078X" |> should equal false
|
49
|
+
|
50
|
+
[<Fact(Skip = "Remove to run test")>]
|
51
|
+
let ``Isbn without check digit`` () =
|
52
|
+
isValid "3-598-21507" |> should equal false
|
53
|
+
|
54
|
+
[<Fact(Skip = "Remove to run test")>]
|
55
|
+
let ``Too long isbn`` () =
|
56
|
+
isValid "3-598-21507-XX" |> should equal false
|
57
|
+
|
58
|
+
[<Fact(Skip = "Remove to run test")>]
|
59
|
+
let ``Check digit of X should not be used for 0`` () =
|
60
|
+
isValid "3-598-21515-X" |> should equal false
|
61
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
module Program = let [<EntryPoint>] main _ = 0
|
@@ -0,0 +1,32 @@
|
|
1
|
+
Check if a given ISBN-10 is valid.
|
2
|
+
|
3
|
+
## Functionality
|
4
|
+
|
5
|
+
Given an unknown string the program should check if the provided string is a valid ISBN-10.
|
6
|
+
Putting this into place requires some thinking about preprocessing/parsing of the string prior to calculating the check digit for the ISBN.
|
7
|
+
|
8
|
+
The program should allow for ISBN-10 without the separating dashes to be verified as well.
|
9
|
+
|
10
|
+
## ISBN
|
11
|
+
|
12
|
+
Let's take a random ISBN-10 number, say `3-598-21508-8` for this.
|
13
|
+
The first digit block indicates the group where the ISBN belongs. Groups can consist of shared languages, geographic regions or countries. The leading '3' signals this ISBN is from a german speaking country.
|
14
|
+
The following number block is to identify the publisher. Since this is a three digit publisher number there is a 5 digit title number for this book.
|
15
|
+
The last digit in the ISBN is the check digit which is used to detect read errors.
|
16
|
+
|
17
|
+
The first 9 digits in the ISBN have to be between 0 and 9.
|
18
|
+
The check digit can additionally be an 'X' to allow 10 to be a valid check digit as well.
|
19
|
+
|
20
|
+
A valid ISBN-10 is calculated with this formula `(x1 * 10 + x2 * 9 + x3 * 8 + x4 * 7 + x5 * 6 + x6 * 5 + x7 * 4 + x8 * 3 + x9 * 2 + x10 * 1) mod 11 == 0`
|
21
|
+
So for our example ISBN this means:
|
22
|
+
(3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 = 0
|
23
|
+
|
24
|
+
Which proves that the ISBN is valid.
|
25
|
+
|
26
|
+
## Caveats
|
27
|
+
|
28
|
+
Converting from string to number can be tricky in certain languages.
|
29
|
+
It's getting even trickier since the check-digit of an ISBN-10 can be 'X'.
|
30
|
+
|
31
|
+
## Submitting Incomplete Solutions
|
32
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
@@ -0,0 +1,46 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
import (
|
4
|
+
"log"
|
5
|
+
"text/template"
|
6
|
+
|
7
|
+
"../../../gen"
|
8
|
+
)
|
9
|
+
|
10
|
+
func main() {
|
11
|
+
t, err := template.New("").Parse(tmpl)
|
12
|
+
if err != nil {
|
13
|
+
log.Fatal(err)
|
14
|
+
}
|
15
|
+
var j js
|
16
|
+
if err := gen.Gen("sieve", &j, t); err != nil {
|
17
|
+
log.Fatal(err)
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
// The JSON structure we expect to be able to unmarshal into
|
22
|
+
type js struct {
|
23
|
+
Cases []struct {
|
24
|
+
Description string
|
25
|
+
Limit int
|
26
|
+
Expected []int
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
// template applied to above data structure generates the Go test cases
|
31
|
+
var tmpl = `package sieve
|
32
|
+
|
33
|
+
{{.Header}}
|
34
|
+
|
35
|
+
var testCases = []struct {
|
36
|
+
description string
|
37
|
+
limit int
|
38
|
+
expected []int
|
39
|
+
}{
|
40
|
+
{{range .J.Cases}}{
|
41
|
+
"{{.Description}}",
|
42
|
+
{{.Limit}},
|
43
|
+
{{printf "%#v" .Expected}},
|
44
|
+
},
|
45
|
+
{{end}}}
|
46
|
+
`
|
@@ -0,0 +1,37 @@
|
|
1
|
+
package sieve
|
2
|
+
|
3
|
+
// Source: exercism/problem-specifications
|
4
|
+
// Commit: f2b2693 sieve: Fix canonical-data.json formatting
|
5
|
+
// Problem Specifications Version: 1.0.0
|
6
|
+
|
7
|
+
var testCases = []struct {
|
8
|
+
description string
|
9
|
+
limit int
|
10
|
+
expected []int
|
11
|
+
}{
|
12
|
+
{
|
13
|
+
"no primes under two",
|
14
|
+
1,
|
15
|
+
[]int{},
|
16
|
+
},
|
17
|
+
{
|
18
|
+
"find first prime",
|
19
|
+
2,
|
20
|
+
[]int{2},
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"find primes up to 10",
|
24
|
+
10,
|
25
|
+
[]int{2, 3, 5, 7},
|
26
|
+
},
|
27
|
+
{
|
28
|
+
"limit is prime",
|
29
|
+
13,
|
30
|
+
[]int{2, 3, 5, 7, 11, 13},
|
31
|
+
},
|
32
|
+
{
|
33
|
+
"find primes up to 1000",
|
34
|
+
1000,
|
35
|
+
[]int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997},
|
36
|
+
},
|
37
|
+
}
|
@@ -1,15 +1,15 @@
|
|
1
1
|
package sieve
|
2
2
|
|
3
3
|
func Sieve(limit int) (primes []int) {
|
4
|
-
c := make([]bool, limit)
|
5
|
-
for p := 2; p
|
6
|
-
for i := p + p; i
|
4
|
+
c := make([]bool, limit+1)
|
5
|
+
for p := 2; p <= limit; {
|
6
|
+
for i := p + p; i <= limit; i += p {
|
7
7
|
c[i] = true
|
8
8
|
}
|
9
|
-
for p++; p
|
9
|
+
for p++; p <= limit && c[p]; p++ {
|
10
10
|
}
|
11
11
|
}
|
12
|
-
for i := 2; i
|
12
|
+
for i := 2; i <= limit; i++ {
|
13
13
|
if !c[i] {
|
14
14
|
primes = append(primes, i)
|
15
15
|
}
|
@@ -5,32 +5,23 @@ import (
|
|
5
5
|
"testing"
|
6
6
|
)
|
7
7
|
|
8
|
-
var p10 = []int{2, 3, 5, 7}
|
9
|
-
var p1000 = []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
|
10
|
-
59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
|
11
|
-
139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223,
|
12
|
-
227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307,
|
13
|
-
311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397,
|
14
|
-
401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487,
|
15
|
-
491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593,
|
16
|
-
599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677,
|
17
|
-
683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787,
|
18
|
-
797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883,
|
19
|
-
887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997}
|
20
|
-
|
21
8
|
func TestSieve(t *testing.T) {
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
9
|
+
for _, tc := range testCases {
|
10
|
+
p := Sieve(tc.limit)
|
11
|
+
if len(p) != 0 || len(tc.expected) != 0 {
|
12
|
+
if !reflect.DeepEqual(p, tc.expected) {
|
13
|
+
t.Fatalf("FAIL: %s\nSieve(%d)\nExpected %v\nActual %v",
|
14
|
+
tc.description, tc.limit, tc.expected, p)
|
15
|
+
}
|
16
|
+
}
|
17
|
+
t.Logf("PASS: %s", tc.description)
|
29
18
|
}
|
30
19
|
}
|
31
20
|
|
32
21
|
func BenchmarkSieve(b *testing.B) {
|
33
22
|
for i := 0; i < b.N; i++ {
|
34
|
-
|
23
|
+
for _, tc := range testCases {
|
24
|
+
Sieve(tc.limit)
|
25
|
+
}
|
35
26
|
}
|
36
27
|
}
|
@@ -2,6 +2,7 @@ import org.junit.Ignore;
|
|
2
2
|
import org.junit.Test;
|
3
3
|
|
4
4
|
import java.util.Arrays;
|
5
|
+
import java.util.Collections;
|
5
6
|
import java.util.List;
|
6
7
|
|
7
8
|
import static org.hamcrest.CoreMatchers.*;
|
@@ -53,7 +54,7 @@ public class AnagramTest {
|
|
53
54
|
@Test
|
54
55
|
public void testDoesNotConfuseDifferentDuplicates() {
|
55
56
|
Anagram detector = new Anagram("galea");
|
56
|
-
assertTrue(detector.match(
|
57
|
+
assertTrue(detector.match(Collections.singletonList("eagle")).isEmpty());
|
57
58
|
}
|
58
59
|
|
59
60
|
@Ignore("Remove to run test")
|
@@ -69,21 +70,21 @@ public class AnagramTest {
|
|
69
70
|
@Test
|
70
71
|
public void testIdenticalWordRepeatedIsNotAnagram() {
|
71
72
|
Anagram detector = new Anagram("go");
|
72
|
-
assertTrue(detector.match(
|
73
|
+
assertTrue(detector.match(Collections.singletonList("go Go GO")).isEmpty());
|
73
74
|
}
|
74
75
|
|
75
76
|
@Ignore("Remove to run test")
|
76
77
|
@Test
|
77
78
|
public void testCapitalWordIsNotOwnAnagram() {
|
78
79
|
Anagram detector = new Anagram("BANANA");
|
79
|
-
assertTrue(detector.match(
|
80
|
+
assertTrue(detector.match(Collections.singletonList("Banana")).isEmpty());
|
80
81
|
}
|
81
82
|
|
82
83
|
@Ignore("Remove to run test")
|
83
84
|
@Test
|
84
85
|
public void testEliminateAnagramsWithSameChecksum() {
|
85
86
|
Anagram detector = new Anagram("mass");
|
86
|
-
assertTrue(detector.match(
|
87
|
+
assertTrue(detector.match(Collections.singletonList("last")).isEmpty());
|
87
88
|
}
|
88
89
|
|
89
90
|
@Ignore("Remove to run test")
|
@@ -121,13 +122,13 @@ public class AnagramTest {
|
|
121
122
|
@Test
|
122
123
|
public void testWordIsNotItsOwnAnagram() {
|
123
124
|
Anagram detector = new Anagram("banana");
|
124
|
-
assertTrue(detector.match(
|
125
|
+
assertTrue(detector.match(Collections.singletonList("Banana")).isEmpty());
|
125
126
|
}
|
126
127
|
|
127
128
|
@Ignore("Remove to run test")
|
128
129
|
@Test
|
129
130
|
public void testAnagramMustUseAllLettersExactlyOnce() {
|
130
131
|
Anagram detector = new Anagram("tapper");
|
131
|
-
assertTrue(detector.match(
|
132
|
+
assertTrue(detector.match(Collections.singletonList("patter")).isEmpty());
|
132
133
|
}
|
133
134
|
}
|
@@ -413,6 +413,19 @@
|
|
413
413
|
"unlocked_by": null,
|
414
414
|
"uuid": "f00fe4b4-7caf-4fe0-b8e6-c1684f71c5f6"
|
415
415
|
},
|
416
|
+
{
|
417
|
+
"core": false,
|
418
|
+
"difficulty": 4,
|
419
|
+
"slug": "say",
|
420
|
+
"topics": [
|
421
|
+
"loops",
|
422
|
+
"parsing",
|
423
|
+
"transforming",
|
424
|
+
"text_formatting"
|
425
|
+
],
|
426
|
+
"unlocked_by": null,
|
427
|
+
"uuid": "9292d37e-2b5f-45a2-b995-ebcce9d90376"
|
428
|
+
},
|
416
429
|
{
|
417
430
|
"core": false,
|
418
431
|
"difficulty": 5,
|
@@ -0,0 +1,55 @@
|
|
1
|
+
#import "SayExample.h"
|
2
|
+
|
3
|
+
@implementation Say
|
4
|
+
|
5
|
+
+ (NSString *)say:(long)number {
|
6
|
+
NSArray<NSString *> *smallNumbers = @[
|
7
|
+
@"zero", @"one", @"two", @"three", @"four", @"five",
|
8
|
+
@"six", @"seven", @"eight", @"nine", @"ten",
|
9
|
+
@"eleven", @"twelve", @"thirteen", @"fourteen", @"fifteen",
|
10
|
+
@"sixteen", @"seventeen", @"eighteen", @"nineteen"
|
11
|
+
];
|
12
|
+
|
13
|
+
NSArray<NSString *> *decades = @[
|
14
|
+
@"twenty", @"thirty", @"forty", @"fifty",
|
15
|
+
@"sixty", @"seventy", @"eighty", @"ninety"
|
16
|
+
];
|
17
|
+
|
18
|
+
NSArray<NSString *> *largeGroupNames = @[@"billion", @"million", @"thousand", @"hundred"];
|
19
|
+
|
20
|
+
NSArray<NSNumber *> *largeGroupAmounts = @[@1000000000, @1000000, @1000, @100];
|
21
|
+
|
22
|
+
if (number < 0 || number >= 1000000000000) {
|
23
|
+
return NULL;
|
24
|
+
}
|
25
|
+
|
26
|
+
if (number < 20) {
|
27
|
+
return smallNumbers[number];
|
28
|
+
}
|
29
|
+
|
30
|
+
for (int i = 0; i < largeGroupAmounts.count; i++) {
|
31
|
+
int amount = largeGroupAmounts[i].intValue;
|
32
|
+
|
33
|
+
if (number >= amount) {
|
34
|
+
NSString *groupName = largeGroupNames[i];
|
35
|
+
NSString *result = [[Say say:(number / amount)] stringByAppendingString:[NSString stringWithFormat:@" %@", groupName]];
|
36
|
+
long remainder = number % amount;
|
37
|
+
|
38
|
+
if (remainder == 0) {
|
39
|
+
return result;
|
40
|
+
}
|
41
|
+
return [result stringByAppendingString:[NSString stringWithFormat:@" %@", [Say say:remainder]]];
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
long decade = number / 10;
|
46
|
+
int remainder = number % 10;
|
47
|
+
NSString *decadeName = decades[decade - 2];
|
48
|
+
|
49
|
+
if (remainder == 0) {
|
50
|
+
return decadeName;
|
51
|
+
}
|
52
|
+
return [decadeName stringByAppendingString:[NSString stringWithFormat:@"-%@", [Say say:remainder]]];
|
53
|
+
}
|
54
|
+
|
55
|
+
@end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
#import <XCTest/XCTest.h>
|
2
|
+
|
3
|
+
#if __has_include("SayExample.h")
|
4
|
+
# import "SayExample.h"
|
5
|
+
#else
|
6
|
+
# import "Say.h"
|
7
|
+
#endif
|
8
|
+
|
9
|
+
@interface SayTest : XCTestCase
|
10
|
+
|
11
|
+
@end
|
12
|
+
|
13
|
+
@implementation SayTest
|
14
|
+
|
15
|
+
- (void)testZero {
|
16
|
+
XCTAssertEqualObjects(@"zero", [Say say:0]);
|
17
|
+
}
|
18
|
+
|
19
|
+
- (void)testOne {
|
20
|
+
XCTAssertEqualObjects(@"one", [Say say:1]);
|
21
|
+
}
|
22
|
+
|
23
|
+
- (void)testFourteen {
|
24
|
+
XCTAssertEqualObjects(@"fourteen", [Say say:14]);
|
25
|
+
}
|
26
|
+
|
27
|
+
- (void)testTwenty {
|
28
|
+
XCTAssertEqualObjects(@"twenty", [Say say:20]);
|
29
|
+
}
|
30
|
+
|
31
|
+
- (void)testTwentyTwo {
|
32
|
+
XCTAssertEqualObjects(@"twenty-two", [Say say:22]);
|
33
|
+
}
|
34
|
+
|
35
|
+
- (void)testOneHundred {
|
36
|
+
XCTAssertEqualObjects(@"one hundred", [Say say:100]);
|
37
|
+
}
|
38
|
+
|
39
|
+
- (void)testOneHundredTwentyThree {
|
40
|
+
XCTAssertEqualObjects(@"one hundred twenty-three", [Say say:123]);
|
41
|
+
}
|
42
|
+
|
43
|
+
- (void)testOneThousand {
|
44
|
+
XCTAssertEqualObjects(@"one thousand", [Say say:1000]);
|
45
|
+
}
|
46
|
+
|
47
|
+
- (void)testOneThousandTwoHundredThirtyFour {
|
48
|
+
XCTAssertEqualObjects(@"one thousand two hundred thirty-four", [Say say:1234]);
|
49
|
+
}
|
50
|
+
|
51
|
+
- (void)testOneMillion {
|
52
|
+
XCTAssertEqualObjects(@"one million", [Say say:1000000]);
|
53
|
+
}
|
54
|
+
|
55
|
+
- (void)testOneMillionTwoThousandThreeHundredFortyFive {
|
56
|
+
XCTAssertEqualObjects(@"one million two thousand three hundred forty-five", [Say say:1002345]);
|
57
|
+
}
|
58
|
+
|
59
|
+
- (void)testOneBillion {
|
60
|
+
XCTAssertEqualObjects(@"one billion", [Say say:1000000000]);
|
61
|
+
}
|
62
|
+
|
63
|
+
- (void)testABigNumber {
|
64
|
+
XCTAssertEqualObjects(@"nine hundred eighty-seven billion six hundred fifty-four million three hundred twenty-one thousand one hundred twenty-three", [Say say:987654321123]);
|
65
|
+
}
|
66
|
+
|
67
|
+
- (void)testNumbersBelowZeroAreOutOfRange {
|
68
|
+
XCTAssertNil([Say say:-1]);
|
69
|
+
}
|
70
|
+
|
71
|
+
- (void)testNumbersAbove999999999999AreOutOfRange {
|
72
|
+
XCTAssertNil([Say say:1000000000000]);
|
73
|
+
}
|
74
|
+
|
75
|
+
@end
|
@@ -79,6 +79,8 @@
|
|
79
79
|
E951B6B91D429550009EB5B6 /* AllergiesTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E951B6B81D429550009EB5B6 /* AllergiesTest.m */; };
|
80
80
|
E95C52551E81C82A0095D321 /* BinarySearchExample.m in Sources */ = {isa = PBXBuildFile; fileRef = E95C52531E81C82A0095D321 /* BinarySearchExample.m */; };
|
81
81
|
E95C52561E81C82A0095D321 /* BinarySearchTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E95C52541E81C82A0095D321 /* BinarySearchTest.m */; };
|
82
|
+
E964F68F1FBF9CA6000114D9 /* SayExample.m in Sources */ = {isa = PBXBuildFile; fileRef = E964F68E1FBF9CA6000114D9 /* SayExample.m */; };
|
83
|
+
E964F6911FBF9CC6000114D9 /* SayTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E964F6901FBF9CC6000114D9 /* SayTest.m */; };
|
82
84
|
E96993981DF60E1E009EA223 /* TransposeExample.m in Sources */ = {isa = PBXBuildFile; fileRef = E96993971DF60E1E009EA223 /* TransposeExample.m */; };
|
83
85
|
E969939A1DF60E5F009EA223 /* TransposeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E96993991DF60E5F009EA223 /* TransposeTest.m */; };
|
84
86
|
E973200C1E9DA0A900ABEE5C /* SieveExample.m in Sources */ = {isa = PBXBuildFile; fileRef = E973200B1E9DA0A900ABEE5C /* SieveExample.m */; };
|
@@ -197,6 +199,9 @@
|
|
197
199
|
E95C52521E81C82A0095D321 /* BinarySearchExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BinarySearchExample.h; path = "../../exercises/binary-search/BinarySearchExample.h"; sourceTree = "<group>"; };
|
198
200
|
E95C52531E81C82A0095D321 /* BinarySearchExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BinarySearchExample.m; path = "../../exercises/binary-search/BinarySearchExample.m"; sourceTree = "<group>"; };
|
199
201
|
E95C52541E81C82A0095D321 /* BinarySearchTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BinarySearchTest.m; path = "../../exercises/binary-search/BinarySearchTest.m"; sourceTree = "<group>"; };
|
202
|
+
E964F68D1FBF9CA6000114D9 /* SayExample.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SayExample.h; path = ../../exercises/say/SayExample.h; sourceTree = "<group>"; };
|
203
|
+
E964F68E1FBF9CA6000114D9 /* SayExample.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SayExample.m; path = ../../exercises/say/SayExample.m; sourceTree = "<group>"; };
|
204
|
+
E964F6901FBF9CC6000114D9 /* SayTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SayTest.m; path = ../../exercises/say/SayTest.m; sourceTree = "<group>"; };
|
200
205
|
E96993961DF60E1E009EA223 /* TransposeExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TransposeExample.h; path = ../../exercises/transpose/TransposeExample.h; sourceTree = "<group>"; };
|
201
206
|
E96993971DF60E1E009EA223 /* TransposeExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TransposeExample.m; path = ../../exercises/transpose/TransposeExample.m; sourceTree = "<group>"; };
|
202
207
|
E96993991DF60E5F009EA223 /* TransposeTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TransposeTest.m; path = ../../exercises/transpose/TransposeTest.m; sourceTree = "<group>"; };
|
@@ -285,6 +290,7 @@
|
|
285
290
|
E9E8B6F51D519E2E0012F12C /* RobotName */,
|
286
291
|
E9FDCA161D540793004EE8DB /* RomanNumerals */,
|
287
292
|
E9C1C02C1D9EC0E50015E86E /* RunLengthEncoding */,
|
293
|
+
E964F68C1FBF9B6B000114D9 /* Say */,
|
288
294
|
E907FE8F1D87545300B93DA9 /* ScrabbleScore */,
|
289
295
|
E9C1C0201D9D98B80015E86E /* SecretHandshake */,
|
290
296
|
E97320091E9DA06500ABEE5C /* Sieve */,
|
@@ -456,6 +462,16 @@
|
|
456
462
|
name = BinarySearch;
|
457
463
|
sourceTree = "<group>";
|
458
464
|
};
|
465
|
+
E964F68C1FBF9B6B000114D9 /* Say */ = {
|
466
|
+
isa = PBXGroup;
|
467
|
+
children = (
|
468
|
+
E964F68D1FBF9CA6000114D9 /* SayExample.h */,
|
469
|
+
E964F68E1FBF9CA6000114D9 /* SayExample.m */,
|
470
|
+
E964F6901FBF9CC6000114D9 /* SayTest.m */,
|
471
|
+
);
|
472
|
+
name = Say;
|
473
|
+
sourceTree = "<group>";
|
474
|
+
};
|
459
475
|
E96993951DF60DF1009EA223 /* Transpose */ = {
|
460
476
|
isa = PBXGroup;
|
461
477
|
children = (
|
@@ -873,6 +889,7 @@
|
|
873
889
|
1EFACABA1CCCAF3D006F2E69 /* SpaceAgeTest.m in Sources */,
|
874
890
|
1EFACAB91CCCAF3D006F2E69 /* SpaceAgeExample.m in Sources */,
|
875
891
|
E9F390091DFCA350005C5F46 /* IsogramTest.m in Sources */,
|
892
|
+
E964F6911FBF9CC6000114D9 /* SayTest.m in Sources */,
|
876
893
|
E951B6B71D4294E6009EB5B6 /* AllergiesExample.m in Sources */,
|
877
894
|
E9FDCA1B1D540801004EE8DB /* RomanNumeralsTest.m in Sources */,
|
878
895
|
E9C1C0231D9D993E0015E86E /* SecretHandshakeExample.m in Sources */,
|
@@ -895,6 +912,7 @@
|
|
895
912
|
E9386EEE1E0B692D0009A414 /* AtbashCipherExample.m in Sources */,
|
896
913
|
1EFACAA61CCCAF3D006F2E69 /* BobTest.m in Sources */,
|
897
914
|
E9B345FA1DB93839006EFBE2 /* PangramTest.m in Sources */,
|
915
|
+
E964F68F1FBF9CA6000114D9 /* SayExample.m in Sources */,
|
898
916
|
E9895B701E8DA914006AD25D /* CryptoSquareTest.m in Sources */,
|
899
917
|
E9B9F2D41E9EB39C00214076 /* LuhnExample.m in Sources */,
|
900
918
|
E9A7B2F91DA5AC55009056B6 /* LargestSeriesProductTest.m in Sources */,
|
@@ -5,6 +5,7 @@ for the school.
|
|
5
5
|
|
6
6
|
In the end, you should be able to:
|
7
7
|
|
8
|
+
- Start with an empty school.
|
8
9
|
- Add a student's name to the roster for a grade
|
9
10
|
- "Add Jim to grade 2."
|
10
11
|
- "OK."
|
@@ -22,20 +23,6 @@ Note that all our students only have one name. (It's a small town, what
|
|
22
23
|
do you want?)
|
23
24
|
|
24
25
|
|
25
|
-
## For bonus points
|
26
|
-
|
27
|
-
Did you get the tests passing and the code clean? If you want to, these
|
28
|
-
are some additional things you could try:
|
29
|
-
|
30
|
-
- If you're working in a language with mutable data structures and your
|
31
|
-
implementation allows outside code to mutate the school's internal DB
|
32
|
-
directly, see if you can prevent this. Feel free to introduce additional
|
33
|
-
tests.
|
34
|
-
|
35
|
-
Then please share your thoughts in a comment on the submission. Did this
|
36
|
-
experiment make the code better? Worse? Did you learn anything from it?
|
37
|
-
|
38
|
-
|
39
26
|
## Getting Started
|
40
27
|
For installation and learning resources, refer to the
|
41
28
|
[exercism help page](http://exercism.io/languages/ocaml).
|
@@ -3,14 +3,12 @@ open OUnit2
|
|
3
3
|
|
4
4
|
module IMap = Int.Map
|
5
5
|
|
6
|
-
|
7
|
-
let ale exp got =
|
6
|
+
let assert_list_equals exp got =
|
8
7
|
let printer l = List.sexp_of_t String.sexp_of_t l
|
9
8
|
|> Sexp.to_string_hum ~indent:1 in
|
10
9
|
assert_equal exp got ~printer
|
11
10
|
|
12
|
-
|
13
|
-
let ame exp got =
|
11
|
+
let assert_map_equals exp got =
|
14
12
|
let printer m =
|
15
13
|
Map.to_alist m
|
16
14
|
|> List.sort ~cmp:compare
|
@@ -18,52 +16,44 @@ let ame exp got =
|
|
18
16
|
|> Sexp.to_string_hum ~indent:1 in
|
19
17
|
assert_equal exp got ~cmp:(Map.equal (=)) ~printer
|
20
18
|
|
21
|
-
(* The tests never reuse a school value, so if you like you can use destructive
|
22
|
-
* modification (i.e. mutable data structures). For the same reason
|
23
|
-
* Grade_school.create takes a unit argument.
|
24
|
-
*
|
25
|
-
* For those who wonder why the test doesn't use objects, it's to not force
|
26
|
-
* the use of objects. You can still use them internally though.
|
27
|
-
*)
|
28
|
-
|
29
19
|
let tests =
|
30
20
|
["add student">:: (fun _ ->
|
31
|
-
let got = Grade_school.
|
21
|
+
let got = Grade_school.empty_school
|
32
22
|
|> Grade_school.add "Aimee" 2 in
|
33
|
-
|
23
|
+
assert_map_equals (IMap.of_alist_exn [(2, ["Aimee"])])
|
34
24
|
(Grade_school.to_map got));
|
35
|
-
"add more students in
|
36
|
-
let got = Grade_school.
|
37
|
-
|> Grade_school.add "
|
25
|
+
"add more students in sassert_map_equals class">:: (fun _ ->
|
26
|
+
let got = Grade_school.empty_school
|
27
|
+
|> Grade_school.add "Jassert_map_equalss" 2
|
38
28
|
|> Grade_school.add "Blair" 2
|
39
29
|
|> Grade_school.add "Paul" 2 in
|
40
|
-
|
30
|
+
assert_map_equals (IMap.of_alist_exn [(2, ["Blair"; "Jassert_map_equalss"; "Paul"])])
|
41
31
|
(Grade_school.to_map got |> Map.map ~f:(List.sort ~cmp:compare)));
|
42
32
|
"add students to different grades">:: (fun _ ->
|
43
|
-
let got = Grade_school.
|
33
|
+
let got = Grade_school.empty_school
|
44
34
|
|> Grade_school.add "Chelsea" 3
|
45
35
|
|> Grade_school.add "Logan" 7 in
|
46
|
-
|
36
|
+
assert_map_equals (IMap.of_alist_exn [(3, ["Chelsea"]); (7, ["Logan"])])
|
47
37
|
(Grade_school.to_map got |> Map.map ~f:(List.sort ~cmp:compare)));
|
48
38
|
"get students in a grade">:: (fun _ ->
|
49
|
-
let got = Grade_school.
|
39
|
+
let got = Grade_school.empty_school
|
50
40
|
|> Grade_school.add "Franklin" 5
|
51
41
|
|> Grade_school.add "Bradley" 5
|
52
42
|
|> Grade_school.add "Jeff" 1
|
53
43
|
|> Grade_school.grade 5 in
|
54
|
-
|
44
|
+
assert_list_equals ["Bradley"; "Franklin"]
|
55
45
|
(List.sort ~cmp:compare got));
|
56
46
|
"get students in a non existant grade">:: (fun _ ->
|
57
|
-
|
47
|
+
assert_list_equals [] (List.sort ~cmp:compare (Grade_school.empty_school |> Grade_school.grade 2)));
|
58
48
|
"sort school">:: (fun _ ->
|
59
|
-
let got = Grade_school.
|
49
|
+
let got = Grade_school.empty_school
|
60
50
|
|> Grade_school.add "Christopher" 4
|
61
51
|
|> Grade_school.add "Jennifer" 4
|
62
52
|
|> Grade_school.add "Aaron" 4
|
63
53
|
|> Grade_school.add "Kareem" 6
|
64
54
|
|> Grade_school.add "Kyle" 3
|
65
55
|
|> Grade_school.sort in
|
66
|
-
|
56
|
+
assert_map_equals (IMap.of_alist_exn [(3, ["Kyle"]);
|
67
57
|
(4, ["Aaron"; "Christopher"; "Jennifer"]);
|
68
58
|
(6, ["Kareem"])])
|
69
59
|
(Grade_school.to_map got));
|
data/tracks/swift/config.json
CHANGED
@@ -572,6 +572,19 @@
|
|
572
572
|
"unlocked_by": null,
|
573
573
|
"uuid": "f6b157cb-ddb0-4c40-baa3-9fc6b58de7ff"
|
574
574
|
},
|
575
|
+
{
|
576
|
+
"core": false,
|
577
|
+
"difficulty": 4,
|
578
|
+
"slug": "say",
|
579
|
+
"topics": [
|
580
|
+
"loops",
|
581
|
+
"parsing",
|
582
|
+
"transforming",
|
583
|
+
"text_formatting"
|
584
|
+
],
|
585
|
+
"unlocked_by": null,
|
586
|
+
"uuid": "0f840c37-a8c0-42da-93f9-d215cb044d53"
|
587
|
+
},
|
575
588
|
{
|
576
589
|
"core": false,
|
577
590
|
"difficulty": 5,
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Say
|
2
|
+
|
3
|
+
Given a number from 0 to 999,999,999,999, spell out that number in English.
|
4
|
+
|
5
|
+
## Step 1
|
6
|
+
|
7
|
+
Handle the basic case of 0 through 99.
|
8
|
+
|
9
|
+
If the input to the program is `22`, then the output should be
|
10
|
+
`'twenty-two'`.
|
11
|
+
|
12
|
+
Your program should complain loudly if given a number outside the
|
13
|
+
blessed range.
|
14
|
+
|
15
|
+
Some good test cases for this program are:
|
16
|
+
|
17
|
+
- 0
|
18
|
+
- 14
|
19
|
+
- 50
|
20
|
+
- 98
|
21
|
+
- -1
|
22
|
+
- 100
|
23
|
+
|
24
|
+
### Extension
|
25
|
+
|
26
|
+
If you're on a Mac, shell out to Mac OS X's `say` program to talk out
|
27
|
+
loud.
|
28
|
+
|
29
|
+
## Step 2
|
30
|
+
|
31
|
+
Implement breaking a number up into chunks of thousands.
|
32
|
+
|
33
|
+
So `1234567890` should yield a list like 1, 234, 567, and 890, while the
|
34
|
+
far simpler `1000` should yield just 1 and 0.
|
35
|
+
|
36
|
+
The program must also report any values that are out of range.
|
37
|
+
|
38
|
+
## Step 3
|
39
|
+
|
40
|
+
Now handle inserting the appropriate scale word between those chunks.
|
41
|
+
|
42
|
+
So `1234567890` should yield `'1 billion 234 million 567 thousand 890'`
|
43
|
+
|
44
|
+
The program must also report any values that are out of range. It's
|
45
|
+
fine to stop at "trillion".
|
46
|
+
|
47
|
+
## Step 4
|
48
|
+
|
49
|
+
Put it all together to get nothing but plain English.
|
50
|
+
|
51
|
+
`12345` should give `twelve thousand three hundred forty-five`.
|
52
|
+
|
53
|
+
The program must also report any values that are out of range.
|
54
|
+
|
55
|
+
### Extensions
|
56
|
+
|
57
|
+
Use _and_ (correctly) when spelling out the number in English:
|
58
|
+
|
59
|
+
- 14 becomes "fourteen".
|
60
|
+
- 100 becomes "one hundred".
|
61
|
+
- 120 becomes "one hundred and twenty".
|
62
|
+
- 1002 becomes "one thousand and two".
|
63
|
+
- 1323 becomes "one thousand three hundred and twenty-three".
|
64
|
+
|
65
|
+
## Setup
|
66
|
+
|
67
|
+
Go through the project setup instructions for Xcode using Swift:
|
68
|
+
|
69
|
+
http://exercism.io/languages/swift
|
70
|
+
|
71
|
+
## Source
|
72
|
+
|
73
|
+
A variation on JavaRanch CattleDrive, exercise 4a [http://www.javaranch.com/say.jsp](http://www.javaranch.com/say.jsp)
|
74
|
+
|
75
|
+
## Submitting Incomplete Solutions
|
76
|
+
|
77
|
+
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,48 @@
|
|
1
|
+
struct Say {
|
2
|
+
|
3
|
+
private static let smallNumbers = [
|
4
|
+
"zero", "one", "two", "three", "four", "five",
|
5
|
+
"six", "seven", "eight", "nine", "ten",
|
6
|
+
"eleven", "twelve", "thirteen", "fourteen", "fifteen",
|
7
|
+
"sixteen", "seventeen", "eighteen", "nineteen"
|
8
|
+
]
|
9
|
+
|
10
|
+
private static let decades = [
|
11
|
+
"twenty", "thirty", "forty", "fifty",
|
12
|
+
"sixty", "seventy", "eighty", "ninety"
|
13
|
+
]
|
14
|
+
|
15
|
+
private static let largeGroups: [(name: String, amount: Int)] = [
|
16
|
+
("billion", 1_000_000_000), ("million", 1_000_000), ("thousand", 1_000), ("hundred", 100)
|
17
|
+
]
|
18
|
+
|
19
|
+
static func say(_ number: Int) -> String? {
|
20
|
+
guard number >= 0 && number < 1_000_000_000_000 else {
|
21
|
+
return nil
|
22
|
+
}
|
23
|
+
|
24
|
+
if number < 20 {
|
25
|
+
return smallNumbers[number]
|
26
|
+
}
|
27
|
+
|
28
|
+
for group in largeGroups where number >= group.amount {
|
29
|
+
let result = "\(say(number / group.amount)!) " + group.name
|
30
|
+
let remainder = number % group.amount
|
31
|
+
|
32
|
+
if remainder == 0 {
|
33
|
+
return result
|
34
|
+
} else {
|
35
|
+
return result + " \(say(remainder)!)"
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
let decade = number / 10
|
40
|
+
let decadeName = decades[decade - 2]
|
41
|
+
|
42
|
+
if number % 10 == 0 {
|
43
|
+
return decadeName
|
44
|
+
} else {
|
45
|
+
return decadeName + "-" + say(number % 10)!
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
@@ -0,0 +1,85 @@
|
|
1
|
+
import XCTest
|
2
|
+
@testable import Say
|
3
|
+
|
4
|
+
class SayTests: XCTestCase {
|
5
|
+
|
6
|
+
func testZero() {
|
7
|
+
XCTAssertEqual("zero", Say.say(0))
|
8
|
+
}
|
9
|
+
|
10
|
+
func testOne() {
|
11
|
+
XCTAssertEqual("one", Say.say(1))
|
12
|
+
}
|
13
|
+
|
14
|
+
func testFourteen() {
|
15
|
+
XCTAssertEqual("fourteen", Say.say(14))
|
16
|
+
}
|
17
|
+
|
18
|
+
func testTwenty() {
|
19
|
+
XCTAssertEqual("twenty", Say.say(20))
|
20
|
+
}
|
21
|
+
|
22
|
+
func testTwentyTwo() {
|
23
|
+
XCTAssertEqual("twenty-two", Say.say(22))
|
24
|
+
}
|
25
|
+
|
26
|
+
func testOneHundred() {
|
27
|
+
XCTAssertEqual("one hundred", Say.say(100))
|
28
|
+
}
|
29
|
+
|
30
|
+
func testOneHundredTwentyThree() {
|
31
|
+
XCTAssertEqual("one hundred twenty-three", Say.say(123))
|
32
|
+
}
|
33
|
+
|
34
|
+
func testOneThousand() {
|
35
|
+
XCTAssertEqual("one thousand", Say.say(1_000))
|
36
|
+
}
|
37
|
+
|
38
|
+
func testOneThousandTwoHundredThirtyFour() {
|
39
|
+
XCTAssertEqual("one thousand two hundred thirty-four", Say.say(1_234))
|
40
|
+
}
|
41
|
+
|
42
|
+
func testOneMillion() {
|
43
|
+
XCTAssertEqual("one million", Say.say(1_000_000))
|
44
|
+
}
|
45
|
+
|
46
|
+
func testOneMillionTwoThousandThreeHundredFortyFive() {
|
47
|
+
XCTAssertEqual("one million two thousand three hundred forty-five", Say.say(1_002_345))
|
48
|
+
}
|
49
|
+
|
50
|
+
func testOneBillion() {
|
51
|
+
XCTAssertEqual("one billion", Say.say(1_000_000_000))
|
52
|
+
}
|
53
|
+
|
54
|
+
func testABigNumber() {
|
55
|
+
XCTAssertEqual("nine hundred eighty-seven billion six hundred fifty-four million three hundred twenty-one thousand one hundred twenty-three", Say.say(987_654_321_123))
|
56
|
+
}
|
57
|
+
|
58
|
+
func testNumbersBelowZeroAreOutOfRange() {
|
59
|
+
XCTAssertNil(Say.say(-1))
|
60
|
+
}
|
61
|
+
|
62
|
+
func testNumbersAbove999999999999AreOutOfRange() {
|
63
|
+
XCTAssertNil(Say.say(1_000_000_000_000))
|
64
|
+
}
|
65
|
+
|
66
|
+
static var allTests: [(String, (SayTests) -> () throws -> Void)] {
|
67
|
+
return [
|
68
|
+
("testZero", testZero),
|
69
|
+
("testOne", testOne),
|
70
|
+
("testFourteen", testFourteen),
|
71
|
+
("testTwenty", testTwenty),
|
72
|
+
("testTwentyTwo", testTwentyTwo),
|
73
|
+
("testOneHundred", testOneHundred),
|
74
|
+
("testOneHundredTwentyThree", testOneHundredTwentyThree),
|
75
|
+
("testOneThousand", testOneThousand),
|
76
|
+
("testOneThousandTwoHundredThirtyFour", testOneThousandTwoHundredThirtyFour),
|
77
|
+
("testOneMillion", testOneMillion),
|
78
|
+
("testOneMillionTwoThousandThreeHundredFortyFive", testOneMillionTwoThousandThreeHundredFortyFive),
|
79
|
+
("testOneBillion", testOneBillion),
|
80
|
+
("testABigNumber", testABigNumber),
|
81
|
+
("testNumbersBelowZeroAreOutOfRange", testNumbersBelowZeroAreOutOfRange),
|
82
|
+
("testNumbersAbove999999999999AreOutOfRange", testNumbersAbove999999999999AreOutOfRange),
|
83
|
+
]
|
84
|
+
}
|
85
|
+
}
|
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.68
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Katrina Owen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-11-
|
11
|
+
date: 2017-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubyzip
|
@@ -5145,6 +5145,12 @@ files:
|
|
5145
5145
|
- tracks/fsharp/exercises/house/HouseTest.fs
|
5146
5146
|
- tracks/fsharp/exercises/house/Program.fs
|
5147
5147
|
- tracks/fsharp/exercises/house/README.md
|
5148
|
+
- tracks/fsharp/exercises/isbn-verifier/Example.fs
|
5149
|
+
- tracks/fsharp/exercises/isbn-verifier/IsbnVerifier.fs
|
5150
|
+
- tracks/fsharp/exercises/isbn-verifier/IsbnVerifier.fsproj
|
5151
|
+
- tracks/fsharp/exercises/isbn-verifier/IsbnVerifierTest.fs
|
5152
|
+
- tracks/fsharp/exercises/isbn-verifier/Program.fs
|
5153
|
+
- tracks/fsharp/exercises/isbn-verifier/README.md
|
5148
5154
|
- tracks/fsharp/exercises/isogram/Example.fs
|
5149
5155
|
- tracks/fsharp/exercises/isogram/Isogram.fs
|
5150
5156
|
- tracks/fsharp/exercises/isogram/Isogram.fsproj
|
@@ -5995,7 +6001,9 @@ files:
|
|
5995
6001
|
- tracks/go/exercises/series/first_example.go
|
5996
6002
|
- tracks/go/exercises/series/first_test.go
|
5997
6003
|
- tracks/go/exercises/series/series_test.go
|
6004
|
+
- tracks/go/exercises/sieve/.meta/gen.go
|
5998
6005
|
- tracks/go/exercises/sieve/README.md
|
6006
|
+
- tracks/go/exercises/sieve/cases_test.go
|
5999
6007
|
- tracks/go/exercises/sieve/example.go
|
6000
6008
|
- tracks/go/exercises/sieve/sieve_test.go
|
6001
6009
|
- tracks/go/exercises/simple-cipher/.meta/description.md
|
@@ -9178,6 +9186,9 @@ files:
|
|
9178
9186
|
- tracks/objective-c/exercises/run-length-encoding/RunLengthEncodingExample.h
|
9179
9187
|
- tracks/objective-c/exercises/run-length-encoding/RunLengthEncodingExample.m
|
9180
9188
|
- tracks/objective-c/exercises/run-length-encoding/RunLengthEncodingTest.m
|
9189
|
+
- tracks/objective-c/exercises/say/SayExample.h
|
9190
|
+
- tracks/objective-c/exercises/say/SayExample.m
|
9191
|
+
- tracks/objective-c/exercises/say/SayTest.m
|
9181
9192
|
- tracks/objective-c/exercises/scrabble-score/README.md
|
9182
9193
|
- tracks/objective-c/exercises/scrabble-score/ScrabbleScoreExample.h
|
9183
9194
|
- tracks/objective-c/exercises/scrabble-score/ScrabbleScoreExample.m
|
@@ -13511,6 +13522,12 @@ files:
|
|
13511
13522
|
- tracks/swift/exercises/saddle-points/Sources/SaddlePointsExample.swift
|
13512
13523
|
- tracks/swift/exercises/saddle-points/Tests/LinuxMain.swift
|
13513
13524
|
- tracks/swift/exercises/saddle-points/Tests/SaddlePointsTests/SaddlePointsTests.swift
|
13525
|
+
- tracks/swift/exercises/say/Package.swift
|
13526
|
+
- tracks/swift/exercises/say/README.md
|
13527
|
+
- tracks/swift/exercises/say/Sources/Say.swift
|
13528
|
+
- tracks/swift/exercises/say/Sources/SayExample.swift
|
13529
|
+
- tracks/swift/exercises/say/Tests/LinuxMain.swift
|
13530
|
+
- tracks/swift/exercises/say/Tests/SayTests/SayTests.swift
|
13514
13531
|
- tracks/swift/exercises/scrabble-score/.gitignore
|
13515
13532
|
- tracks/swift/exercises/scrabble-score/Package.swift
|
13516
13533
|
- tracks/swift/exercises/scrabble-score/README.md
|