9
\$\begingroup\$

A Norwegian Birth Number consists of 11 digits, composed the following way:

DDMMYYiiikk
  • DD is the day (from 01-31)
  • MM is the month (from 01-12)
  • YY is the year (from 00-99). It's not differentiated between 1900 and 2000
  • iii is the "individual number"
  • kk are two control digits

iii is determined by birthyear and gender the following way

  • 0000-1900: Disregard, there is some inconsistency and special cases
  • 1900-1999: Range = 000-499
  • 2000-2039: Range = 500-999
  • Female: Even numbers (and 000)
  • Male: Odd numbers

The control numbers are determined the following way:

Let's call the 11 digits:

d1 d2 m1 m2 y1 y2 i1 i2 i3 k1 k2

Then the control digits can be calculated using the equations:

k1 = 11 - ((3 * d1 + 7 * d2 + 6 * m1 + 1 * m2 + 8 * y1 + 9 * y2 + 4 * i1 + 5 * i2 + 2 * i3) mod 11)

k2 = 11 - ((5 * d1 + 4 * d2 + 3 * m1 + 2 * m2 + 7 * y1 + 6 * y2 + 5 * i1 + 4 * i2 + 3 * i3 + 2 * k1) mod 11).

For some combinations, the control numbers k1 or k2 can become 10. If that's the case, the number will be invalid.

If the sum modulus 11 for k1 or k2 is 11, i.e. k1 = 11 - (11 mod 11), then the control digit will be 0, not 11.

Challenge

Take a letter, M or F (male or female), and an eleven digit number as input, and check if the Birth Number is valid according to the rules above.

  • Input format and order is optional
  • The 11 numbers must be a single number or a consecutive string (you can't take the input as DD, MM, YY, iii, kk).
  • You can assume the date is valid (310699xxxxx will not be given as input)
  • Output is a truthy/falsy value (1/0, true/false etc.)
  • Program or function
  • All standard rules apply

You can find all valid numbers on this page (in Norwegian) by choosing a date.

Examples:

M, 01010099931
True

F, 01029042620
True

M, 0101009841
False

F, 01010051866
True  

F, 08021690849
True

M, 01029040105
True

M, 01029037473
False

Shortest code in bytes win.

\$\endgroup\$
  • \$\begingroup\$ Do we need to handle genders other than M and F? (Is it against the rules if ["Q", "01010099931"] returns true?) \$\endgroup\$ – Chiru Feb 9 '16 at 16:44
  • \$\begingroup\$ @Chiru, assume only M or F is given as input. Undefined behavior for invalid input is OK. \$\endgroup\$ – Stewie Griffin Feb 9 '16 at 16:46
2
\$\begingroup\$

Python 3, 227 221 bytes

Function that takes two arguments, the gender 'm', and the birthnumber 'n', both as strings. There may be some more golfing to be done, especially in the last line. I'll keep working on it.

def a(m,n):
 o=[3,7,6,1,8,9,4,5,2];t=[5,4,3,2,7,6,5,4,3,2];n=list(map(int,n));y=z=b=0;q=11
 for i in n[:9]:z+=o[b]*i;y+=t[b]*i;b+=1
 print((q-z%q)%q==n[9] and (q-(y-z-z)%q)%q==n[-1] and len(n)<12 and ord(m)%2==n[8]%2)
\$\endgroup\$
2
\$\begingroup\$

JavaScript (ES2016), 275 259 255 254 252 Bytes

Golfed:

f=(g,I)=>{[,d,m,y,i,k]=/(..)(..)(..)(...)(..)/.exec(I.padEnd(12)),v=g.charCodeAt()%2!=i%2|y<=39&i<500,s=k=>11-([...I].slice(0,-2).map((e,i)=>e*[..."376189452543276543"][i+!k|9]).reduce((a,b)=>a+b)+2*k)%11,[s(0),s(s(0))].map((s,i)=>v&=k[i]!=s);return!v}

Tests:

for (let args of [
    ["M", "01010099931"], // true
    ["F", "01029042620"], // true
    ["M", "0101009841"],  // false
    ["F", "01010051866"], // true
    ["F", "08021690849"], // true
    ["M", "01029040105"], // true
    ["M", "01029037473"]  // false
]) {
    console.log(f(...args));
}

Ungolfed:

let f = (g, input) => {

    /* Sanitize input, destructure arguments via RegExp */
    let [, d, m, y, i, k] = /(..)(..)(..)(...)(..)/.exec(input.padRight(12));

    /* Validate gender and year */
    let violation = g.charCodeAt() % 2 != i % 2 | y <= 39 & i < 500;

    let n = [..."376189452543276543"];
    /* This function computes k1 if given no arguments, k2 if given one argument */
    let s = k => 11 - ([...input].slice(0, -2).map((e, i) => e * n[i + !k | 9]).reduce((a, b) => a + b) + 2 * k) % 11;

    /* Validate the control numbers k */
    [s(0), s(s(0))].map((s, i) => violation &= k[i] != s);

    return !violation;
}
\$\endgroup\$
1
\$\begingroup\$

JS, 343 Bytes

x=prompt().replace(/F/,1).replace(/M/,2).match(/\d{1}/g);v=Math.abs((x[0]-x[9])%2);v++;t=x[5]*10+x[6]*1;i=x[7]*1;if(t>39&&i>4){v--}if((11-(3*x[1]+7*x[2]+6*x[3]+1*x[4]+8*x[5]+9*x[6]+4*x[7]+5*x[8]+2*x[9])%11)%11===x[10]*1&&(11-(5*x[1]+4*x[2]+3*x[3]+2*x[4]+7*x[5]+6*x[6]+5*x[7]+4*x[8]+3*x[9]+2*x[10])%11)%11===x[11]*1){v++}alert(Math.floor(v/3))
\$\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.