From 70c2852af9cbe64807ec06c5788c4700873cba37 Mon Sep 17 00:00:00 2001 From: Kah Goh Date: Fri, 23 Feb 2024 01:02:01 +0800 Subject: [PATCH] Sync Luhn with problem specifications (#199) --- exercises/practice/luhn/.meta/config.json | 3 +- exercises/practice/luhn/.meta/example.lfe | 48 +++++++------- exercises/practice/luhn/.meta/tests.toml | 9 +++ exercises/practice/luhn/src/luhn.app.src | 2 +- exercises/practice/luhn/src/luhn.lfe | 5 ++ exercises/practice/luhn/test/luhn-tests.lfe | 72 ++++++++++++++++++--- 6 files changed, 105 insertions(+), 34 deletions(-) diff --git a/exercises/practice/luhn/.meta/config.json b/exercises/practice/luhn/.meta/config.json index c321e682..c5c28cf4 100644 --- a/exercises/practice/luhn/.meta/config.json +++ b/exercises/practice/luhn/.meta/config.json @@ -5,7 +5,8 @@ "contributors": [ "adolfopa", "etrepum", - "yurrriq" + "yurrriq", + "kahgoh" ], "files": { "solution": [ diff --git a/exercises/practice/luhn/.meta/example.lfe b/exercises/practice/luhn/.meta/example.lfe index e0d9c4a8..cebe2498 100644 --- a/exercises/practice/luhn/.meta/example.lfe +++ b/exercises/practice/luhn/.meta/example.lfe @@ -1,28 +1,30 @@ (defmodule luhn - (export (valid? 1) - (create 1) - (checksum 1))) + (export (valid? 1)) +) -(defun valid? (number) (== (rem (checksum number) 10) 0)) +(defun valid? (number) + (case (checksum (lists:reverse number) 0 0) + ((tuple 'ok count total) (when (> count 1)) (== (rem total 10) 0)) + (_ 'false) + ) +) -(defun create (number) - (lists:flatten `(,number ,(- #\: (rem (checksum (++ number "0")) 10))))) +(defun checksum + (('() count total) (tuple 'ok count total)) + (((cons 32 reversed-number) count total) (checksum reversed-number count total)) + (((cons h reversed-number) count total) + (when (=< #\0 h) (=< h #\9)) + (checksum reversed-number + (+ count 1) + (+ total (number-to-add count (- h #\0))) + ) + ) + ((_ count total) (tuple 'invalid count total)) +) -(defun checksum (number) - (checksum - (lists:reverse - (lists:filter - (lambda (c) - (=< #\0 c #\9)) - number)) - 'odd - 0)) +(defun number-to-add + ((count digit) (when (== (rem count 2) 0)) digit) + ((_ digit) (when (< digit 5)) (* digit 2)) + ((_ digit) (- (* digit 2) 9)) +) -(defun checksum - ([() _ total] total) - ([(cons h reversed-number) 'odd total] - (checksum reversed-number 'even (- (+ total h) #\0))) - ([(cons h reversed-number) 'even total] (when (< h #\5)) - (checksum reversed-number 'odd (+ total (* (- h #\0) 2)))) - ([(cons h reversed-number) 'even total] (when (>= h #\5)) - (checksum reversed-number 'odd (- (+ total (* (- h #\0) 2)) 9)))) diff --git a/exercises/practice/luhn/.meta/tests.toml b/exercises/practice/luhn/.meta/tests.toml index 06c28800..c0be0c4d 100644 --- a/exercises/practice/luhn/.meta/tests.toml +++ b/exercises/practice/luhn/.meta/tests.toml @@ -33,6 +33,9 @@ description = "invalid credit card" [20e67fad-2121-43ed-99a8-14b5b856adb9] description = "invalid long number with an even remainder" +[7e7c9fc1-d994-457c-811e-d390d52fba5e] +description = "invalid long number with a remainder divisible by 5" + [ad2a0c5f-84ed-4e5b-95da-6011d6f4f0aa] description = "valid number with an even number of digits" @@ -57,6 +60,12 @@ description = "more than a single zero is valid" [ab56fa80-5de8-4735-8a4a-14dae588663e] description = "input digit 9 is correctly converted to output digit 9" +[b9887ee8-8337-46c5-bc45-3bcab51bc36f] +description = "very long input is valid" + +[8a7c0e24-85ea-4154-9cf1-c2db90eabc08] +description = "valid luhn with an odd number of digits and non zero first digit" + [39a06a5a-5bad-4e0f-b215-b042d46209b1] description = "using ascii value for non-doubled non-digit isn't allowed" diff --git a/exercises/practice/luhn/src/luhn.app.src b/exercises/practice/luhn/src/luhn.app.src index c84c6578..063d9e5f 100644 --- a/exercises/practice/luhn/src/luhn.app.src +++ b/exercises/practice/luhn/src/luhn.app.src @@ -1,6 +1,6 @@ %% -*- erlang -*- {application, 'luhn', - [{description, ""}, + [{description, "Given a number determine whether or not it is valid per the Luhn formula."}, {vsn, "0.0.1"}, {modules, ['luhn']}, diff --git a/exercises/practice/luhn/src/luhn.lfe b/exercises/practice/luhn/src/luhn.lfe index e69de29b..512e06ee 100644 --- a/exercises/practice/luhn/src/luhn.lfe +++ b/exercises/practice/luhn/src/luhn.lfe @@ -0,0 +1,5 @@ +(defmodule luhn + (export (valid? 1)) +) + +; Please implement the `valid?` function. diff --git a/exercises/practice/luhn/test/luhn-tests.lfe b/exercises/practice/luhn/test/luhn-tests.lfe index 03ba505e..331e25d2 100644 --- a/exercises/practice/luhn/test/luhn-tests.lfe +++ b/exercises/practice/luhn/test/luhn-tests.lfe @@ -4,14 +4,68 @@ (include-lib "ltest/include/ltest-macros.lfe") -(deftest invalid - (is-not (luhn:valid? "1111")) - (is-not (luhn:valid? "738"))) +(deftest single-digit-strings-can-not-be-valid + (is-not (luhn:valid? "1"))) -(deftest valid - (is (luhn:valid? "8739567")) - (is (luhn:valid? "8763")) - (is (luhn:valid? "2323 2005 7766 3554"))) +(deftest a-single-zero-is-invalid + (is-not (luhn:valid? "0"))) -(deftest create - (is-equal "2323 2005 7766 3554" (luhn:create "2323 2005 7766 355"))) +(deftest a-simple-valid-SIN-that-remains-valid-reversed + (is (luhn:valid? "059"))) + +(deftest a-simple-valid-SIN-that-becomes-invalid-if-reversed + (is (luhn:valid? "59"))) + +(deftest a-valid-Canadian-SIN + (is (luhn:valid? "055 444 285"))) + +(deftest invalid-Canadian-SIN + (is-not (luhn:valid? "055 444 286"))) + +(deftest invalid-credit-card + (is-not (luhn:valid? "8273 1232 7352 0569"))) + +(deftest invalid-long-number-with-an-even-remainder + (is-not (luhn:valid? "1 2345 6789 1234 5678 9012"))) + +(deftest invalid-long-with-a-remainder-divisible-by-5 + (is-not (luhn:valid? "1 2345 6789 1234 5678 9013"))) + +(deftest valid-number-with-an-even-number-of-digits + (is (luhn:valid? "095 245 88"))) + +(deftest valid-number-with-an-odd-number-of-spaces + (is (luhn:valid? "234 567 891 234"))) + +(deftest valid-strings-with-a-non-digit-added-at-the-end-become-invalid + (is-not (luhn:valid? "059a"))) + +(deftest valid-strings-with-punctuation-included-become-invalid + (is-not (luhn:valid? "055-444-285"))) + +(deftest valid-strings-with-symbols-included-become-invalid + (is-not (luhn:valid? "055# 444$ 285"))) + +(deftest single-zero-with-space-is-invalid + (is-not (luhn:valid? " 0"))) + +(deftest more-than-a-single-zero-is-valid + (is (luhn:valid? "0000 0"))) + +(deftest input-digit-9-is-correctly-converted-to-output-digit-9 + (is (luhn:valid? "091"))) + +(deftest very-long-input-is-valid + (is (luhn:valid? "9999999999 9999999999 9999999999 9999999999"))) + +(deftest valid-luhn-with-an-odd-number-of-digits-and-non-zero-first-digit + (is (luhn:valid? "109"))) + +(deftest using-ascii-value-for-non-doubled-non-digit-isnt-allowed + (is-not (luhn:valid? "055b 444 285"))) + +(deftest using-ascii-value-for-doubled-non-digit-isnt-allowed + (is-not (luhn:valid? ":9"))) + +(deftest non-numeric-non-space-char-in-the-middle-with-a-sum-thats-divisible-by-10-isnt-allowed + (is-not (luhn:valid? "59%59")))