29
\$\begingroup\$

Introduction:

A Dutch BSN (BurgerServiceNummer) is valid when it complies to the following rules:

  • It only contains digits.
  • The length should be either 8 or 9 in length.
  • When the digits are indexed as A through I, the result of the following sum: 9xA + 8xB + 7xC + 6xD + 5xE + 4xF + 3xG + 2xH + -1xI (NOTE the -1 instead of 1!) should be divisible by 11, and should not be 0.

Challenge:

Input: A string or char-array representing the BSN.

Output: A truthy or falsey result whether the input is a valid BSN.

Challenge Rules:

  • The input format should be a string or char-array. You are not allowed to use an int-array of digits, or a (possibly octal) number. (You are allowed to convert it to an int-array of digits yourself, though, but not directly as argument.)
  • Despite the restriction on the input above, you can assume all test cases will contain one or more digits ([0-9]+)
  • Regarding the BSN with length 8 instead of 9, the Dutch Wikipedia states the following: "For the eleven-test and for other practical uses, a leading zero is added to make the number of length 9." (source)

General rules:

  • This is , so shortest answer in bytes wins.
    Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
  • Standard rules apply for your answer, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters, full programs. Your call.
  • Default Loopholes are forbidden.
  • If possible, please add a link with a test for your code.
  • Also, please add an explanation if necessary.

Test cases:

// Truthy test cases:
111222333
123456782
232262536
010464554
10464554
44016773

// Falsey test cases:
000000000
192837465
247594057
88888888
73
3112223342
000000012
\$\endgroup\$
  • 4
    \$\begingroup\$ Is it true that if there are 8 digits, one omits A from the formula given? \$\endgroup\$ – isaacg Dec 8 '16 at 8:29
  • \$\begingroup\$ @isaacg I've added the rule regarding this with a link to the (Dutch) wikipedia page. You are indeed right, it omits A from the formula (or basically adds a leading 0 to make it length 9, resulting in the same result as omitting A). \$\endgroup\$ – Kevin Cruijssen Dec 8 '16 at 9:13
  • \$\begingroup\$ Test case for "sum [...] should not be 0.": 000000012 \$\endgroup\$ – betseg Dec 8 '16 at 11:51
  • \$\begingroup\$ @betseg I've added it to the list \$\endgroup\$ – Kevin Cruijssen Dec 8 '16 at 11:58

24 Answers 24

8
\$\begingroup\$

05AB1E, 23 21 bytes

`()DgLR*OD11Ö89¹gåP0Ê

Try it online! or as a Test suite

Explanation

`                        # push input as individual chars onto stack
 (                       # negate top value
  )                      # wrap in list
   DgLR                  # range [len(input) ... 1]
       *O                # multiply with list of digits and sum
         D11Ö            # is evenly divisible by 11
             89¹gå       # len(input) is 8 or 9
                  P      # product of sum/divisible by 11/len in (8,9)
                   0Ê    # not equal to 0
\$\endgroup\$
  • \$\begingroup\$ Probably due to an older version of 05AB1E, but you can save 3 bytes now by changing DgL to ā and to Ā. Try it online. \$\endgroup\$ – Kevin Cruijssen Aug 31 '18 at 10:06
12
\$\begingroup\$

JavaScript (ES6) 57

Input as an array of chars. reduceRight saves the day!

s=>!(i=1,t=s.reduceRight((t,v)=>t-v*++i),!t|t%11|(i|1)-9)

Test

F=
s=>!(i=1,t=s.reduceRight((t,v)=>t-v*++i),!t|t%11|(i|1)-9)


;['111222333','123456782','232262536','010464554','10464554','44016773']
.forEach(t=>{
  var r=F([...t]);console.log(t,r)
})

;['000000000','192837465','247594057','88888888','73','3112223342','3112223342']
.forEach(t=>{
  var r=F([...t]);console.log(t,r)
})

