Skip to content

Commit 2886848

Browse files
authored
Implement Luhn (#247)
* Implement Luhn Closes #237 This follows the current test suite as of right now https://github.com/exercism/x-common/blob/41b9fe8e9c2513f4443e1cad1f286f53b2720ce9/exercises/luhn/canonical-data.json * Place Luhn before Largest Series Product I don't think my solution is that far from what people will do. The [existing crate](https://lunemec.github.io/rust-luhn/src/luhn2/src/lib.rs.html) uses another crate to handle digits > 10 after doubling. If people go down that path their solutions will vary a bit from mine, but not by a bunch. So the solution mostly requires a good handle on - Converting a string to digits - Working with iteration The conversion of a string to digits is also part of Largest Series Product, so we could put the exercise to right before LSP to reinforce that concept.
1 parent c0c6178 commit 2886848

File tree

5 files changed

+70
-0
lines changed

5 files changed

+70
-0
lines changed

config.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,15 @@
122122
"match"
123123
]
124124
},
125+
{
126+
"slug": "luhn",
127+
"difficulty": 1,
128+
"topics": [
129+
"str to digits",
130+
"iterators",
131+
"higher-order functions"
132+
]
133+
},
125134
{
126135
"slug": "largest-series-product",
127136
"difficulty": 1,

exercises/luhn/.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Generated by Cargo
2+
# will have compiled files and executables
3+
/target/
4+
5+
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
6+
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
7+
Cargo.lock

exercises/luhn/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[package]
2+
name = "luhn"
3+
version = "0.0.0"

exercises/luhn/example.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pub fn is_valid(candidate: &str) -> bool {
2+
if candidate.chars().any(|c| c.is_alphabetic()) || candidate.chars().count() == 1 {
3+
return false;
4+
}
5+
6+
candidate.chars()
7+
.filter_map(|c| c.to_digit(10))
8+
.rev()
9+
.enumerate()
10+
.map(|(index, digit)| if index % 2 == 0 { digit } else { digit * 2 })
11+
.map(|digit| if digit > 9 { digit - 9 } else { digit })
12+
.sum::<u32>() % 10 == 0
13+
}

exercises/luhn/tests/luhn.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
extern crate luhn;
2+
3+
use luhn::*;
4+
5+
#[test]
6+
fn single_digit_string_is_invalid() {
7+
assert!(!is_valid("1"));
8+
}
9+
10+
#[test]
11+
#[ignore]
12+
fn single_zero_string_is_invalid() {
13+
assert!(!is_valid("0"));
14+
}
15+
16+
#[test]
17+
#[ignore]
18+
fn valid_canadian_sin_is_valid() {
19+
assert!(is_valid("046 454 286"));
20+
}
21+
22+
#[test]
23+
#[ignore]
24+
fn invalid_canadian_sin_is_invalid() {
25+
assert!(!is_valid("046 454 287"));
26+
}
27+
28+
#[test]
29+
#[ignore]
30+
fn invalid_credit_card_is_invalid() {
31+
assert!(!is_valid("8273 1232 7352 0569"));
32+
}
33+
34+
#[test]
35+
#[ignore]
36+
fn strings_that_contain_non_digits_are_invalid() {
37+
assert!(!is_valid("046a 454 286"));
38+
}

0 commit comments

Comments
 (0)