diff --git a/exercises/luhn/example.R b/exercises/luhn/example.R index b0d063e5..c676b56e 100644 --- a/exercises/luhn/example.R +++ b/exercises/luhn/example.R @@ -1,35 +1,23 @@ -# Convert a number to a valid number, if it isn't already. -luhn <- function(input) { - if (is_valid(input)) { - return(input) - } - diff <- (10 - checksum(10*input)) %% 10 - return(10 * input + diff) -} - -# Get the check digit -check_digit <- function(input) { - as.numeric(substring(input,nchar(input))) -} - -# Compute the checksum -checksum <- function(input) { - sum(addends(input)) -} - # Determine whether the number is valid. is_valid <- function(input) { - checksum(input) %% 10 == 0 -} - -# addends returns the vector of numbers that follow the luhn algorithm -addends <- function(input) { - check <- check_digit(input) - v <- as.numeric(strsplit(as.character(input),"")[[1]]) - # counting from right double value of every second digit - start_seq <- ifelse(length(v) %% 2 == 1, 0, 1) - v2 <- replace(v,seq(start_seq,length(v),2),v[seq(start_seq,length(v),2)]*2) - v2 <- ifelse(v2 > 9, v2 - 9, v2) - replace_vals <- v2[seq(start_seq,length(v),2)] - replace(v,seq(start_seq,length(v),2),replace_vals) + + # Strip spaces, check length & check for invalid characters + input_vector <- strsplit(gsub(pattern = " ", replacement = "", input), "")[[1]] + if (length(input_vector) < 2 || any(grepl("[^[:digit:]]", input_vector))) { + return (FALSE) + } + + # Convert to numeric + num_vector <- as.numeric(input_vector) + + # Double every second digit starting from the right + num_vector <- rev(num_vector) + num_vector[seq(2,length(num_vector),2)] = num_vector[seq(2,length(num_vector),2)]*2 + + # Subtract 9 if > 9 (can apply to all since no digit can be greater than 9 before doubling) + num_vector <- ifelse(num_vector > 9, num_vector - 9, num_vector) + + # Check checksum is divisible by 10 + sum(num_vector) %% 10 == 0 + } diff --git a/exercises/luhn/luhn.R b/exercises/luhn/luhn.R index 3db9494f..fd2e1384 100644 --- a/exercises/luhn/luhn.R +++ b/exercises/luhn/luhn.R @@ -1,25 +1,4 @@ -# Convert a number to a valid number, if it isn't already. -luhn <- function() { - -} - -# Get the check digit -check_digit <- function() { - -} - -# Compute the checksum -checksum <- function() { - -} - # Determine whether the number is valid. -is_valid <- function() { +is_valid <- function(input) { } - - -# addends returns the vector of numbers that follow the luhn algorithm -addends <- function(input) { - -} \ No newline at end of file diff --git a/exercises/luhn/test_luhn.R b/exercises/luhn/test_luhn.R index 25906de3..e6a7614d 100644 --- a/exercises/luhn/test_luhn.R +++ b/exercises/luhn/test_luhn.R @@ -1,81 +1,69 @@ -source('./luhn.R') +source('./is_valid.R') suppressPackageStartupMessages({ require(testthat) }) -test_that("check digit", { - input <- 34567 - expect_equal(check_digit(input), - 7 - ) +test_that("single digit strings can not be valid", { + input <- "1" + expect_equal(is_valid(input), FALSE) }) -test_that("check digit with input ending in zero", { - input <- 91370 - expect_equal(check_digit(input), - 0 - ) +test_that("A single zero is invalid", { + input <- "0" + expect_equal(is_valid(input), FALSE) }) -test_that("check addends", { - input <- 12121 - expect_equal(addends(input), - c(1,4,1,4,1) - ) +test_that("simple valid sin", { + input <- " 5 9 " + expect_equal(is_valid(input), TRUE) }) -test_that("check too large addends", { - input <- 8631 - expect_equal(addends(input), - c(7,6,6,1) - ) +test_that("valid Canadian SIN", { + input <- "046 454 286" + expect_equal(is_valid(input), TRUE) }) -test_that("checksum", { - input <- 4913 - expect_equal(checksum(input), - 22 - ) +test_that("invalid Canadian SIN", { + input <- "046 454 287" + expect_equal(is_valid(input), FALSE) }) -test_that("checksum of larger number", { - input <- 201773 - expect_equal(checksum(input), - 21 - ) +test_that("invalid credit card", { + input <- "8273 1232 7352 0569" + expect_equal(is_valid(input), FALSE) }) -test_that("check invalid number", { - input <- 738 - expect_equal(is_valid(input), - FALSE - ) +test_that("valid strings with a non-digit added become invalid", { + input <- "046a 454 286" + expect_equal(is_valid(input), FALSE) }) -test_that("check valid number", { - input <- 8739567 - expect_equal(is_valid(input), - TRUE - ) +test_that("punctuation is not allowed", { + input <- "055-444-285" + expect_equal(is_valid(input), FALSE) }) -test_that("create valid number", { - input <- 123 - expect_equal(luhn(input), - 1230 - ) +test_that("symbols are not allowed", { + input <- "055£ 444$ 285" + expect_equal(is_valid(input), FALSE) }) -test_that("create larger valid number", { - input <- 873956 - expect_equal(luhn(input), - 8739567 - ) +test_that("single zero with space is invalid", { + input <- " 0" + expect_equal(is_valid(input), FALSE) }) -test_that("create even larger valid number", { - input <- 837263756 - expect_equal(luhn(input), - 8372637564 - ) +test_that("lots of zeros are valid", { + input <- " 00000" + expect_equal(is_valid(input), TRUE) +}) + +test_that("another valid sin", { + input <- "055 444 285" + expect_equal(is_valid(input), TRUE) +}) + +test_that("nine doubled is nine", { + input <- "091" + expect_equal(is_valid(input), TRUE) }) print("All tests passed!")