\$\endgroup\$
  • 1
    \$\begingroup\$ Always nice to see a reduceRight answer! \$\endgroup\$ – Neil Dec 8 '16 at 11:42
  • \$\begingroup\$ Finally found a way to reach 58 with map(), just to realize that your answer is actually 57 bytes long :-) \$\endgroup\$ – Arnauld Dec 8 '16 at 15:57
  • \$\begingroup\$ @Arnauld yep I can't believe I counted wrong again, thanks \$\endgroup\$ – edc65 Dec 8 '16 at 17:40
8
\$\begingroup\$

R, 86 67 bytes

Edit: Thanks to Jarko Dubbeldam for suggesting the dot product!

l=length(x<-scan(,""));s=as.double(x)%*%c(l:2,-1);!s%%11&s&l>7&l<10

Reads input from stdin and store as an array/vector of characters. Subsequently convert to numeric,multiply with the vector 9...2,-1 and check all conditions.

\$\endgroup\$
  • \$\begingroup\$ Does not work for me. You should split x as vector. \$\endgroup\$ – djhurio Dec 8 '16 at 13:42
  • \$\begingroup\$ @djhurio Enter the values separated by space and they are implicitly stored in a vector of characters. Alternatively enter them one by one by hitting enter in between. \$\endgroup\$ – Billywob Dec 8 '16 at 15:03
  • 1
    \$\begingroup\$ if(l<9)x=c(0,x);s=sum(as.double(x)*c(9:2,-1)) can be turned into s=sum(as.double(x)*c(l:2,-1)). Also, the sum of the pairwise product of two vectors is the same as their dot-multiplication %*%. \$\endgroup\$ – JAD Dec 9 '16 at 9:30
  • \$\begingroup\$ @JarkoDubbeldam Nice! The dot product is really clever. \$\endgroup\$ – Billywob Dec 9 '16 at 9:40
7
\$\begingroup\$

JavaScript (ES6), 61 60 59 58 bytes

Takes an array of chars as input. Returns false / true.

a=>!(a.map(c=>s-=--k?-c*k-c:c,k=a.length&9,s=0)|!s|k|s%11)

Test cases

let f =

a=>!(a.map(c=>s-=--k?-c*k-c:c,k=a.length&9,s=0)|!s|k|s%11)

// truthy
console.log(f([..."111222333"]));
console.log(f([..."123456782"]));
console.log(f([..."232262536"]));
console.log(f([..."010464554"]));
console.log(f([..."10464554"]));
console.log(f([..."44016773"]));

// falsy
console.log(f([..."000000000"]));
console.log(f([..."192837465"]));
console.log(f([..."247594057"]));
console.log(f([..."88888888"]));
console.log(f([..."73"]));
console.log(f([..."3112223342"]));

\$\endgroup\$
6
\$\begingroup\$

C, 112 101 96 98 104 bytes

Thanks to @MartinEnder for saving 5 3 bytes while fixing my code!

j,i,k,l;f(char*s){l=strlen(s);for(i=l,j=k=0;j<l;)k+=(s[j++]-48)*(i>1?i--:-1);return!(k%11)&&k&&(l^8)<2;}

Returns 0 if invalid, 1 if valid. Try it online!

