Skip to content

Commit

Permalink
🎯 feat: luhn
Browse files Browse the repository at this point in the history
  • Loading branch information
LuCCoelho committed Oct 19, 2023
1 parent 3d39e28 commit 8e3e45e
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 0 deletions.
22 changes: 22 additions & 0 deletions dart/luhn/.exercism/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"authors": [
"amscotti"
],
"contributors": [
"kytrinyx"
],
"files": {
"solution": [
"lib/luhn.dart"
],
"test": [
"test/luhn_test.dart"
],
"example": [
".meta/lib/example.dart"
]
},
"blurb": "Given a number determine whether or not it is valid per the Luhn formula.",
"source": "The Luhn Algorithm on Wikipedia",
"source_url": "https://en.wikipedia.org/wiki/Luhn_algorithm"
}
1 change: 1 addition & 0 deletions dart/luhn/.exercism/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"track":"dart","exercise":"luhn","id":"bf2ce773c30246a69f3805d717697f50","url":"https://exercism.org/tracks/dart/exercises/luhn","handle":"LuCCoelho","is_requester":true,"auto_approve":false}
38 changes: 38 additions & 0 deletions dart/luhn/HELP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Help

## Running the tests

To run the tests:

```sh
$ dart test
```

## Submitting your solution

You can submit your solution using the `exercism submit lib/luhn.dart` command.
This command will upload your solution to the Exercism website and print the solution page's URL.

It's possible to submit an incomplete solution which allows you to:

- See how others have completed the exercise
- Request help from a mentor

## Need to get help?

If you'd like help solving the exercise, check the following pages:

- The [Dart track's documentation](https://exercism.org/docs/tracks/dart)
- The [Dart track's programming category on the forum](https://forum.exercism.org/c/programming/dart)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)

Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.

To get help if you're having trouble, you can use one of the following resources:

- [Dart API Documentation](https://api.dart.dev/)
- [Dart Gitter Chat](https://gitter.im/dart-lang/home)
- [Community Information](https://www.dart.dev/community)
- [/r/dartlang](https://www.reddit.com/r/dartlang) is the Dart subreddit.
- [StackOverflow](https://stackoverflow.com/questions/tagged/dart) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
83 changes: 83 additions & 0 deletions dart/luhn/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Luhn

Welcome to Luhn on Exercism's Dart Track.
If you need help running the tests or submitting your code, check out `HELP.md`.

## Instructions

Given a number determine whether or not it is valid per the Luhn formula.

The [Luhn algorithm][luhn] is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers and Canadian Social Insurance Numbers.

The task is to check if a given string is valid.

## Validating a Number

Strings of length 1 or less are not valid.
Spaces are allowed in the input, but they should be stripped before checking.
All other non-digit characters are disallowed.

### Example 1: valid credit card number

```text
4539 3195 0343 6467
```

The first step of the Luhn algorithm is to double every second digit, starting from the right.
We will be doubling

```text
4_3_ 3_9_ 0_4_ 6_6_
```

If doubling the number results in a number greater than 9 then subtract 9 from the product.
The results of our doubling:

```text
8569 6195 0383 3437
```

Then sum all of the digits:

```text
8+5+6+9+6+1+9+5+0+3+8+3+3+4+3+7 = 80
```

If the sum is evenly divisible by 10, then the number is valid.
This number is valid!

### Example 2: invalid credit card number

```text
8273 1232 7352 0569
```

Double the second digits, starting from the right

```text
7253 2262 5312 0539
```

Sum the digits

```text
7+2+5+3+2+2+6+2+5+3+1+2+0+5+3+9 = 57
```

57 is not evenly divisible by 10, so this number is not valid.

[luhn]: https://en.wikipedia.org/wiki/Luhn_algorithm

## Source

### Created by

- @amscotti

### Contributed to by

- @kytrinyx

### Based on

The Luhn Algorithm on Wikipedia - https://en.wikipedia.org/wiki/Luhn_algorithm
15 changes: 15 additions & 0 deletions dart/luhn/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
analyzer:
errors:
unused_element: error
unused_import: error
unused_local_variable: error
dead_code: error

linter:
rules:
# Error Rules
- avoid_relative_lib_imports
- avoid_types_as_parameter_names
- literal_only_boolean_expressions
- no_adjacent_strings_in_list
- valid_regexps
47 changes: 47 additions & 0 deletions dart/luhn/lib/luhn.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
class Luhn {
bool valid(String number) {
List<String> validCharacters = [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9'
];

number = number.replaceAll(' ', '');
int result = 0;
List<String> numberDigits = number.split('');

if (numberDigits.length < 2) {
return false;
}

for (int i = (numberDigits.length - 2); i > -1; i -= 2) {
if (validCharacters.contains(numberDigits[i])) {
int digit = int.parse(numberDigits[i]);
int digitDouble = digit * 2;
if (digitDouble > 9) {
digitDouble -= 9;
}
numberDigits[i] = digitDouble.toString();
} else {
return false;
}
}

for (int i = 0; i < numberDigits.length; i++) {
if (validCharacters.contains(numberDigits[i])) {
result += int.parse(numberDigits[i]);
} else {
return false;
}
}

return result % 10 == 0;
}
}
5 changes: 5 additions & 0 deletions dart/luhn/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: 'luhn'
environment:
sdk: '>=2.18.0 <3.0.0'
dev_dependencies:
test: '<2.0.0'
118 changes: 118 additions & 0 deletions dart/luhn/test/luhn_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import 'package:luhn/luhn.dart';
import 'package:test/test.dart';

void main() {
final luhn = Luhn();

group('Luhn', () {
test('single digit strings can not be valid', () {
final result = luhn.valid('1');
expect(result, equals(false));
}, skip: false);

test('a single zero is invalid', () {
final result = luhn.valid('0');
expect(result, equals(false));
}, skip: false);

test('a simple valid SIN that remains valid if reversed', () {
final result = luhn.valid('059');
expect(result, equals(true));
}, skip: false);

test('a simple valid SIN that becomes invalid if reversed', () {
final result = luhn.valid('59');
expect(result, equals(true));
}, skip: false);

test('a valid Canadian SIN', () {
final result = luhn.valid('055 444 285');
expect(result, equals(true));
}, skip: false);

test('invalid Canadian SIN', () {
final result = luhn.valid('055 444 286');
expect(result, equals(false));
}, skip: false);

test('invalid credit card', () {
final result = luhn.valid('8273 1232 7352 0569');
expect(result, equals(false));
}, skip: false);

test('invalid long number with an even remainder', () {
final result = luhn.valid('1 2345 6789 1234 5678 9012');
expect(result, equals(false));
}, skip: false);

test('invalid long number with a remainder divisible by 5', () {
final result = luhn.valid('1 2345 6789 1234 5678 9013');
expect(result, equals(false));
}, skip: false);

test('valid number with an even number of digits', () {
final result = luhn.valid('095 245 88');
expect(result, equals(true));
}, skip: false);

test('valid number with an odd number of spaces', () {
final result = luhn.valid('234 567 891 234');
expect(result, equals(true));
}, skip: false);

test('valid strings with a non-digit added at the end become invalid', () {
final result = luhn.valid('059a');
expect(result, equals(false));
}, skip: false);

test('valid strings with punctuation included become invalid', () {
final result = luhn.valid('055-444-285');
expect(result, equals(false));
}, skip: false);

test('valid strings with symbols included become invalid', () {
final result = luhn.valid('055# 444\$ 285');
expect(result, equals(false));
}, skip: false);

test('single zero with space is invalid', () {
final result = luhn.valid(' 0');
expect(result, equals(false));
}, skip: false);

test('more than a single zero is valid', () {
final result = luhn.valid('0000 0');
expect(result, equals(true));
}, skip: false);

test('input digit 9 is correctly converted to output digit 9', () {
final result = luhn.valid('091');
expect(result, equals(true));
}, skip: false);

test('very long input is valid', () {
final result = luhn.valid('9999999999 9999999999 9999999999 9999999999');
expect(result, equals(true));
}, skip: false);

test('valid luhn with an odd number of digits and non zero first digit', () {
final result = luhn.valid('109');
expect(result, equals(true));
}, skip: false);

test('using ascii value for non-doubled non-digit isn\'t allowed', () {
final result = luhn.valid('055b 444 285');
expect(result, equals(false));
}, skip: false);

test('using ascii value for doubled non-digit isn\'t allowed', () {
final result = luhn.valid(':9');
expect(result, equals(false));
}, skip: false);

test('non-numeric, non-space char in the middle with a sum that\'s divisible by 10 isn\'t allowed', () {
final result = luhn.valid('59%59');
expect(result, equals(false));
}, skip: false);
});
}

0 comments on commit 8e3e45e

Please sign in to comment.