trackler 2.0.8.24 → 2.0.8.26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/tracks/c/config.json +9 -0
- data/tracks/c/exercises/nucleotide-count/makefile +15 -0
- data/tracks/c/exercises/nucleotide-count/src/example.c +43 -0
- data/tracks/c/exercises/nucleotide-count/src/example.h +6 -0
- data/tracks/c/exercises/nucleotide-count/test/test_nucleotide_count.c +58 -0
- data/tracks/c/exercises/nucleotide-count/test/vendor/unity.c +1300 -0
- data/tracks/c/exercises/nucleotide-count/test/vendor/unity.h +274 -0
- data/tracks/c/exercises/nucleotide-count/test/vendor/unity_internals.h +701 -0
- data/tracks/ceylon/README.md +2 -2
- data/tracks/csharp/.gitattributes +11 -0
- data/tracks/csharp/appveyor.yml +1 -4
- data/tracks/csharp/exercises/acronym/AcronymTest.cs +1 -1
- data/tracks/csharp/exercises/atbash-cipher/AtbashCipher.cs +8 -3
- data/tracks/csharp/exercises/atbash-cipher/AtbashCipherTest.cs +76 -0
- data/tracks/csharp/exercises/atbash-cipher/Example.cs +22 -23
- data/tracks/csharp/exercises/isogram/Example.cs +2 -2
- data/tracks/csharp/exercises/isogram/IsogramTest.cs +47 -15
- data/tracks/csharp/exercises/nth-prime/Example.cs +4 -1
- data/tracks/csharp/exercises/nth-prime/NthPrime.cs +1 -1
- data/tracks/csharp/exercises/nth-prime/NthPrimeTest.cs +29 -15
- data/tracks/csharp/exercises/perfect-numbers/Example.cs +14 -16
- data/tracks/csharp/exercises/perfect-numbers/PerfectNumbers.cs +2 -2
- data/tracks/csharp/exercises/perfect-numbers/PerfectNumbersTest.cs +78 -26
- data/tracks/csharp/exercises/pig-latin/PigLatinTest.cs +69 -24
- data/tracks/csharp/exercises/raindrops/Example.cs +1 -1
- data/tracks/csharp/exercises/raindrops/RaindropsTest.cs +93 -31
- data/tracks/csharp/exercises/roman-numerals/HINTS.md +2 -0
- data/tracks/csharp/exercises/roman-numerals/RomanNumeralsTest.cs +106 -23
- data/tracks/csharp/exercises/word-search/HINTS.md +6 -0
- data/tracks/csharp/generators/{TestClass.cs → Classes/TestClass.cs} +2 -1
- data/tracks/csharp/generators/{TestClassNameTransformer.cs → Classes/TestClassNameTransformer.cs} +1 -1
- data/tracks/csharp/generators/{TestClassRenderer.cs → Classes/TestClassRenderer.cs} +2 -1
- data/tracks/csharp/generators/Classes/TestedClassNameTransformer.cs +9 -0
- data/tracks/csharp/generators/{CanonicalData.cs → Data/CanonicalData.cs} +1 -1
- data/tracks/csharp/generators/{CanonicalDataCase.cs → Data/CanonicalDataCase.cs} +3 -3
- data/tracks/csharp/generators/{CanonicalDataCaseJsonConverter.cs → Data/CanonicalDataCaseJsonConverter.cs} +1 -1
- data/tracks/csharp/generators/{CanonicalDataCasesJsonConverter.cs → Data/CanonicalDataCasesJsonConverter.cs} +2 -2
- data/tracks/csharp/generators/{CanonicalDataParser.cs → Data/CanonicalDataParser.cs} +5 -5
- data/tracks/csharp/generators/{ExerciseCollection.cs → Data/ExerciseCollection.cs} +3 -3
- data/tracks/csharp/generators/Exercises/AcronymExercise.cs +20 -0
- data/tracks/csharp/generators/Exercises/AtbashCipherExercise.cs +20 -0
- data/tracks/csharp/generators/Exercises/BooleanExercise.cs +14 -0
- data/tracks/csharp/generators/Exercises/EqualityExercise.cs +14 -0
- data/tracks/csharp/generators/Exercises/Exercise.cs +59 -4
- data/tracks/csharp/generators/Exercises/IsogramExercise.cs +9 -0
- data/tracks/csharp/generators/Exercises/LeapExercise.cs +1 -4
- data/tracks/csharp/generators/Exercises/NthPrimeExercise.cs +25 -0
- data/tracks/csharp/generators/Exercises/PerfectNumbersExercise.cs +29 -0
- data/tracks/csharp/generators/Exercises/PigLatinExercise.cs +9 -0
- data/tracks/csharp/generators/Exercises/RaindropsExercise.cs +20 -0
- data/tracks/csharp/generators/Exercises/RomanNumeralsExercise.cs +30 -0
- data/tracks/csharp/generators/Helpers/StringExtensions.cs +8 -0
- data/tracks/csharp/generators/{To.cs → Helpers/To.cs} +4 -1
- data/tracks/csharp/generators/Methods/BooleanTestMethodGenerator.cs +32 -0
- data/tracks/csharp/generators/Methods/EqualityTestMethodGenerator.cs +25 -0
- data/tracks/csharp/generators/Methods/ExceptionTestMethodGenerator.cs +30 -0
- data/tracks/csharp/generators/{TestMethod.cs → Methods/TestMethod.cs} +6 -3
- data/tracks/csharp/generators/Methods/TestMethodData.cs +12 -0
- data/tracks/csharp/generators/Methods/TestMethodGenerator.cs +64 -0
- data/tracks/csharp/generators/Methods/TestMethodNameTransformer.cs +23 -0
- data/tracks/csharp/generators/Methods/TestMethodOptions.cs +13 -0
- data/tracks/csharp/generators/{TestMethodRenderer.cs → Methods/TestMethodRenderer.cs} +1 -1
- data/tracks/csharp/generators/{TestedMethodNameTransformer.cs → Methods/TestedMethodNameTransformer.cs} +1 -1
- data/tracks/csharp/generators/Methods/TestedMethodType.cs +9 -0
- data/tracks/csharp/generators/Program.cs +2 -0
- data/tracks/elixir/config.json +7 -0
- data/tracks/elixir/exercises/diffie-hellman/HINTS.md +10 -0
- data/tracks/elixir/exercises/diffie-hellman/diffie_hellman.exs +61 -0
- data/tracks/elixir/exercises/diffie-hellman/diffie_hellman_test.exs +99 -0
- data/tracks/elixir/exercises/diffie-hellman/example.exs +64 -0
- data/tracks/haskell/exercises/pov/src/POV.hs +2 -2
- data/tracks/haskell/exercises/pythagorean-triplet/src/Triplet.hs +6 -3
- data/tracks/haskell/exercises/queen-attack/src/Queens.hs +1 -1
- data/tracks/haskell/exercises/raindrops/src/Raindrops.hs +2 -1
- data/tracks/haskell/exercises/robot-name/src/Robot.hs +2 -2
- data/tracks/haskell/exercises/robot-simulator/src/Robot.hs +6 -6
- data/tracks/haskell/exercises/roman-numerals/src/Roman.hs +2 -1
- data/tracks/haskell/exercises/run-length-encoding/src/RunLength.hs +2 -2
- data/tracks/haskell/exercises/saddle-points/src/Matrix.hs +2 -1
- data/tracks/haskell/exercises/say/src/Say.hs +2 -1
- data/tracks/haskell/exercises/scrabble-score/src/Scrabble.hs +4 -2
- data/tracks/haskell/exercises/secret-handshake/src/SecretHandshake.hs +1 -1
- data/tracks/haskell/exercises/sgf-parsing/src/Sgf.hs +1 -1
- data/tracks/java/exercises/acronym/src/example/java/Acronym.java +11 -1
- data/tracks/java/exercises/acronym/src/test/java/AcronymTest.java +8 -9
- data/tracks/java/exercises/grade-school/src/test/java/SchoolTest.java +8 -2
- data/tracks/java/exercises/luhn/src/test/java/LuhnValidatorTest.java +20 -13
- data/tracks/java/exercises/robot-name/src/test/java/RobotTest.java +6 -1
- data/tracks/javascript/README.md +1 -1
- data/tracks/javascript/docs/TESTS.md +9 -1
- data/tracks/kotlin/exercises/luhn/src/example/kotlin/Luhn.kt +18 -26
- data/tracks/kotlin/exercises/luhn/src/test/kotlin/LuhnTest.kt +40 -38
- data/tracks/php/README.md +1 -1
- data/tracks/php/config.json +5 -0
- data/tracks/php/exercises/perfect-numbers/example.php +23 -0
- data/tracks/php/exercises/perfect-numbers/perfect-numbers_test.php +99 -0
- data/tracks/purescript/.travis.yml +1 -0
- data/tracks/purescript/bin/test.sh +33 -8
- data/tracks/purescript/config.json +7 -0
- data/tracks/purescript/exercises/meetup/bower.json +17 -0
- data/tracks/purescript/exercises/meetup/examples/src/Meetup.purs +37 -0
- data/tracks/purescript/exercises/meetup/src/Meetup.purs +11 -0
- data/tracks/purescript/exercises/meetup/test/Main.purs +395 -0
- data/tracks/python/README.md +7 -6
- data/tracks/python/docs/TOOLS.md +3 -3
- data/tracks/python/exercises/bracket-push/bracket_push_test.py +32 -15
- data/tracks/python/exercises/hamming/hamming_test.py +2 -0
- data/tracks/python/exercises/luhn/luhn_test.py +2 -0
- data/tracks/python/test/check-exercises.py +7 -1
- metadata +56 -20
- data/tracks/csharp/exercises/atbash-cipher/AtbashTest.cs +0 -17
- data/tracks/csharp/generators/BooleanTestMethod.cs +0 -36
- data/tracks/csharp/generators/TestMethodNameTransformer.cs +0 -11
- data/tracks/csharp/generators/TestedClassNameTransformer.cs +0 -11
- data/tracks/java/exercises/allergies/src/main/java/.keep +0 -0
@@ -0,0 +1,99 @@
|
|
1
|
+
if !System.get_env("EXERCISM_TEST_EXAMPLES") do
|
2
|
+
Code.load_file("diffie_hellman.exs", __DIR__)
|
3
|
+
end
|
4
|
+
|
5
|
+
ExUnit.start
|
6
|
+
ExUnit.configure exclude: :pending, trace: true
|
7
|
+
|
8
|
+
defmodule DiffieHellmanTest do
|
9
|
+
use ExUnit.Case
|
10
|
+
|
11
|
+
#@tag :pending
|
12
|
+
test "private key should be between 1 and P-1, inclusive" do
|
13
|
+
prime_p = 23
|
14
|
+
|
15
|
+
assert DiffieHellman.generate_private_key(prime_p) in Range.new(1, prime_p-1)
|
16
|
+
end
|
17
|
+
|
18
|
+
@tag :pending
|
19
|
+
test "private key generator should support very large primes" do
|
20
|
+
prime_p = 120227323036150778550155526710966921740030662694578947298423549235265759593711587341037426347114541533006628856300552706996143592240453345642869233562886752930249953227657883929905072620233073626594386072962776144691433658814261874113232461749035425712805067202910389407991986070558964461330091797026762932543
|
21
|
+
|
22
|
+
assert DiffieHellman.generate_private_key(prime_p) in Range.new(1, prime_p-1)
|
23
|
+
end
|
24
|
+
|
25
|
+
@tag :pending
|
26
|
+
test "private keys should be random" do
|
27
|
+
prime_p = 23
|
28
|
+
|
29
|
+
# Due to the nature of random generators, there's a small chance it could generate
|
30
|
+
# the same numbers over an over, so this may fail, but the RNG should be good enough
|
31
|
+
# that 100 generated keys between 1 and 22 ought to be at least half unique.
|
32
|
+
|
33
|
+
unique_key_count = Stream.repeatedly(fn -> DiffieHellman.generate_private_key(prime_p) end)
|
34
|
+
|> Enum.take(100)
|
35
|
+
|> Enum.uniq
|
36
|
+
|> length
|
37
|
+
min_expected_unique_keys = div(prime_p, 2)
|
38
|
+
|
39
|
+
assert unique_key_count > min_expected_unique_keys
|
40
|
+
end
|
41
|
+
|
42
|
+
@tag :pending
|
43
|
+
test "public key correctly calculated from two primes and private key" do
|
44
|
+
prime_p = 23
|
45
|
+
prime_g = 5
|
46
|
+
private_key = 6
|
47
|
+
expected_public_key = 8
|
48
|
+
|
49
|
+
assert DiffieHellman.generate_public_key(prime_p, prime_g, private_key) == expected_public_key
|
50
|
+
end
|
51
|
+
|
52
|
+
@tag :pending
|
53
|
+
test "public key generator should support very large primes" do
|
54
|
+
prime_p = 120227323036150778550155526710966921740030662694578947298423549235265759593711587341037426347114541533006628856300552706996143592240453345642869233562886752930249953227657883929905072620233073626594386072962776144691433658814261874113232461749035425712805067202910389407991986070558964461330091797026762932543
|
55
|
+
prime_g = 75205441154357919442925546169208711235485855904969178206313309299205868312399046149367516336607966149689640419216591714331722664409474612463910928128055994157922930443733535659848264364106037925315974095321112757711756912144137705613776063541350548911512715512539186192176020596861210448363099541947258202188
|
56
|
+
private_key = 8675309
|
57
|
+
expected_public_key = 81945102766205597052444239927191366879878802281637258134656723311532689587789695879960502348293388789700383121890410484395608064685866057972603193444399431765316092443741213175747052166212523610645396217140238838864033970876203333493173215068467082830013531737232331628864212666452277691016389511356912249174
|
58
|
+
|
59
|
+
assert DiffieHellman.generate_public_key(prime_p, prime_g, private_key) == expected_public_key
|
60
|
+
end
|
61
|
+
|
62
|
+
@tag :pending
|
63
|
+
test "shared secret key correctly calculated from initial prime, Bob's public key, and Alice's private key" do
|
64
|
+
prime_p = 23
|
65
|
+
bob_public_key = 19
|
66
|
+
alice_private_key = 6
|
67
|
+
expected_shared_secret = 2
|
68
|
+
|
69
|
+
assert DiffieHellman.generate_shared_secret(prime_p, bob_public_key, alice_private_key) == expected_shared_secret
|
70
|
+
end
|
71
|
+
|
72
|
+
@tag :pending
|
73
|
+
test "shared secret correctly calculated when using large primes" do
|
74
|
+
prime_p = 120227323036150778550155526710966921740030662694578947298423549235265759593711587341037426347114541533006628856300552706996143592240453345642869233562886752930249953227657883929905072620233073626594386072962776144691433658814261874113232461749035425712805067202910389407991986070558964461330091797026762932543
|
75
|
+
bob_public_key = 75205441154357919442925546169208711235485855904969178206313309299205868312399046149367516336607966149689640419216591714331722664409474612463910928128055994157922930443733535659848264364106037925315974095321112757711756912144137705613776063541350548911512715512539186192176020596861210448363099541947258202188
|
76
|
+
alice_private_key = 2483479393625932939911081304356888505153797135447327501792696199190469015215177630758617902200417377685436170904594686456961202706692908603181062371925882
|
77
|
+
expected_shared_secret = 70900735223964890815905879227737819348808518698920446491346508980461201746567735331455825644429877946556431095820785835497384849778344216981228226252639932672153547963980483673419756271345828771971984887453014488572245819864454136618980914729839523581263886740821363010486083940557620831348661126601106717071
|
78
|
+
|
79
|
+
assert DiffieHellman.generate_shared_secret(prime_p, bob_public_key, alice_private_key) == expected_shared_secret
|
80
|
+
end
|
81
|
+
|
82
|
+
@tag :pending
|
83
|
+
test "exchanging public keys between Alice and Bob should calculate the same shared secret" do
|
84
|
+
prime_p = 23
|
85
|
+
prime_g = 5
|
86
|
+
|
87
|
+
alice_private_key = DiffieHellman.generate_private_key(prime_p)
|
88
|
+
bob_private_key = DiffieHellman.generate_private_key(prime_p)
|
89
|
+
|
90
|
+
alice_public_key = DiffieHellman.generate_public_key(prime_p, prime_g, alice_private_key)
|
91
|
+
bob_public_key = DiffieHellman.generate_public_key(prime_p, prime_g, bob_private_key)
|
92
|
+
|
93
|
+
alice_shared_secret = DiffieHellman.generate_shared_secret(prime_p, bob_public_key, alice_private_key)
|
94
|
+
bob_shared_secret = DiffieHellman.generate_shared_secret(prime_p, alice_public_key, bob_private_key)
|
95
|
+
|
96
|
+
assert alice_shared_secret == bob_shared_secret
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
defmodule DiffieHellman do
|
2
|
+
@moduledoc """
|
3
|
+
Diffie-Hellman is a method of securely exchanging keys in a public-key
|
4
|
+
cryptosystem. Two users, Alice and Bob, want to share a secret between
|
5
|
+
themselves, while ensuring nobody else can read it.
|
6
|
+
|
7
|
+
Step 0: Alice and Bob agree on two prime numbers, P and G. An attacker, Eve,
|
8
|
+
can intercept these numbers, but without one of Alice or Bob's private keys,
|
9
|
+
we'll see Eve can't do anything useful with them.
|
10
|
+
|
11
|
+
Step 1: Alice and Bob each generate a private key between 1 and P-1.
|
12
|
+
P).
|
13
|
+
|
14
|
+
Step 2: Using the initial primes P and G, Alice and Bob calculate their
|
15
|
+
public keys by raising G to the power of their private key, then calculating
|
16
|
+
the modulus of that number by P. ((G**private_key) % P)
|
17
|
+
|
18
|
+
Step 3: Alice and Bob exchange public keys. Alice and Bob calculate a secret
|
19
|
+
shared key by raising the other's public key to the power of their private
|
20
|
+
key, then doing a modulus of the result by P. Due to the way modulus math
|
21
|
+
works, they should both generate the same shared key.
|
22
|
+
|
23
|
+
Alice calculates: (bob_public ** alice_private) % P
|
24
|
+
Bob calculates: (alice_public ** bob_private) % P
|
25
|
+
|
26
|
+
As long as their private keys are never lost or transmitted, only they know
|
27
|
+
their private keys, so even if Eve has P, G, and both public keys, she can't
|
28
|
+
do anything with them.
|
29
|
+
|
30
|
+
A video example is available at:
|
31
|
+
https://www.khanacademy.org/computing/computer-science/cryptography/modern-crypt/v/diffie-hellman-key-exchange-part-2
|
32
|
+
"""
|
33
|
+
|
34
|
+
@doc """
|
35
|
+
Given a prime integer `prime_p`, return a random integer between 1 and `prime_p` - 1
|
36
|
+
"""
|
37
|
+
@spec generate_private_key(prime_p :: integer) :: integer
|
38
|
+
def generate_private_key(prime_p) do
|
39
|
+
1 |> Range.new(prime_p - 1) |> Enum.random
|
40
|
+
end
|
41
|
+
|
42
|
+
@doc """
|
43
|
+
Given two prime integers as generators (`prime_p` and `prime_g`), and a private key,
|
44
|
+
generate a public key using the mathematical formula:
|
45
|
+
|
46
|
+
(prime_g ** private_key) % prime_p
|
47
|
+
"""
|
48
|
+
@spec generate_public_key(prime_p :: integer, prime_g :: integer, private_key :: integer) :: integer
|
49
|
+
def generate_public_key(prime_p, prime_g, private_key) do
|
50
|
+
:crypto.mod_pow(prime_g, private_key, prime_p) |> :binary.decode_unsigned
|
51
|
+
end
|
52
|
+
|
53
|
+
@doc """
|
54
|
+
Given a prime integer `prime_p`, user B's public key, and user A's private key,
|
55
|
+
generate a shared secret using the mathematical formula:
|
56
|
+
|
57
|
+
(public_key_b ** private_key_a) % prime_p
|
58
|
+
"""
|
59
|
+
@spec generate_shared_secret(prime_p :: integer, public_key_b :: integer, private_key_a :: integer) :: integer
|
60
|
+
def generate_shared_secret(prime_p, public_key_b, private_key_a) do
|
61
|
+
:crypto.mod_pow(public_key_b, private_key_a, prime_p) |> :binary.decode_unsigned
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
@@ -3,7 +3,7 @@ module POV (fromPOV, tracePathBetween) where
|
|
3
3
|
import Data.Tree (Tree)
|
4
4
|
|
5
5
|
fromPOV :: Eq a => a -> Tree a -> Maybe (Tree a)
|
6
|
-
fromPOV = error "You need to implement this function."
|
6
|
+
fromPOV x tree = error "You need to implement this function."
|
7
7
|
|
8
8
|
tracePathBetween :: Eq a => a -> a -> Tree a -> Maybe [a]
|
9
|
-
tracePathBetween = error "You need to implement this function."
|
9
|
+
tracePathBetween from to tree = error "You need to implement this function."
|
@@ -1,7 +1,10 @@
|
|
1
1
|
module Triplet (isPythagorean, mkTriplet, pythagoreanTriplets) where
|
2
2
|
|
3
|
-
isPythagorean
|
3
|
+
isPythagorean :: (Int, Int, Int) -> Bool
|
4
|
+
isPythagorean triplet = error "You need to implement this function."
|
4
5
|
|
5
|
-
mkTriplet
|
6
|
+
mkTriplet :: Int -> Int -> Int -> (Int, Int, Int)
|
7
|
+
mkTriplet a b c = error "You need to implement this function."
|
6
8
|
|
7
|
-
pythagoreanTriplets
|
9
|
+
pythagoreanTriplets :: Int -> Int -> [(Int, Int, Int)]
|
10
|
+
pythagoreanTriplets minFactor maxFactor = error "You need to implement this function."
|
@@ -4,4 +4,4 @@ boardString :: Maybe (Int, Int) -> Maybe (Int, Int) -> String
|
|
4
4
|
boardString white black = error "You need to implement this function."
|
5
5
|
|
6
6
|
canAttack :: (Int, Int) -> (Int, Int) -> Bool
|
7
|
-
canAttack = error "You need to implement this function."
|
7
|
+
canAttack queenA queenB = error "You need to implement this function."
|
@@ -6,7 +6,7 @@ mkRobot :: IO Robot
|
|
6
6
|
mkRobot = error "You need to implement this function."
|
7
7
|
|
8
8
|
resetName :: Robot -> IO ()
|
9
|
-
resetName = error "You need to implement this function."
|
9
|
+
resetName robot = error "You need to implement this function."
|
10
10
|
|
11
11
|
robotName :: Robot -> IO String
|
12
|
-
robotName = error "You need to implement this function."
|
12
|
+
robotName robot = error "You need to implement this function."
|
@@ -17,19 +17,19 @@ data Bearing = North
|
|
17
17
|
data Robot = Dummy
|
18
18
|
|
19
19
|
bearing :: Robot -> Bearing
|
20
|
-
bearing = error "You need to implement this function."
|
20
|
+
bearing robot = error "You need to implement this function."
|
21
21
|
|
22
22
|
coordinates :: Robot -> (Integer, Integer)
|
23
|
-
coordinates = error "You need to implement this function."
|
23
|
+
coordinates robot = error "You need to implement this function."
|
24
24
|
|
25
25
|
mkRobot :: Bearing -> (Integer, Integer) -> Robot
|
26
|
-
mkRobot = error "You need to implement this function."
|
26
|
+
mkRobot direction coordinates = error "You need to implement this function."
|
27
27
|
|
28
28
|
simulate :: Robot -> String -> Robot
|
29
|
-
simulate = error "You need to implement this function."
|
29
|
+
simulate robot instructions = error "You need to implement this function."
|
30
30
|
|
31
31
|
turnLeft :: Bearing -> Bearing
|
32
|
-
turnLeft = error "You need to implement this function."
|
32
|
+
turnLeft direction = error "You need to implement this function."
|
33
33
|
|
34
34
|
turnRight :: Bearing -> Bearing
|
35
|
-
turnRight = error "You need to implement this function."
|
35
|
+
turnRight direction = error "You need to implement this function."
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module RunLength (decode, encode) where
|
2
2
|
|
3
3
|
decode :: String -> String
|
4
|
-
decode = error "You need to implement this function."
|
4
|
+
decode encodedText = error "You need to implement this function."
|
5
5
|
|
6
6
|
encode :: String -> String
|
7
|
-
encode = error "You need to implement this function."
|
7
|
+
encode text = error "You need to implement this function."
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module Scrabble (scoreLetter, scoreWord) where
|
2
2
|
|
3
|
-
scoreLetter
|
3
|
+
scoreLetter :: Char -> Integer
|
4
|
+
scoreLetter letter = error "You need to implement this function."
|
4
5
|
|
5
|
-
scoreWord
|
6
|
+
scoreWord :: String -> Integer
|
7
|
+
scoreWord word = error "You need to implement this function."
|
@@ -2,7 +2,17 @@ import java.util.regex.Matcher;
|
|
2
2
|
import java.util.regex.Pattern;
|
3
3
|
|
4
4
|
public class Acronym {
|
5
|
-
|
5
|
+
private final String acronym;
|
6
|
+
|
7
|
+
public Acronym(String phrase) {
|
8
|
+
acronym = generateAcronym(phrase);
|
9
|
+
}
|
10
|
+
|
11
|
+
public String get() {
|
12
|
+
return acronym;
|
13
|
+
}
|
14
|
+
|
15
|
+
private String generateAcronym(String phrase){
|
6
16
|
final Pattern BREAK_WORDS = Pattern.compile("[A-Z]+[a-z]*|[a-z]+");
|
7
17
|
final Matcher matcher = BREAK_WORDS.matcher(phrase);
|
8
18
|
final StringBuilder b = new StringBuilder();
|
@@ -5,12 +5,11 @@ import static org.junit.Assert.assertEquals;
|
|
5
5
|
|
6
6
|
public class AcronymTest {
|
7
7
|
|
8
|
-
|
9
8
|
@Test
|
10
9
|
public void fromTitleCasedPhrases() {
|
11
10
|
final String phrase = "Portable Network Graphics";
|
12
11
|
final String expected = "PNG";
|
13
|
-
assertEquals(expected, Acronym
|
12
|
+
assertEquals(expected, new Acronym(phrase).get());
|
14
13
|
}
|
15
14
|
|
16
15
|
@Ignore
|
@@ -18,7 +17,7 @@ public class AcronymTest {
|
|
18
17
|
public void fromOtherTitleCasedPhrases() {
|
19
18
|
final String phrase = "Ruby on Rails";
|
20
19
|
final String expected = "ROR";
|
21
|
-
assertEquals(expected, Acronym
|
20
|
+
assertEquals(expected, new Acronym(phrase).get());
|
22
21
|
}
|
23
22
|
|
24
23
|
@Ignore
|
@@ -26,7 +25,7 @@ public class AcronymTest {
|
|
26
25
|
public void fromInconsistentlyCasedPhrases() {
|
27
26
|
final String phrase = "HyperText Markup Language";
|
28
27
|
final String expected = "HTML";
|
29
|
-
assertEquals(expected, Acronym
|
28
|
+
assertEquals(expected, new Acronym(phrase).get());
|
30
29
|
}
|
31
30
|
|
32
31
|
@Ignore
|
@@ -34,7 +33,7 @@ public class AcronymTest {
|
|
34
33
|
public void fromPhrasesWithPunctuation() {
|
35
34
|
final String phrase = "First In, First Out";
|
36
35
|
final String expected = "FIFO";
|
37
|
-
assertEquals(expected, Acronym
|
36
|
+
assertEquals(expected, new Acronym(phrase).get());
|
38
37
|
}
|
39
38
|
|
40
39
|
@Ignore
|
@@ -42,7 +41,7 @@ public class AcronymTest {
|
|
42
41
|
public void fromOtherPhrasesWithPunctuation() {
|
43
42
|
final String phrase = "PHP: Hypertext Preprocessor";
|
44
43
|
final String expected = "PHP";
|
45
|
-
assertEquals(expected, Acronym
|
44
|
+
assertEquals(expected, new Acronym(phrase).get());
|
46
45
|
}
|
47
46
|
|
48
47
|
@Ignore
|
@@ -50,7 +49,7 @@ public class AcronymTest {
|
|
50
49
|
public void fromPhrasesWithNonAcronymAllCapsWord() {
|
51
50
|
final String phrase = "GNU Image Manipulation Program";
|
52
51
|
final String expected = "GIMP";
|
53
|
-
assertEquals(expected, Acronym
|
52
|
+
assertEquals(expected, new Acronym(phrase).get());
|
54
53
|
}
|
55
54
|
|
56
55
|
@Ignore
|
@@ -58,7 +57,7 @@ public class AcronymTest {
|
|
58
57
|
public void fromPhrasesWithPunctuationAndSentenceCasing() {
|
59
58
|
final String phrase = "Complementary metal-oxide semiconductor";
|
60
59
|
final String expected = "CMOS";
|
61
|
-
assertEquals(expected, Acronym
|
60
|
+
assertEquals(expected, new Acronym(phrase).get());
|
62
61
|
}
|
63
62
|
|
64
63
|
@Ignore
|
@@ -66,7 +65,7 @@ public class AcronymTest {
|
|
66
65
|
public void fromPhraseWithSingleLetterWord() {
|
67
66
|
final String phrase = "Cat in a Hat";
|
68
67
|
final String expected = "CIAH";
|
69
|
-
assertEquals(expected, Acronym
|
68
|
+
assertEquals(expected, new Acronym(phrase).get());
|
70
69
|
}
|
71
70
|
|
72
71
|
}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import org.junit.Before;
|
1
2
|
import org.junit.Ignore;
|
2
3
|
import org.junit.Test;
|
3
4
|
|
@@ -15,7 +16,12 @@ import static org.junit.Assert.assertTrue;
|
|
15
16
|
import static org.junit.Assert.assertEquals;
|
16
17
|
|
17
18
|
public class SchoolTest {
|
18
|
-
private
|
19
|
+
private School school;
|
20
|
+
|
21
|
+
@Before
|
22
|
+
public void setUp() {
|
23
|
+
school = new School();
|
24
|
+
}
|
19
25
|
|
20
26
|
@Test
|
21
27
|
public void startsWithNoStudents() {
|
@@ -120,7 +126,7 @@ public class SchoolTest {
|
|
120
126
|
// Such as UnsupportedOperationException when an unmodifiableMap is used
|
121
127
|
}
|
122
128
|
|
123
|
-
assertThat(school.studentsByGradeAlphabetical().get(grade),
|
129
|
+
assertThat(school.studentsByGradeAlphabetical().get(grade),
|
124
130
|
not(hasItem(studentWhichShouldNotBeAdded)));
|
125
131
|
}
|
126
132
|
}
|
@@ -1,86 +1,93 @@
|
|
1
1
|
import org.junit.Ignore;
|
2
|
+
import org.junit.Before;
|
2
3
|
import org.junit.Test;
|
3
4
|
|
4
5
|
import static org.junit.Assert.assertFalse;
|
5
6
|
import static org.junit.Assert.assertTrue;
|
6
7
|
|
7
8
|
public class LuhnValidatorTest {
|
9
|
+
private LuhnValidator luhnValidator;
|
10
|
+
|
11
|
+
@Before
|
12
|
+
public void setUp() {
|
13
|
+
luhnValidator = new LuhnValidator();
|
14
|
+
}
|
8
15
|
|
9
16
|
@Test
|
10
17
|
public void testThatSingleDigitStringIsNotValid() {
|
11
|
-
assertFalse(
|
18
|
+
assertFalse(luhnValidator.isValid("1"));
|
12
19
|
}
|
13
20
|
|
14
21
|
@Ignore
|
15
22
|
@Test
|
16
23
|
public void testThatTheStringConsistingOfASingleZeroIsInvalid() {
|
17
|
-
assertFalse(
|
24
|
+
assertFalse(luhnValidator.isValid("0"));
|
18
25
|
}
|
19
26
|
|
20
27
|
@Ignore
|
21
28
|
@Test
|
22
29
|
public void testThatASimpleValidNumberIsIdentifiedAsValid() {
|
23
|
-
assertTrue(
|
30
|
+
assertTrue(luhnValidator.isValid(" 5 9 "));
|
24
31
|
}
|
25
32
|
|
26
33
|
@Ignore
|
27
34
|
@Test
|
28
35
|
public void testThatAValidCanadianSocialInsuranceNumberIsIdentifiedAsValidV1() {
|
29
|
-
assertTrue(
|
36
|
+
assertTrue(luhnValidator.isValid("046 454 286"));
|
30
37
|
}
|
31
38
|
|
32
39
|
@Ignore
|
33
40
|
@Test
|
34
41
|
public void testThatAValidCanadianSocialInsuranceNumberIsIdentifiedAsValidV2() {
|
35
|
-
assertTrue(
|
42
|
+
assertTrue(luhnValidator.isValid("055 444 285"));
|
36
43
|
}
|
37
44
|
|
38
45
|
@Ignore
|
39
46
|
@Test
|
40
47
|
public void testThatAnInvalidCanadianSocialInsuranceNumberIsIdentifiedAsInvalid() {
|
41
|
-
assertFalse(
|
48
|
+
assertFalse(luhnValidator.isValid("046 454 287"));
|
42
49
|
}
|
43
50
|
|
44
51
|
@Ignore
|
45
52
|
@Test
|
46
53
|
public void testThatAnInvalidCreditCardIsIdentifiedAsInvalid() {
|
47
|
-
assertFalse(
|
54
|
+
assertFalse(luhnValidator.isValid("8273 1232 7352 0569"));
|
48
55
|
}
|
49
56
|
|
50
57
|
@Ignore
|
51
58
|
@Test
|
52
59
|
public void testThatAddingANonDigitCharacterToAValidStringInvalidatesTheString() {
|
53
|
-
assertFalse(
|
60
|
+
assertFalse(luhnValidator.isValid("046a 454 286"));
|
54
61
|
}
|
55
62
|
|
56
63
|
@Ignore
|
57
64
|
@Test
|
58
65
|
public void testThatStringContainingPunctuationIsInvalid() {
|
59
|
-
assertFalse(
|
66
|
+
assertFalse(luhnValidator.isValid("055-444-285"));
|
60
67
|
}
|
61
68
|
|
62
69
|
@Ignore
|
63
70
|
@Test
|
64
71
|
public void testThatStringContainingSymbolsIsInvalid() {
|
65
|
-
assertFalse(
|
72
|
+
assertFalse(luhnValidator.isValid("055£ 444$ 285"));
|
66
73
|
}
|
67
74
|
|
68
75
|
@Ignore
|
69
76
|
@Test
|
70
77
|
public void testThatTheStringConsistingOfASpaceAndASingleZeroIsInvalid() {
|
71
|
-
assertFalse(
|
78
|
+
assertFalse(luhnValidator.isValid(" 0"));
|
72
79
|
}
|
73
80
|
|
74
81
|
@Ignore
|
75
82
|
@Test
|
76
83
|
public void testThatStringContainingMultipleZerosIsValid() {
|
77
|
-
assertTrue(
|
84
|
+
assertTrue(luhnValidator.isValid(" 00000"));
|
78
85
|
}
|
79
86
|
|
80
87
|
@Ignore
|
81
88
|
@Test
|
82
89
|
public void testThatDoublingNineIsHandledCorrectly() {
|
83
|
-
assertTrue(
|
90
|
+
assertTrue(luhnValidator.isValid("091"));
|
84
91
|
}
|
85
92
|
|
86
93
|
}
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import org.junit.Test;
|
2
2
|
import org.junit.Ignore;
|
3
|
+
import org.junit.Before;
|
3
4
|
|
4
5
|
import static org.hamcrest.CoreMatchers.equalTo;
|
5
6
|
import static org.hamcrest.core.Is.is;
|
@@ -9,8 +10,12 @@ import static org.junit.Assert.assertThat;
|
|
9
10
|
public class RobotTest {
|
10
11
|
|
11
12
|
private static final String EXPECTED_ROBOT_NAME_PATTERN = "[A-Z]{2}\\d{3}";
|
12
|
-
private
|
13
|
+
private Robot robot;
|
13
14
|
|
15
|
+
@Before
|
16
|
+
public void setUp() {
|
17
|
+
robot = new Robot();
|
18
|
+
}
|
14
19
|
|
15
20
|
@Test
|
16
21
|
public void hasName() {
|
data/tracks/javascript/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# xJavaScript [![Build Status](https://travis-ci.org/exercism/xjavascript.
|
1
|
+
# xJavaScript [![Build Status](https://travis-ci.org/exercism/xjavascript.svg?branch=master)](https://travis-ci.org/exercism/xjavascript)
|
2
2
|
|
3
3
|
Exercism exercises in JavaScript
|
4
4
|
|
@@ -1,4 +1,12 @@
|
|
1
|
-
After configuring `exercism` command-line client
|
1
|
+
After configuring `exercism` command-line client you can fetch the very next exercise
|
2
|
+
|
3
|
+
exercism fetch javascript
|
4
|
+
|
5
|
+
or you can fetch a specific exercise, passing the exercise name after the language. For example, to fetch the `bob` exercise:
|
6
|
+
|
7
|
+
exercism fetch javascript bob
|
8
|
+
|
9
|
+
Now, it's time to run some tests. Move to the folder where that exercise's files are located (a path similar to `<EXERCISM_HOME_DIR>/<TRACK_ID>/<EXERCISE>`) and run the tests with the `jasmine-node` command you should have installed on the *Installing JavaScript* step:
|
2
10
|
|
3
11
|
cd ~/exercism/javascript/bob
|
4
12
|
jasmine-node bob_test.spec.js
|
@@ -1,37 +1,29 @@
|
|
1
|
-
|
1
|
+
object Luhn {
|
2
2
|
|
3
|
-
|
3
|
+
fun isValid(candidate: String): Boolean =
|
4
|
+
isValidCandidate(candidate) && checksum(number(candidate)) == 0
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
}
|
6
|
+
private fun isValidCandidate(candidate: String): Boolean =
|
7
|
+
candidate.filter(Char::isDigit).length > 1 &&
|
8
|
+
candidate.all { it.isDigit() || Character.isSpaceChar(it) }
|
9
9
|
|
10
|
-
|
10
|
+
private fun number(candidate: String) = candidate.filter(Char::isDigit).toLong()
|
11
11
|
|
12
|
-
|
12
|
+
private fun checksum(number: Long) = addends(number).sum() % 10
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
val luhn = Luhn(zeroCheckDigitNumber)
|
14
|
+
private fun addends(number: Long): List<Int> = digits(number).withIndex().reversed()
|
15
|
+
.map { if (isOdd(it.index)) dbl(it.value) else it.value }
|
17
16
|
|
18
|
-
|
17
|
+
private fun digits(n: Long): List<Int> = when (n) {
|
18
|
+
0L -> emptyList()
|
19
|
+
else -> listOf((n % 10).toInt()) + digits(n / 10)
|
19
20
|
}
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
private fun digits(n: Long): List<Int> = when (n) {
|
25
|
-
0L -> emptyList()
|
26
|
-
else -> listOf(checkDigit(n)) + digits(n / 10)
|
27
|
-
}
|
28
|
-
|
29
|
-
private fun dbl(n: Int): Int {
|
30
|
-
val dbled = n * 2
|
31
|
-
return if (dbled > 10) dbled - 9 else dbled
|
32
|
-
}
|
33
|
-
|
34
|
-
private fun isOdd(i: Int) = i % 2 == 1
|
22
|
+
private fun dbl(n: Int): Int {
|
23
|
+
val dbled = n * 2
|
24
|
+
return if (dbled > 9) dbled - 9 else dbled
|
35
25
|
}
|
36
26
|
|
27
|
+
private fun isOdd(i: Int) = i % 2 == 1
|
28
|
+
|
37
29
|
}
|