\$\endgroup\$
  • \$\begingroup\$ This accepts 61 even though it is not of correct length. \$\endgroup\$ – Christian Sievers Dec 8 '16 at 10:53
  • 1
    \$\begingroup\$ This does not work with my personal BSN. \$\endgroup\$ – Roberrrt Dec 8 '16 at 11:03
  • \$\begingroup\$ Hopefully fixed. \$\endgroup\$ – betseg Dec 8 '16 at 11:46
  • \$\begingroup\$ Not fixed. Doesn't work with mine either. \$\endgroup\$ – DavidPostill Dec 8 '16 at 23:32
  • 1
    \$\begingroup\$ @Roberrrt, @DavidPostill; is it OK now or should I just give up? =( \$\endgroup\$ – betseg Dec 9 '16 at 15:53
5
\$\begingroup\$

R, 95 79 93 bytes

function(x){y=as.double(el(strsplit(x,"")));z=y%*%c((q<-length(y)):2,-1);(z&!z%%11&q>7&q<10)}

Unnamed function that takes a string as argument. At first I overread the requirement of having a string as input instead of a number, but that's good, because it saves some bytes on conversion.

I am not sure how to interpret the array of characters, but if that means that you can use a vector of stringed digits "1" "2" "3" "4" etc as input, it becomes a bit shorter even:

function(x){y=as.double(x);z=y%*%c((q<-length(y)):2,-1);(z&!z%%11&q>7&q<10)}

Splits x into a numeric vector, then appends a 0 if length is 8, then calculates the dotproduct of vector y and c(9,8,7,6,5,4,3,2,-1). Tests if the result is both nonzero and divisible by 11.

Saved 16 bytes thanks to the logic by @Enigma, implicitly appending the 0 in the creation of the vector c(length(x):2,-1).

Forgot to add check for length 8/9, so +14 bytes :(

\$\endgroup\$
4
\$\begingroup\$

Perl, 58 bytes (52 + 6)

@N=(-1,2..9);$r+=$_*shift@N for reverse@F;$_=$r&&/^\d{8,9}$/&&!($r%11)

Run with

perl -F// -lapE

Input passed through STDIN:

Usage

echo 232262536 | perl -F// -lapE '@N=(-1,2..9);$r+=$_*shift@N for reverse@F;$_=$r&&/^\d{8,9}$/&&!($r%11)'

Outputs 1 for as the truthy value, 0 or nothing for falsey values.

\$\endgroup\$
  • \$\begingroup\$ You can save some bytes at the beginning: $r+=$_*(-1,2..9)[$i++]for reverse@F. Also, -F -pe (and input supplied without final newline, with echo -n for instance) is enough (unless your Perl is too old, in which case you'll need -a (but on recent Perls, it's implied by -F). Finally, your code was 70 bytes long, not 52 ;) \$\endgroup\$ – Dada Jan 12 '17 at 21:27
3
\$\begingroup\$

C++14, 107 106 bytes

-1 byte for int instead of auto in for loop.

As unnamed lambda returning via reference parameter. Requires input to be std::string or a container of char, like vector<char>.

[](auto c,int&r){int i=c.size();r=7<i&&i<10?-2*c.back()+96:~1<<9;for(int x:c)r+=(x-48)*i--;r=r%11<1&&r>0;}

Ungolfed and usage:

#include<iostream>
#include<string>

auto f=
[](auto c, int& r){
 int i = c.size();
 //if the size is correct, init r to -2*I so we can add I safely later
 //otherwise such a big negative number, that the final test fails
 r = 7<i && i<10 ? -2*c.back()+96 : ~1<<9;
 for (auto x:c)
  r += (x-48)*i--;
 r = r%11<1 && r>0;
}
;

using namespace std;
using namespace std::literals;

int main(){
 int r;
 f("111222333"s,r); std::cout << r << std::endl;
 f("123456782"s,r); std::cout << r << std::endl;
 f("010464554"s,r); std::cout << r << std::endl;
 f("10464554"s,r); std::cout << r << std::endl;
 f("44016773"s,r); std::cout << r << std::endl;
 std::cout << std::endl;
 f("000000000"s,r); std::cout << r << std::endl;
 f("192837465"s,r); std::cout << r << std::endl;
 f("73"s,r); std::cout << r << std::endl;
 f("88888888"s,r); std::cout << r << std::endl;
 f("3112222342"s,r); std::cout << r << std::endl;
 std::cout << std::endl;
 f("99999999"s,r); std::cout << r << std::endl;
 f("999999999"s,r); std::cout << r << std::endl;
}
\$\endgroup\$
3
\$\begingroup\$

Befunge, 72 bytes

>+~>:0`v
^1\-*68_\2/4-!00p*8>1-10p\910gv
@.!+!\%+56:*g00$  _^#!:g01+*-<<

Try it online!

Explanation

>+~>:0`v            Read characters from stdin until EOF, converting each digit into
^1\-*68_              a number on the stack, and keeping a count of the characters read.

      \2/4-!00p     Save !(count/2-4), which is only true for valid lengths (8 and 9).
               *    Multiply the EOF (-1) with the final digit; this is the initial total.

8>1-10p\910gv       Loop over the remaining 8 digits, multiplying each of them by 9-i and
 ^#!:g01+*-<<         add to the total; i goes from 7 down to 0, so 9-i goes from 2 to 9.

               $    Drop the loop counter.
           *g00     Multiply total by the length calculation (invalid lengths become 0).
      %+65:         Make a copy of the total, and calculate modulo 11.
    !\              Boolean not the other copy to check for zero. 
  !+                !(total%11 + !(total)) is only true for non-zero multiples of 11.
@.                  Output the result and exit.
\$\endgroup\$
3
\$\begingroup\$

MATL, 36 bytes

Not the longest MATL program I've ever written, but I like how if/else statements get very lengthy very quickly in golfing languages. I feel that this solution may not be optimal in MATL, but as of yet I can't optimize it any further. I'm thinking of using the double 0 somewhere, and maybe cut down on the t's everywhere.

48-tn8=?0wh]tn9=?P[a2:9]*st11\~Y&}x0

