trackler 2.2.1.75 → 2.2.1.76
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/alphametics/canonical-data.json +18 -1
- data/problem-specifications/exercises/anagram/canonical-data.json +72 -39
- data/problem-specifications/exercises/binary/canonical-data.json +47 -17
- data/tracks/clojure/exercises/beer-song/src/beer_song.clj +11 -0
- data/tracks/erlang/config.json +10 -0
- data/tracks/erlang/exercises/raindrops/README.md +67 -0
- data/tracks/erlang/exercises/raindrops/rebar.config +30 -0
- data/tracks/erlang/exercises/raindrops/src/example.erl +30 -0
- data/tracks/erlang/exercises/raindrops/src/raindrops.app.src +9 -0
- data/tracks/erlang/exercises/raindrops/src/raindrops.erl +8 -0
- data/tracks/erlang/exercises/raindrops/test/raindrops_tests.erl +50 -0
- data/tracks/fsharp/exercises/bob/BobTest.fs +2 -2
- data/tracks/fsharp/exercises/bob/Example.fs +10 -4
- data/tracks/fsharp/exercises/book-store/BookStoreTest.fs +5 -1
- data/tracks/fsharp/exercises/rna-transcription/RnaTranscriptionTest.fs +1 -13
- data/tracks/fsharp/generators/CanonicalData.fs +14 -7
- data/tracks/fsharp/generators/Exercise.fs +84 -18
- data/tracks/fsharp/generators/Generators.fs +65 -62
- data/tracks/fsharp/generators/Generators.fsproj +0 -4
- data/tracks/fsharp/generators/Options.fs +51 -17
- data/tracks/fsharp/generators/Program.fs +34 -7
- data/tracks/fsharp/generators/Rendering.fs +2 -1
- data/tracks/go/config.json +11 -0
- data/tracks/go/exercises/reverse-string/.meta/gen.go +52 -0
- data/tracks/go/exercises/reverse-string/README.md +31 -0
- data/tracks/go/exercises/reverse-string/cases_test.go +37 -0
- data/tracks/go/exercises/reverse-string/example.go +10 -0
- data/tracks/go/exercises/reverse-string/reverse_string_test.go +25 -0
- data/tracks/haskell/exercises/bob/README.md +2 -0
- data/tracks/haskell/exercises/bob/examples/success-standard/src/Bob.hs +7 -3
- data/tracks/haskell/exercises/bob/package.yaml +1 -1
- data/tracks/haskell/exercises/bob/test/Tests.hs +1 -1
- data/tracks/haskell/exercises/isbn-verifier/README.md +25 -20
- data/tracks/haskell/exercises/pov/README.md +0 -2
- data/tracks/haskell/exercises/secret-handshake/README.md +1 -1
- data/tracks/haskell/exercises/simple-cipher/README.md +4 -6
- data/tracks/java/config.json +12 -0
- data/tracks/java/exercises/beer-song/README.md +1 -1
- data/tracks/java/exercises/house/README.md +1 -1
- data/tracks/java/exercises/isbn-verifier/README.md +27 -21
- data/tracks/java/exercises/kindergarten-garden/README.md +3 -3
- data/tracks/java/exercises/meetup/README.md +16 -12
- data/tracks/java/exercises/nucleotide-count/README.md +2 -2
- data/tracks/java/exercises/palindrome-products/README.md +1 -1
- data/tracks/java/exercises/parallel-letter-frequency/.meta/HINTS.md +3 -0
- data/tracks/java/exercises/parallel-letter-frequency/.meta/src/reference/java/ParallelLetterFrequency.java +45 -0
- data/tracks/java/exercises/parallel-letter-frequency/README.md +30 -0
- data/tracks/java/exercises/parallel-letter-frequency/build.gradle +18 -0
- data/tracks/java/exercises/parallel-letter-frequency/src/main/java/.keep +0 -0
- data/tracks/java/exercises/parallel-letter-frequency/src/test/java/ParallelLetterFrequencyTest.java +235 -0
- data/tracks/java/exercises/pig-latin/README.md +1 -0
- data/tracks/java/exercises/protein-translation/README.md +4 -2
- data/tracks/java/exercises/rectangles/README.md +9 -9
- data/tracks/java/exercises/settings.gradle +1 -0
- data/tracks/java/exercises/simple-cipher/README.md +4 -6
- data/tracks/java/exercises/sum-of-multiples/README.md +3 -3
- data/tracks/objective-c/config.json +11 -0
- data/tracks/objective-c/exercises/two-fer/TwoFerExample.h +15 -0
- data/tracks/objective-c/exercises/two-fer/TwoFerExample.m +21 -0
- data/tracks/objective-c/exercises/two-fer/TwoFerTest.m +31 -0
- data/tracks/objective-c/xcodeProject/ObjectiveC.xcodeproj/project.pbxproj +18 -0
- data/tracks/rust/exercises/bob/Cargo.toml +1 -1
- data/tracks/rust/exercises/bob/README.md +2 -0
- data/tracks/rust/exercises/bob/example.rs +1 -0
- data/tracks/rust/exercises/bob/tests/bob.rs +1 -1
- data/tracks/rust/exercises/isbn-verifier/README.md +25 -20
- data/tracks/typescript/config.json +13 -0
- data/tracks/typescript/exercises/atbash-cipher/README.md +60 -0
- data/tracks/typescript/exercises/atbash-cipher/atbash-cipher.example.ts +32 -0
- data/tracks/typescript/exercises/atbash-cipher/atbash-cipher.test.ts +73 -0
- data/tracks/typescript/exercises/atbash-cipher/atbash-cipher.ts +0 -0
- data/tracks/typescript/exercises/atbash-cipher/package.json +36 -0
- data/tracks/typescript/exercises/atbash-cipher/tsconfig.json +22 -0
- data/tracks/typescript/exercises/atbash-cipher/tslint.json +127 -0
- data/tracks/typescript/exercises/atbash-cipher/yarn.lock +2624 -0
- metadata +31 -2
@@ -16,10 +16,6 @@
|
|
16
16
|
<Compile Include="Program.fs" />
|
17
17
|
</ItemGroup>
|
18
18
|
|
19
|
-
<ItemGroup>
|
20
|
-
<EmbeddedResource Include="Templates\*.liquid" />
|
21
|
-
</ItemGroup>
|
22
|
-
|
23
19
|
<ItemGroup>
|
24
20
|
<PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
|
25
21
|
<PackageReference Include="DotLiquid" Version="2.0.232" />
|
@@ -4,26 +4,60 @@ open System
|
|
4
4
|
open System.IO
|
5
5
|
open CommandLine
|
6
6
|
|
7
|
-
type
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
7
|
+
type Status =
|
8
|
+
| Implemented
|
9
|
+
| Unimplemented
|
10
|
+
| MissingData
|
11
|
+
| Custom
|
12
|
+
|
13
|
+
type CommandLineOptions =
|
14
|
+
{ [<Option('e', "exercise", Required = false,
|
15
|
+
HelpText = "Exercise to generate (if not specified, defaults to all exercises).")>] Exercise : string;
|
16
|
+
[<Option('s', "status", Required = false,
|
17
|
+
HelpText = "The generator status to filter on (defaults to exercises with generator).")>] Status : string;
|
18
|
+
[<Option('d', "canonicaldatadirectory", Required = false,
|
19
|
+
HelpText = "Canonical data directory. If the directory does not exist, the canonical data will be downloaded.")>] CanonicalDataDirectory : string;
|
20
|
+
[<Option('c', "cachecanonicaldata", Required = false,
|
21
|
+
HelpText = "Use the cached canonical data and don't update the data.")>] CacheCanonicalData : bool; }
|
22
|
+
|
23
|
+
type Options =
|
24
|
+
{ Exercise : string option
|
25
|
+
Status : Status option
|
26
|
+
CanonicalDataDirectory : string
|
27
|
+
CacheCanonicalData : bool }
|
28
|
+
|
29
|
+
let private normalizeCanonicalDataDirectory canonicalDataDirectory =
|
30
|
+
if canonicalDataDirectory <> "" then
|
31
|
+
canonicalDataDirectory
|
19
32
|
else
|
20
33
|
let appDataDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
|
21
34
|
let defaultCanonicalDataDirectory = Path.Combine(appDataDirectory, "exercism", "problem-specifications")
|
22
|
-
|
35
|
+
defaultCanonicalDataDirectory
|
36
|
+
|
37
|
+
let private normalizeExercise exercise = Option.ofNonEmptyString exercise
|
38
|
+
|
39
|
+
let private normalizeStatus status =
|
40
|
+
match Option.ofNonEmptyString status with
|
41
|
+
| Some "Implemented" -> Some Implemented
|
42
|
+
| Some "Unimplemented" -> Some Unimplemented
|
43
|
+
| Some "MissingData" -> Some MissingData
|
44
|
+
| Some "Custom" -> Some Custom
|
45
|
+
| Some "All" -> None
|
46
|
+
| Some _ -> failwith "Invalid status"
|
47
|
+
| None -> Some Implemented
|
48
|
+
|
49
|
+
let private mapOptions (options: CommandLineOptions) =
|
50
|
+
{ Exercise = normalizeExercise options.Exercise
|
51
|
+
Status = normalizeStatus options.Status
|
52
|
+
CanonicalDataDirectory = normalizeCanonicalDataDirectory options.CanonicalDataDirectory
|
53
|
+
CacheCanonicalData = options.CacheCanonicalData }
|
23
54
|
|
24
55
|
let parseOptions argv =
|
25
|
-
let result = CommandLine.Parser.Default.ParseArguments<
|
56
|
+
let result = CommandLine.Parser.Default.ParseArguments<CommandLineOptions>(argv)
|
26
57
|
match result with
|
27
|
-
| :? Parsed<
|
28
|
-
|
29
|
-
|
|
58
|
+
| :? Parsed<CommandLineOptions> as parsed ->
|
59
|
+
Result.Ok(mapOptions parsed.Value)
|
60
|
+
| :? NotParsed<CommandLineOptions> as notParsed ->
|
61
|
+
Result.Error(notParsed.Errors |> Seq.map string)
|
62
|
+
| _ ->
|
63
|
+
failwith "Invalid parsing result"
|
@@ -5,21 +5,48 @@ open Exercise
|
|
5
5
|
open CanonicalData
|
6
6
|
open Options
|
7
7
|
|
8
|
+
let private isNotFilteredByName options (exercise: Exercise) =
|
9
|
+
match options.Exercise with
|
10
|
+
| Some filteredExerciseName -> filteredExerciseName = exerciseName exercise
|
11
|
+
| None -> true
|
12
|
+
|
13
|
+
let private isNotFilteredByStatus options (exercise: Exercise) =
|
14
|
+
match options.Status, exercise with
|
15
|
+
| None, _ -> true
|
16
|
+
| Some Status.Implemented, Exercise.Generator _ -> true
|
17
|
+
| Some Status.Unimplemented, Exercise.Unimplemented _ -> true
|
18
|
+
| Some Status.MissingData, Exercise.MissingData _ -> true
|
19
|
+
| Some Status.Custom, Exercise.Custom _ -> true
|
20
|
+
| _ -> false
|
21
|
+
|
22
|
+
let private shouldBeIncluded options (exercise: Exercise) =
|
23
|
+
isNotFilteredByName options exercise &&
|
24
|
+
isNotFilteredByStatus options exercise
|
25
|
+
|
8
26
|
let private regenerateTestClass options =
|
9
27
|
let parseCanonicalData' = parseCanonicalData options
|
10
28
|
|
11
|
-
fun (exercise
|
12
|
-
|
13
|
-
|
29
|
+
fun (exercise) ->
|
30
|
+
match exercise with
|
31
|
+
| Exercise.Custom custom ->
|
32
|
+
Log.Information("{Exercise}: has customized tests", custom.Name)
|
33
|
+
| Exercise.Unimplemented unimplemented ->
|
34
|
+
Log.Error("{Exercise}: missing test generator", unimplemented.Name)
|
35
|
+
| Exercise.MissingData missingData ->
|
36
|
+
Log.Warning("{Exercise}: missing canonical data", missingData.Name)
|
37
|
+
| Exercise.Generator generator ->
|
38
|
+
let canonicalData = parseCanonicalData' generator.Name
|
39
|
+
generator.Regenerate(canonicalData)
|
40
|
+
Log.Information("{Exercise}: tests generated", generator.Name)
|
14
41
|
|
15
42
|
let private regenerateTestClasses options =
|
16
43
|
Log.Information("Re-generating test classes...")
|
17
44
|
|
18
45
|
let regenerateTestClass' = regenerateTestClass options
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|>
|
46
|
+
|
47
|
+
createExercises options
|
48
|
+
|> List.filter (shouldBeIncluded options)
|
49
|
+
|> List.iter regenerateTestClass'
|
23
50
|
|
24
51
|
Log.Information("Re-generated test classes.")
|
25
52
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module Generators.Rendering
|
2
2
|
|
3
|
+
open System.IO
|
3
4
|
open System.Collections.Generic
|
4
5
|
open System.Reflection
|
5
6
|
open FSharp.Reflection
|
@@ -12,7 +13,7 @@ type OutputFilter() =
|
|
12
13
|
|
13
14
|
static member Indent (input: string) = indent 1 input
|
14
15
|
|
15
|
-
let private fileSystem =
|
16
|
+
let private fileSystem = LocalFileSystem(Path.GetFullPath("./Templates"))
|
16
17
|
Template.RegisterFilter(OutputFilter().GetType())
|
17
18
|
Template.FileSystem <- fileSystem :> DotLiquid.FileSystems.IFileSystem
|
18
19
|
|
data/tracks/go/config.json
CHANGED
@@ -115,6 +115,17 @@
|
|
115
115
|
"unlocked_by": null,
|
116
116
|
"uuid": "c2064df8-cce5-4f03-9d85-0818b4e34112"
|
117
117
|
},
|
118
|
+
{
|
119
|
+
"core": false,
|
120
|
+
"difficulty": 2,
|
121
|
+
"slug": "reverse-string",
|
122
|
+
"topics": [
|
123
|
+
"sequences",
|
124
|
+
"strings"
|
125
|
+
],
|
126
|
+
"unlocked_by": "isogram",
|
127
|
+
"uuid": "e2df2756-7a48-4b45-b601-91be91027dbd"
|
128
|
+
},
|
118
129
|
{
|
119
130
|
"core": true,
|
120
131
|
"difficulty": 2,
|
@@ -0,0 +1,52 @@
|
|
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("reverse-string", &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
|
+
Exercise string
|
24
|
+
Version string
|
25
|
+
Cases []oneCase
|
26
|
+
}
|
27
|
+
|
28
|
+
// Test cases
|
29
|
+
type oneCase struct {
|
30
|
+
Description string
|
31
|
+
Property string
|
32
|
+
Input string
|
33
|
+
Expected string
|
34
|
+
}
|
35
|
+
|
36
|
+
// Template to generate test cases.
|
37
|
+
var tmpl = `package reverse
|
38
|
+
|
39
|
+
{{.Header}}
|
40
|
+
|
41
|
+
var testCases = []struct {
|
42
|
+
description string
|
43
|
+
input string
|
44
|
+
expected string
|
45
|
+
}{ {{range .J.Cases}}
|
46
|
+
{
|
47
|
+
description: {{printf "%q" .Description}},
|
48
|
+
input: {{printf "%q" .Input}},
|
49
|
+
expected: {{printf "%q" .Expected}},
|
50
|
+
},{{end}}
|
51
|
+
}
|
52
|
+
`
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# reverse-string
|
2
|
+
|
3
|
+
Reverse a string
|
4
|
+
|
5
|
+
For example:
|
6
|
+
input: "cool"
|
7
|
+
output: "looc"
|
8
|
+
|
9
|
+
## Running the tests
|
10
|
+
|
11
|
+
To run the tests run the command `go test` from within the exercise directory.
|
12
|
+
|
13
|
+
If the test suite contains benchmarks, you can run these with the `-bench`
|
14
|
+
flag:
|
15
|
+
|
16
|
+
go test -bench .
|
17
|
+
|
18
|
+
Keep in mind that each reviewer will run benchmarks on a different machine, with
|
19
|
+
different specs, so the results from these benchmark tests may vary.
|
20
|
+
|
21
|
+
## Further information
|
22
|
+
|
23
|
+
For more detailed information about the Go track, including how to get help if
|
24
|
+
you're having trouble, please visit the exercism.io [Go language page](http://exercism.io/languages/go/about).
|
25
|
+
|
26
|
+
## Source
|
27
|
+
|
28
|
+
Introductory challenge to reverse an input string [https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb](https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb)
|
29
|
+
|
30
|
+
## Submitting Incomplete Solutions
|
31
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
@@ -0,0 +1,37 @@
|
|
1
|
+
package reverse
|
2
|
+
|
3
|
+
// Source: exercism/problem-specifications
|
4
|
+
// Commit: ae82c90 More consistent reverse-string canonical data
|
5
|
+
// Problem Specifications Version: 1.0.1
|
6
|
+
|
7
|
+
var testCases = []struct {
|
8
|
+
description string
|
9
|
+
input string
|
10
|
+
expected string
|
11
|
+
}{
|
12
|
+
{
|
13
|
+
description: "an empty string",
|
14
|
+
input: "",
|
15
|
+
expected: "",
|
16
|
+
},
|
17
|
+
{
|
18
|
+
description: "a word",
|
19
|
+
input: "robot",
|
20
|
+
expected: "tobor",
|
21
|
+
},
|
22
|
+
{
|
23
|
+
description: "a capitalized word",
|
24
|
+
input: "Ramen",
|
25
|
+
expected: "nemaR",
|
26
|
+
},
|
27
|
+
{
|
28
|
+
description: "a sentence with punctuation",
|
29
|
+
input: "I'm hungry!",
|
30
|
+
expected: "!yrgnuh m'I",
|
31
|
+
},
|
32
|
+
{
|
33
|
+
description: "a palindrome",
|
34
|
+
input: "racecar",
|
35
|
+
expected: "racecar",
|
36
|
+
},
|
37
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
package reverse
|
2
|
+
|
3
|
+
import (
|
4
|
+
"testing"
|
5
|
+
"testing/quick"
|
6
|
+
)
|
7
|
+
|
8
|
+
func TestReverse(t *testing.T) {
|
9
|
+
for _, testCase := range testCases {
|
10
|
+
if res := String(testCase.input); res != testCase.expected {
|
11
|
+
t.Fatalf("FAIL: %s(%s)\nExpected: %q\nActual: %q",
|
12
|
+
testCase.description, testCase.input, testCase.expected, res)
|
13
|
+
}
|
14
|
+
t.Logf("PASS: %s", testCase.description)
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
func TestReverseOfReverse(t *testing.T) {
|
19
|
+
assertion := func(s string) bool {
|
20
|
+
return s == String(String(s))
|
21
|
+
}
|
22
|
+
if err := quick.Check(assertion, nil); err != nil {
|
23
|
+
t.Fatal(err)
|
24
|
+
}
|
25
|
+
}
|
@@ -6,6 +6,8 @@ Bob answers 'Sure.' if you ask him a question.
|
|
6
6
|
|
7
7
|
He answers 'Whoa, chill out!' if you yell at him.
|
8
8
|
|
9
|
+
He answers 'Calm down, I know what I'm doing!' if you yell a question at him.
|
10
|
+
|
9
11
|
He says 'Fine. Be that way!' if you address him without actually saying
|
10
12
|
anything.
|
11
13
|
|
@@ -1,16 +1,20 @@
|
|
1
1
|
module Bob (responseFor) where
|
2
2
|
import Data.Char (isSpace, isUpper, isAlpha)
|
3
3
|
|
4
|
-
data Prompt = Silence | Yell | Question | Other
|
4
|
+
data Prompt = Silence | YellQuestion | Yell | Question | Other
|
5
5
|
|
6
6
|
classify :: String -> Prompt
|
7
7
|
classify s | all isSpace s = Silence
|
8
|
-
|
|
9
|
-
|
|
8
|
+
| yell && question = YellQuestion
|
9
|
+
| yell = Yell
|
10
|
+
| question = Question
|
10
11
|
| otherwise = Other
|
12
|
+
where yell = any isAlpha s && all isUpper (filter isAlpha s)
|
13
|
+
question = '?' == last (filter (not . isSpace) s)
|
11
14
|
|
12
15
|
response :: Prompt -> String
|
13
16
|
response Silence = "Fine. Be that way!"
|
17
|
+
response YellQuestion = "Calm down, I know what I'm doing!"
|
14
18
|
response Yell = "Whoa, chill out!"
|
15
19
|
response Question = "Sure."
|
16
20
|
response Other = "Whatever."
|
@@ -54,7 +54,7 @@ cases = [ Case { description = "stating something"
|
|
54
54
|
}
|
55
55
|
, Case { description = "forceful question"
|
56
56
|
, input = "WHAT THE HELL WERE YOU THINKING?"
|
57
|
-
, expected = "
|
57
|
+
, expected = "Calm down, I know what I'm doing!"
|
58
58
|
}
|
59
59
|
, Case { description = "shouting numbers"
|
60
60
|
, input = "1, 2, 3 GO!"
|
@@ -1,40 +1,45 @@
|
|
1
1
|
# Isbn Verifier
|
2
2
|
|
3
|
-
|
3
|
+
The [ISBN-10 verification process](https://en.wikipedia.org/wiki/International_Standard_Book_Number) is used to validate book identification
|
4
|
+
numbers. These normally contain dashes and look like: `3-598-21508-8`
|
4
5
|
|
5
|
-
##
|
6
|
+
## ISBN
|
6
7
|
|
7
|
-
|
8
|
-
Putting this into place requires some thinking about preprocessing/parsing of the string prior to calculating the check digit for the ISBN.
|
8
|
+
The ISBN-10 format is 9 digits (0 to 9) plus one check character (either a digit or an X only). In the case the check character is an X, this represents the value '10'. These may be communicated with or without hyphens, and can be checked for their validity by the following formula:
|
9
9
|
|
10
|
-
|
10
|
+
```
|
11
|
+
(x1 * 10 + x2 * 9 + x3 * 8 + x4 * 7 + x5 * 6 + x6 * 5 + x7 * 4 + x8 * 3 + x9 * 2 + x10 * 1) mod 11 == 0
|
12
|
+
```
|
11
13
|
|
12
|
-
|
14
|
+
If the result is 0, then it is a valid ISBN-10, otherwise it is invalid.
|
13
15
|
|
14
|
-
|
15
|
-
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.
|
16
|
-
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.
|
17
|
-
The last digit in the ISBN is the check digit which is used to detect read errors.
|
16
|
+
## Example
|
18
17
|
|
19
|
-
|
20
|
-
|
18
|
+
Let's take the ISBN-10 `3-598-21508-8`. We plug it in to the formula, and get:
|
19
|
+
```
|
20
|
+
(3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 == 0
|
21
|
+
```
|
22
|
+
|
23
|
+
Since the result is 0, this proves that our ISBN is valid.
|
24
|
+
|
25
|
+
## Task
|
26
|
+
|
27
|
+
Given a string the program should check if the provided string is a valid ISBN-10.
|
28
|
+
Putting this into place requires some thinking about preprocessing/parsing of the string prior to calculating the check digit for the ISBN.
|
21
29
|
|
22
|
-
|
23
|
-
So for our example ISBN this means:
|
24
|
-
(3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 = 0
|
30
|
+
The program should be able to verify ISBN-10 both with and without separating dashes.
|
25
31
|
|
26
|
-
Which proves that the ISBN is valid.
|
27
32
|
|
28
33
|
## Caveats
|
29
34
|
|
30
|
-
Converting from
|
31
|
-
|
35
|
+
Converting from strings to numbers can be tricky in certain languages.
|
36
|
+
Now, it's even trickier since the check digit of an ISBN-10 may be 'X' (representing '10'). For instance `3-598-21507-X` is a valid ISBN-10.
|
32
37
|
|
33
38
|
## Bonus tasks
|
34
39
|
|
35
|
-
* Generate a valid ISBN-13 from the input ISBN-10 (and maybe verify it again with a derived verifier)
|
40
|
+
* Generate a valid ISBN-13 from the input ISBN-10 (and maybe verify it again with a derived verifier).
|
36
41
|
|
37
|
-
* Generate valid ISBN, maybe even from a given starting ISBN
|
42
|
+
* Generate valid ISBN, maybe even from a given starting ISBN.
|
38
43
|
|
39
44
|
## Getting Started
|
40
45
|
|