36
\$\begingroup\$

An EAN-8 barcode includes 7 digits of information and an 8th checksum digit.

The checksum is calculated by multiplying the digits by 3 and 1 alternately, adding the results, and subtracting from the next multiple of 10.

For example, given the digits 2103498:

Digit:        2   1   0   3   4   9   8
Multiplier:   3   1   3   1   3   1   3
Result:       6   1   0   3  12   9  24

The sum of these resulting digits is 55, so the checksum digit is 60 - 55 = 5


The Challenge

Your task is to, given an 8 digit barcode, verify if it is valid - returning a truthy value if the checksum is valid, and falsy otherwise.

  • You may take input in any of the following forms:
    • A string, 8 characters in length, representing the barcode digits
    • A list of 8 integers, the barcode's digits
    • A non-negative integer (you can either assume leading zeroes where none are given, i.e. 1 = 00000001, or request input with the zeroes given)
  • Builtins that compute the EAN-8 checksum (i.e, take the first 7 digits and calculate the last) are banned.
  • This is , so the shortest program (in bytes) wins!

Test Cases

20378240 -> True
33765129 -> True
77234575 -> True
00000000 -> True

21034984 -> False
69165430 -> False
11965421 -> False
12345678 -> False
\$\endgroup\$
5
  • \$\begingroup\$ Related to Luhn algorithm for verifying credit card numbers, possibly a dupe. \$\endgroup\$
    – xnor
    Nov 15, 2017 at 17:58
  • 1
    \$\begingroup\$ This question is not actually about a bar code (which is the black-white striped thing), but about the number encoded by a barcode. The number can exist without a bar code, and the bar code can encode other things than EANs. Maybe just "Is my EAN-8 valid" is a better title? \$\endgroup\$ Nov 15, 2017 at 19:49
  • 2
    \$\begingroup\$ @PaŭloEbermann doesn't quite have the same ring to it... \$\endgroup\$
    – FlipTack
    Nov 15, 2017 at 20:17
  • 7
    \$\begingroup\$ When reading about barcodes, I expect some image reading (or at least a bit-string), not verifying a checksum. \$\endgroup\$ Nov 15, 2017 at 20:19
  • \$\begingroup\$ Strongly related, since an ISBN-13 is an EAN. \$\endgroup\$ Nov 16, 2017 at 14:55

59 Answers 59

1
2
1
\$\begingroup\$

Ruby, 41 Bytes

Takes an array of integers. -6 bytes thanks to Jordan.

->n{n.zip([3,1]*4){|x,y|$.+=x*y};$.%10<1}
\$\endgroup\$
1
  • \$\begingroup\$ Nice! FWIW you don’t need map here at all: zip takes a block. You can save a couple more bytes by using $. instead of initializing s: ->n{n.zip([3,1]*4){|x,y|$.+=x*y};$.%10<1} \$\endgroup\$
    – Jordan
    Nov 16, 2017 at 6:44
1
\$\begingroup\$

TI-Basic (83 series), 18 bytes