Try it online! Explanation:

48-                                  % Subtract 48 (ASCII '0')
   tn                                % Duplicate. Get length.
     8=?                             % If length equals 8
        0wh                          %     Prepend 0 to the duplicate
           ]                         % End if.
            t                        % Duplicate again.
             n9=?                    % If length equals 9.
                 P                   %     Reverse the duplicate
                  [a2:9]*            %     Element-wise product with [-1 2 ... 9]
                         s           %     Sum
                          t11\       %     Duplicate sum, modulus 11
                              ~Y&    %     Result on stack: modulus==0 AND sum!=0
                                 }   % Else
                                  x0 %     Remove the duplicate. Put 0 on stack.
                                     % Display implicitly.
\$\endgroup\$
  • \$\begingroup\$ If you can make do with a column vector: !U instead of 48- \$\endgroup\$ – Luis Mendo Dec 8 '16 at 15:28
  • \$\begingroup\$ Beat ya :-P \$\endgroup\$ – Luis Mendo Dec 8 '16 at 15:42
  • \$\begingroup\$ @LuisMendo Too bad. [a2:9]* results in a non-element-wise multiplication, so another ! would be needed which would offset the initial gain. \$\endgroup\$ – Sanchises Dec 8 '16 at 15:43
3
\$\begingroup\$

MATL, 26 bytes

!UGg*R!s0&)s-t11\~Gn8-tg=v

The result is a non-empty column vector, which is truthy iff all its entries are nonzero.

Try it online!

Or verify all test cases with each result on a different line.

Explanation

This tests the three conditions in the following order:

  1. Weighted sum is nonzero;
  2. Weighted sum is dividible by 11;
  3. Length is 8 or 9.

Consider input '8925' for the explanation. ; is the row separator for matrices.

!     % Implicit input. Transpose into a column vecvtor
      % STACK: ['8'; '9'; '2'; '5']
U     % Convert each digit to number
      % STACK: [8; 9; 2; 5]
Gg    % Push a row array of ones as long as the input
      % STACK: [8; 9; 2; 5], [1 1 1 1]
*     % Multiply, element-wise with broadcast
      % STACK: [8 8 8 8; 9 9 9 9; 2 2 2 2; 5 5 5 5]
R     % Upper triangular part
      % STACK: [8 8 8 8; 0 9 9 9; 0 0 2 2; 0 0 0 5]
!     % Transpose
      % STACK: [8 0 0 0;8 9 0 0;8 9 2 0;8 9 2 5]
s     % Sum of each column. This multiplies last element by 1, second-last by 2 etc
      % STACK: [32 27 4 5]
0&)   % Split into last element and remaining elements
      % STACK: 5, [32 27 4]
s     % Sum of array
      % STACK: 5, 63
-     % Subtract
      % STACK: -58. This is the result of condition 1
t11\  % Duplicate. Modulo 11
      % STACK: -58, 8
~     % Logical negation
      % STACK: -58, 0. This gives condition 2
Gn    % Push numnber of entries in the input
      % STACK: -58, 0, 4
8-    % Subtract 8. For valid lengths (8 or 9) this gives 0 or 1
      % STACK: -58, 0, -4
tg    % Duplicate. Convert to logical: set nonzero values to 1
      % STACK: -58, 0, -4, 1
=     % 1 if equal, 0 otherwise. Lenghts 8 or 9 will give 1. This is condition 3
      % STACK: -58, 0, 0
v     % Vertically concatenate the entire stack. This is truthy iff all values 
      % are non-zero. Implicitly display
      % STACK: [-58; 0; 0]
\$\endgroup\$
  • \$\begingroup\$ Well done. I figured that an approach without ? would probably be more efficient, but I couldn't figure out how to shorten the length 8 or 9. Your Gn8-tg= is very clever. \$\endgroup\$ – Sanchises Dec 8 '16 at 15:55
  • 1
    \$\begingroup\$ By the way, wouldn't a column vector input qualify as a char-array representing the BSN, saving you the first !? \$\endgroup\$ – Sanchises Dec 9 '16 at 14:28
  • \$\begingroup\$ @Sanchises The problem is that then G pushes a column vector and I need to transpose it to do the repetition with g* \$\endgroup\$ – Luis Mendo Dec 9 '16 at 16:58
  • \$\begingroup\$ Oh right of course. Never mind! \$\endgroup\$ – Sanchises Dec 9 '16 at 17:30
3
\$\begingroup\$

Haskell, 116 112 102 bytes

f x=div(length x)2==4&&g x>0&&h x
h=((==0).(`mod`11)).g
g=sum.zipWith(*)(-1:[2..]).map(read.(:[])).reverse

g counts the sum used in the eleven-proef of h, while f also checks for the correct length and that the eleven-proef is not 0. Especially the checks of f take a lot of bytes.

EDIT: saved 10 bytes thanks to Lynn and div rounding down.

\$\endgroup\$
  • 1
    \$\begingroup\$ How about f x=div(length x)2==4&&g x>0&&h x? \$\endgroup\$ – Lynn Dec 8 '16 at 17:53
  • \$\begingroup\$ @Lynn: that is a nice one, thanks. \$\endgroup\$ – Renzeee Dec 9 '16 at 7:50
2
\$\begingroup\$

Jelly, 21 bytes

V€U×JN1¦µL:2=4×Sµ11ḍa

TryItOnline! or run all test cases

Truthy return values are non-zero (and are, in fact, the multiple of 11 sum).

How?

V€U×JN1¦µL:2=4×Sµ11ḍa - Main link: string of digits  e.g. "111222333"
V€                    - eval each - effectively cast each to an integer (keeps leading zeros)
  U                   - upend                        e.g. [ 3, 3, 3, 2, 2, 2, 1, 1, 1]
    J                 - range(length)                e.g. [ 1, 2, 3, 4, 5, 6, 7, 8, 9]
   ×                  - multiply                     e.g. [ 3, 6, 9, 8,10,12, 7, 8, 9]
      1¦              - apply to index 1 (first element)
     N                -     negate                   e.g. [-3, 6, 9, 8,10,12, 7, 8, 9]
        µ             - monadic chain separation   e.g. z=[-3, 6, 9, 8,10,12, 7, 8, 9]
         L            - length(z)                    e.g. 9
          :2          - integer divide by 2          e.g. 4
            =4        - equals 4?                    e.g. 1
               S      - sum(z)                       e.g. 66
              ×       - multiply                     e.g. 66
                µ     - monadic chain separation   e.g. z=66
                 11ḍ  - divides(11, z)               e.g. 1
                    a - and z (for z=0 case)         e.g. 66 (truthy)