not(fPart(.1sum(2Ans-Ans9^cumSum(binomcdf(7,0

Takes input as a list in Ans. Returns 1 for valid barcodes and 0 for invalid ones.

A port of my Mathematica answer. Includes screenshot, in lieu of an online testing environment:

barcode screenshot

Notable feature: binomcdf(7,0 is used to generate the list {1,1,1,1,1,1,1,1} (the list of probabilities that from 7 trials with success probability 0, there will be at most N successes, for N=0,1,...,7). Then, cumSum( turns this into {1,2,3,4,5,6,7,8}.

This is one byte shorter than using the seq( command, though historically the point was that it's also significantly faster.

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

><>, 89 84 Bytes

8>i$1\
/\?:-/
\8+  \
/1-:?v~r3*+\
\ } \$>3*+v<
/++-/f}   l
\+3ff/\?-4/
/a+++/
\%0=n;

Can probably certainly be improved (this is my second ><> program)

How it works:

8>i$1\
 \?:-/

Gets user input, 8 times. Note that since i pushes -1 if the input stack is empty, this may not always return false for inputs shorter than 8 digits.

/
\8+  \
/1-:?v
\ } \$
/++-/f
\+3ff/

Converts the ascii values to their actual values.

      ~r3*+\
      >3*+v<
      }   l
      \?-4/

Remove the counter, and reverse the stack. Then, while the stack is longer than 4, multiply the top value by three, add it to the digit below it, and move the result to the bottom of the stack.

     /
/a+++/
\%0=n;

Sum the values on the stack. If the answer is divisible by 10, the code is valid. If so, print 1, otherwise, 0.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nice work! Here are a couple of suggestions to help get the bytes down. You can use the fish's wrapping behaviour to cut down on direction commands — it's often possible to fit a loop on a single line, with clever use of / and ?. The register (accessed with &) is a good place to store a counting variable, like you use to count how many times to go through a loop. Here's what your code might look like after applying these ideas (and a couple of others): Try it online! \$\endgroup\$
    – Not a tree
    Nov 28, 2017 at 23:37
1
\$\begingroup\$

Julia 29 bytes

~x=[3,1,3,1,3,1,3,1]⋅x%10<1

golfing away that long literal array would be nice.

⋅ is a 3 byte character. But it is shorter than calling dot(...,x). and shorter that anything that handles everything as arrays and then grabs the only element.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ !x=~2(1:8)%4⋅x%10==0 saves a few bytes. Try it online! \$\endgroup\$
    – Dennis
    Nov 18, 2017 at 17:32
1
\$\begingroup\$

Acc!!, 60 45 bytes

3*N+N+3*N+N+3*N+N+3*N+N-8
Write 1/(1+_%10)+48

Try it online!

Explanation

We read eight digits, multiplying the appropriate ones by 3, and add. It's not quite that simple, because what we're actually reading is ASCII codes, and so each digit has 48 added to it. Thus, the resulting sum is too big by 3*48*4 + 48*4 = 768. We only care about the 1's digit, so subtracting 8 is sufficient to get the correct result.

We want to print 1 if the accumulator mod 10 is 0, and 0 otherwise. Acc!! doesn't have comparison operators, so we have to use integer division:

_%10        0  1  9
1+_%10      1  2  10
1/(1+_%10)  1  0  0

Then we add 48 to get an ASCII value and Write it.


Original 60-byte solution with a loop:

Count i while 8-i {
_+(N-48)*(3-i%2*2)
}
Write 1/(1+_%10)+48
\$\endgroup\$
1
\$\begingroup\$

C 98, 118 bytes

Ive edited this now to instead of echoing F or T it will return 0 or 1 to the pipe.

int i,j,k;int main(int,char**v){for(;i<7;(j+=(v[1][i]-48)*(i++%2?1:3)));for(;(k+=10)<j;);return v[1][7]-48==(k-j)%10;}

usage:

./a.out XXXXXXXX

where XXXXXXXX is a zero padded string, it will return either a 0 or a 1 as an exit code

this is 118 chars long in total. and the the compiled program is

   text    data     bss     dec     hex filename
   1307     544      16    1867     74b a.out
\$\endgroup\$
3
  • \$\begingroup\$ Welcome to the site! I don't think that C requires newlines after semi-colons, so I think you can shave off a newline while retaining your functionality. \$\endgroup\$
    – Wheat Wizard
    Nov 20, 2017 at 7:02
  • \$\begingroup\$ Oh yeah for sure could've totally done that and bring it down to a 154 char solution. Though I don't think I could ever hit some of those 9 byte solutions with c. \$\endgroup\$
    – Peter Li
    Nov 20, 2017 at 7:34
  • \$\begingroup\$ It's best not to try to compare cross languages, the languages with the small solutions are designed to get short answers in the first place. (I've been here a while and I've never had the shortest answer yet) C answers can be impressive in their own right. I don't golf in C but I do know C a little bit and this seems like a pretty good answer to me. It's all about how cleverly you use the tools. \$\endgroup\$
    – Wheat Wizard
    Nov 20, 2017 at 7:40
1
\$\begingroup\$

Husk, 10 bytes

¬→dB3mΣTC2

Try it online!

Husk, 10 bytes

¦10B3mΣTC2

Try it online!

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

Japt, 12 11 bytes

Takes input as an array of digits, outputs 1 or 0.

xÈ*31sgYÃvA

Try it

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

Perl 6, 23 bytes

{:1[$_ «*»(3,1)]%%10}

Try it online!

Takes a list of digits.

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

Ruby, 37 bytes

->n{(n+n.scan(/.(.)/)*''*2).sum%10<1}

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Batch, 88 bytes

@set/as=0,n=%1
@for %%i in (1 2 3 4)do @set/as+=n+n/10*3,n/=100
@if %s:~-1%==0 echo 1

N.B. Leading zeros are not acceptable as they will cause the input to be treated as octal. As the numbers are always 8 digits the loop size can be hardcoded which saves 2 bytes.

\$\endgroup\$
0
\$\begingroup\$

Java (OpenJDK 8), 104 99 bytes

s->{int y=0,i=0;for(;i<7;y+=(3-i%2*2)*(s.charAt(i++)-48));return 58-(y%10<1?10:y%10)==s.charAt(7);}

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Suggest return(y%10<1?10:y%10)+s.charAt(7)==58; instead of return 58-(y%10<1?10:y%10)==s.charAt(7); \$\endgroup\$
    – ceilingcat
    Nov 13, 2019 at 8:12
0
\$\begingroup\$

Octave, 40 bytes

@(a)9-mod(a*("31313130"'-48)-1,10)==a(8)

Accepts an array of integers as input and returns true/false.

Try it online!

\$\endgroup\$
0
\$\begingroup\$

QBIC, 23 bytes

[4|_!_!p=p+b*3+c]?p%z=0

Explanation

[4|          DO four times
_!           Ask the user for a digit, save as 'b' ('a' is taken by [4| )
_!           Ask the user for a digit, save as 'c'
p=p          Add to running total p 
+b*3         the first digit times 3
+c           and the second digit
]            NEXT
?p%z=0       PRINT -1 if the seven digits + checksum MOD 10 == 0
\$\endgroup\$
0
\$\begingroup\$

Perl 5, 54 + 1 (-F) = 55bytes

$r=pop@F;map$s+=$_*(($.+=2)%4),@F;say$r==(10-$s%10)%10

Try it online!

\$\endgroup\$
0
\$\begingroup\$

PHP, 82 bytes

<?for(;$i<strlen($p=$argv[1])-1;)$t+=($i%2?1:3)*$p[$i++];echo(10-$t%10)%10==$p[7];

Try it online!

Input as a string; prints 1 for valid, nothing for invalid.

\$\endgroup\$
0
\$\begingroup\$

Clojure, 41 bytes

#(=(mod(apply +(map *(cycle[3 1])%))10)0)
\$\endgroup\$
0
\$\begingroup\$

GolfScript - 54 52 bytes

1/[{~}/][):a;[3 1]3*[3]+]zip 0\{{*}*+}/10%10\- 10%a=
  • Input: 33765129
  • Output: 1

If the input is an array the code can be modified to:

~[):a;[3 1]3*[3]+]zip 0\{{*}*+}/10%10\- 10%a=     # 45 bytes
  • Input: [3 3 7 6 5 1 2 9]
  • Output: 1

Explanation

1/[{~}/]     # Parse input
[):a;        # Gets last digit
[3 1]3*[3]+  # Generates the vector [3 1 3 1 3 1 3]
]zip         # Transposes the vector [[input] [3 1s]]
0\{{*}*+}/   # Vector dot product
10%10\- 10%  # (10-ans mod10)mod10
a=           # Compare
\$\endgroup\$
0
\$\begingroup\$

Pyke, 14 13 12 9 bytes

2%2*+sT%!

Try it here!

2%        -      input[::2]
  2*      -     ^ * 2
    +     -    input + ^
     s    -   sum(^)
      T%  -  ^ % 10
        ! - not ^

Thanks Mr. Xcoder for saving 3 bytes!

\$\endgroup\$
1
  • \$\begingroup\$ 10 bytes: 2%2*+s10%! \$\endgroup\$
    – Mr. Xcoder
    Nov 15, 2017 at 19:53
0
\$\begingroup\$

C (gcc), 54 by pizzapants184 51 bytes

c;i;f(x){for(i=3,c=0;x;x/=10)c+=(i^=2)*x;c=c%10<1;}

Try it online!

This answer heavily builds upon the answer of pizzapants184, but improves the bytecount by 3. i would have commented, but rep is below 50. The 3 bytes are removed, by replacing i=0 (...) (1+2*i++%4) with i=3 (...) (i^=2).

\$\endgroup\$
0
\$\begingroup\$

R, 45 bytes 42 bytes

x=scan();(140-sum(x[-8]*c(3,1)))%%10==x[8]

Try it online!

Explanation:

140-         #the largest value possible is 135 (all 9's)
sum( 
  x[-8]      #drop last value from input vector
     *c(3,1) #multiply by a automatically replicating vector of 3,1
)
  %%10       #modulo 10
== x[8]      #compare to the checksum
\$\endgroup\$
0
\$\begingroup\$

GolfScript, 16 bytes

0\~{\3*++}4*10%!

Try it online!

Example Input

2 0 3 7 8 2 4 0

Output:

1

How it Works

Takes a string of 8 digits separated by spaces. For convenience I have included a header which automatically adds spaces to the input.

0\                          - Add zero to stack and place under input
  ~                         - Dump digits in input string onto stack
   {     }4*                - Loop 4 times.
    \                       - Swap top two indices of stack
     3*                     - Multiply by three
       ++                   - Add twice
            10%             - Modulo 10
               !            - Logical(?) not
\$\endgroup\$
0
\$\begingroup\$

PHP, 50 bytes

while($c++<8)$s+=$argv[$c]*($c&1?3:1);echo$s%10<1;

Run with -nr, provide digits as separate command line arguments or try it online.

\$\endgroup\$
0
\$\begingroup\$

APL (Dyalog Unicode), 36 bytes

f←{0=10∣+/⍵+2×+/⍵×8⍴0 1}

Try it online!

I just copy and modify (because that formula it seems wrong) the above Excel solution....

\$\endgroup\$
0
\$\begingroup\$

Z80 Assembly, 22 bytes

; INPUT:
;   HL = a memory location storing barcode as a sequence of integers
; OUTPUT:
;   flag Z signals that barcode is valid, NZ signals invalid barcode

CheckBarcode:
        xor a : ld bc,7*256+%10101010       ; B is the number of loop iterations
                                            ; bits of C say when factor 3 is to be used
AddLoop:
        sub (hl) : rl c : jr nc,Times1      ; negative checksum computation
Times3: sub (hl) : sub (hl)
Times1: inc hl : djnz AddLoop

        jr z,Check                          ; the ugly line to deal with 00000000

Rem:    add 10 : jr nc,Rem                  ; add 10s until the answer is non-negative...

Check:  cp (hl) : ret                       ; ...and compare it with 8th digit!

This task fits into 8-bit assembly quite well.

\$\endgroup\$
0
\$\begingroup\$

Tcl, 89 bytes

proc C L {lmap c $L {incr t [expr [incr i]%8?$i%2?3*$c:$c:0]}
expr [lindex $L 7]==-$t%10}

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Tcl, 93 bytes

proc C s {expr ([regsub -all (.)(.) [string repl $s 7 7 0] {-3*\1-\2}])%10==[string in $s 7]}

Try it online!

Will golf it more later!

\$\endgroup\$
0
\$\begingroup\$

Jelly, 17 bytes

Ṗµ3,1ṁ×⁸S⁵a%⁵⁼³Ṫ¤

Try it online!

Explanation:

Ṗµ                 take off the last element
  3,1ṁ             repeat [3, 1] to the same length as the input without the last element
      ×⁸           multiply together
        S          sum
         ⁵a        abs(10 - sum)
           %⁵      mod 10
              ³Ṫ¤  the last element of the original input
             ⁼     are they equal?
\$\endgroup\$
0
\$\begingroup\$

05AB1E, 6 bytes

ιO3βTÖ

Try it online! Beats all other answers. Takes input as a list of digits with leading zeros.

ιO3βTÖ  # full program
     Ö  # is...
        # (implicit) list of...
 O      # sum...
        # (implicit) s...
 O      # of...
        # (implicit) each element of...
   β    # list of base-10 values of base...
  3     # literal...
   β    # digits of...
        # implicit input...
ι       # split into pieces of...
        # (implicit) 2...
ι       # with each digit of each element concatenated with digits in corresponding indices in other elements...
   β    # in decimal...
     Ö  # divisible by...
    T   # 10...
     Ö  # ?
        # implicit output
\$\endgroup\$
1
2

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.