\$\endgroup\$
  • \$\begingroup\$ Unfortunately I can only accept one answer instead of two, since yours has the same 21 byte-count as @Emigna's 05AB1E answer. But since Enigma answered sooner (and his edit for 21 bytes was also sooner) I've accepted his. \$\endgroup\$ – Kevin Cruijssen Jun 29 '17 at 11:54
  • \$\begingroup\$ That sounds fair to me! \$\endgroup\$ – Jonathan Allan Jun 29 '17 at 14:50
2
\$\begingroup\$

Python 2, 102 bytes

def f(i):S=sum(a*b for a,b in zip([-1]+range(2,10),map(int,i)[::-1]));return(7<len(i)<10)*(S%11<1)*S>0
\$\endgroup\$
2
\$\begingroup\$

Python 2, 96 bytes

def g(s):u=7<len(s)<10and sum(x*int(('0'+s)[-x])for x in range(2,10))-int(s[-1]);print(u%11<1)*u

Takes a string as input. The function adds a '0' to the front of the string whether it needs it or not, and uses Python's negative indices to add elements, starting from the end of the string and working back-to-front.

The -1xI is handled separately, using a second call to int(). I couldn't figure out how to avoid this without costing more bytes than I saved.

def g(s):u=7<len(s)<10and sum(x*int(('0'+s)[-x])for x in range(10))-2*int(s[-1]);print(u%11<1)*u would work just as well, since it would add 1 times s[-1] but then subtract it twice, and it would also add 0 times (something) which of course wouldn't affect the sum.

\$\endgroup\$
2
\$\begingroup\$

Brain-Flak, 345 Bytes

Includes +3 for -a

([]){{}({}[((((()()()){}){}){}){}]<>)<>([])}{}<>([][(()()()()){}]){({}[()]){([]){{}{}([])}}}{}([{}])({}({}){})({}({})({}){})({}(({}){}){})({}(({})({})){}{})({}(({})({}){}){})({}((({}))({}){}){}{})({}((({}){}){}){})(({}(((({})){}){}){}{}{}<(((()()())()){}{})>)){{}({}(<>))<>{(({})){({}[()])<>}{}}{}<>([{}()]{}[{}]<(())>){((<{}{}>))}{}(<()>)}{}

Truthy is 1, Falsy has a 0 on the top of the stack.

Try it Online!

I'm pretty sure there is a shorter way to do the multiplication in a loop, but I haven't found it yet.

#reverse and subtract 48 from all numbers (ASCII -> decimal)
([]){{}({}[((((()()()){}){}){}){}]<>)<>([])}{}<> 

([][(()()()()){}])       #height - 8
{({}[()]){               #if not 0 subtract 1
   ([]){{}{}([])}        #if still not 0 pop everything
}}{}                     #this loop pops everything unless there are 8 or 9 digits

([{}])                   # -I
({}({}){})               # H*2
({}({})({}){})           # G*3
({}(({}){}){})           # F*4
({}(({})({})){}{})       # E*5
({}(({})({}){}){})       # D*6
({}((({}))({}){}){}{})   # C*7
({}((({}){}){}){})       # B*8
(({}(((({})){}){}){}{}{} # A*9 pushed twice with:
<(((()()())()){}{})>))   # 11 under it


{{} #if not 0
({}(<>))<>{(({})){({}[()])<>}{}}{}<>([{}()]{}   # mod 11
[{}]<(())>){((<{}{}>))}{}                       # logical not
(<()>)                                          # push 0 to exit loop
}{}
                                                # implicit print
\$\endgroup\$
2
\$\begingroup\$

PowerShell v2+, 96 bytes

param($n)$i=8-($n.count-eq8);!(($b=($n|%{(-"$_",(($i+1)*+"$_"))[!!$i--]})-join'+'|iex)%11)-and$b

OK, I'll admit, this looks like a complete mess. And it kinda is. But, bear with me and we'll get through it.

We take input $n (as a char-array) and set $i equal to 8 minus a Boolean value for whether there are 8 items in $n. Meaning, if there are 8 items, then $i would be 7.

The next section combines the calculation with our output. Working from the inside, we loop through $n with $n|%{...}. Each iteration, we use a pseudo-ternary to come up with one of two results -- either -"$_" or (($i+1)*+"$_"). The index is based on whether $i is 0 or not (i.e., we've hit the -1xI case from the challenge equation), which gets post-decremented for the next go-round. Those are all gathered up in parens and -joined together with +. For example, with input 111222333 at this point we'd have 9+8+7+12+10+8+9+6+-3. That is piped to iex (short for Invoke-Expression and similar to eval) before being stored into $b. We then take that %11 and perform a Boolean-not !(...) on that (i.e., so if it is divisible by 11, this portion is $true). That's coupled with -and$b to ensure that $b is non-zero. That Boolean result is left on the pipeline and output is implicit.

Examples

PS C:\Tools\Scripts\golfing> 111222333,123456782,232262536,010464554,10464554,44016773|%{"$_ -> "+(.\dutch-burgerservicenummer.ps1 ([char[]]"$_"))}
111222333 -> True
123456782 -> True
232262536 -> True
10464554 -> True
10464554 -> True
44016773 -> True

PS C:\Tools\Scripts\golfing> 000000000,192837465,247594057,88888888,73,3112223342,000000012|%{"$_ -> "+(.\dutch-burgerservicenummer.ps1 ([char[]]"$_"))}
0 -> False
192837465 -> False
247594057 -> False
88888888 -> False
73 -> False
3112223342 -> False
12 -> False
\$\endgroup\$
2
\$\begingroup\$

PHP 139 128 bytes

 $u=-1;$i=$argv[1];while($u<=strlen($i)){$c+=($u*(substr($i,-(abs($u)),1)));$u +=$u<0?3:1;}echo($c>0&&!($c%11)&&$u>8&&$u<11?1:0);

Could not get the CLI to just echo the true of false. Had to make do it this way. Any ideas?

128 bytes: Turned "true" and "false" to 1 and 0.

\$\endgroup\$
2
\$\begingroup\$

C#, 120 115 bytes

This loops through the char[] it receives as input and returns true or false:

bool b(char[]n){int r=0,k,i=0,l=n.Length;for(;i<l;i++){k=i==l-1?-1:l-i;r+=k*(n[i]-48);}return r>0&r%11<1&l<10&l>7;}

Fiddle: https://dotnetfiddle.net/3Kaxrt

I'm sure I can scrape out a few bytes, especially in the messy return. Any ideas welcome!

Edit: Saved 5 bytes thanks to Kevin. I had no idea I could use & instead of &&!

\$\endgroup\$
  • 1
    \$\begingroup\$ +1! r>0&&r%11==0&&l<10&&l>7 can be golfed to r>0&r%11<1&l<10&l>7 (&& to & and r%11==0 to r%11<1). And -'0' can be golfed to -48. \$\endgroup\$ – Kevin Cruijssen Dec 9 '16 at 7:56
2
\$\begingroup\$

PHP, 86 85 84 83 82 79 bytes

Note: uses PHP 7.1 for negative string indices.

for($l=log10($a=$argn);~$c=$a[-++$x];)$s+=$x>1?$x*$c:-$c;echo$s%11<1&$l>7&$l<9;

Run like this:

echo 010464554 | php -nR 'for($l=log10($a=$argn);~$c=$a[-++$x];)$s+=$x>1?$x*$c:-$c;echo$s%11<1&$l>7&$l<9;';echo
> 1

Version for PHP < 7.1 (+10 bytes)

echo 010464554 | php -nR 'for($l=log10($a=$argn);~$c=$a[strlen($a)-++$x];)$s+=$x>1?$x*$c:-$c;echo$s%11<1&$l>7&$l<9;';echo

Explanation

for(
  $l=log10(         # Take the log of the input number.
    $a=$argn        # Set input to $a
  );
  ~$c=$a[-++$x];    # Iterate over digits of input (reverse). Negate to
                    # change every char to extended ASCII (all truthy),
                    # without changing empty sting (still falsy, ending
                    # the loop).
)
  $s+=$x>1?         # Add current char to the sum...
     ?$x*$c:-$c;    # multiplied by $x, unless $x is 1; subtract it.
echo
  $s%11<1 &         # Check if sum is divisible by 11, and
  $l>7   &          # log of the input is greater than 7, and
  $l<9;             # log of the input is less than 9. Outputs 0 or 1.

Tweaks

  • Shorter way to distinguish between empty string and "0", saved a byte
  • Since 10000000 is invalid, no need to compare with greater than or equals, greater than suffices, saving a byte
  • Shorter way to subtract least significant digit
  • Negate char instead of XOR, saving a byte
  • Saved 3 bytes by using -R to make $argn available
\$\endgroup\$
2
\$\begingroup\$

Java 8, 115 98 bytes

b->{int l=b.length,i=0,r=0,x;for(;l>7&l<10&i<l;r+=(b[i++]-48)*(x<2?-1:x))x=l-i;return r>0&r%11<1;}

I'm surprised no one has posted a Java answer yet, so here is one.

Explanation:

Try it here.

b->{                  // Method with character-array as parameter and boolean return-type
  int l=b.length,     //  Length of the array
      i=0,            //  Index-integer, starting at 0
      r=0,            //  The result-sum, starting at 0
      x;              //  Temp integer `x`
  for(;l>7&l<10       //  Start looping if the length is either 8 or 9
       &i<l;          //  And continue looping while the index is smaller than the length
      r+=             //    After every iteration, increase the result-sum by:
         (b[i++]-48)  //     The current digit
         *(           //     Multiplied by:
           x<2?       //      If `x` is 1:
            -1        //       Multiply by -1
           :          //      Else:
            x))       //       Simply multiply by `x` 
    x=l-i;            //   Set `x` to the length minus the current index
                      //  End of loop (implicit / single-line body)
  return r>0          //  Return if the result-sum is larger than 0,
    &r%11<1;          //   and if the result-sum is divisible by 11
}                     // End of method
\$\endgroup\$
1
\$\begingroup\$

Clojure, 114 bytes

Well this is something, - substracts the rest of the arguments from the first one so that handles the special case of weight -1. This function returns nil for inputs of invalid length, but on if clauses they operate the same as false. (#{8 9}(count v)) returns nil if length of v is not 8 or 9.

(fn[v](if(#{8 9}(count v))(#(and(< % 0)(=(mod % 11)0))(apply -(map *(range 1 10)(reverse(map #(-(int %)48)v)))))))

Test cases:

(pprint (group-by f (map str [123456782 232262536 "010464554" 10464554 44016773 "000000000" 192837465 247594057 88888888 73 3112223342 "000000012"])))
{true  ["123456782" "232262536" "010464554" "10464554" "44016773"],
 false ["000000000" "192837465" "247594057" "88888888" "000000012"],
 nil   ["73" "3112223342"]}
\$\endgroup\$
1
\$\begingroup\$

Perl 5, 63 + 2 (-F) = 65 bytes

$F[-1]*=-1;map$s+=++$i*$_,reverse@F;say/^.{8,9}$/&&$s&&!($s%11)

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Stax, 23 bytes

╪╦µΘç}<╔▼◘╞i∟~¿≥←║▐√ 4u

Run and debug online!

Explanation

Uses the unpacked version to explain.

i%8A:byr{]ei^*mBN+|+c11%!L|A
i                               Suppress implicit eval
 %8A:b                          Length is 8 or 9 (Element #1 on the final stack)
      yr                        Reverse input
        {     m                 Map each element with
         ]e                         Its numerical value
           i^*                      Multiplied current 1-based loop index
               BN+              Negate the first element
                  |+            Sum (Element #2 on the final stack)
                    c11%!       Sum is multiple of 11 (Element #3 on the final stack)
                         L|A    Collect all the three elements and `and` them.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.