Question

The challenge

The shortest code by character count to draw an ASCII representation of a Code 39 bar code.

Wikipedia article about Code 39: http://en.wikipedia.org/wiki/Code_39

Input

The input will be a string of legal characters for Code 39 bar codes. This means 43 characters are valid: 0-9 A-Z (space) and -.$/+%. The * character will not appear in the input as it is used as the start and stop characters.

Output

Each character encoded in Code 39 bar codes have nine elements, five bars and four spaces. Bars will be represented with # characters, and spaces will be represented with the space character. Three of the nine elements will be wide. The narrow elements will be one character wide, and the wide elements will be three characters wide. A inter-character space of a single space should be added between each character pattern. The pattern should be repeated so that the height of the bar code is eight characters high.

The start/stop character * (bWbwBwBwb) would be represented like this:

                       #   # ### ### # 
                       #   # ### ### # 
                       #   # ### ### # 
                       #   # ### ### # 
                       #   # ### ### # 
                       #   # ### ### # 
                       #   # ### ### # 
                       #   # ### ### # 
                       ^ ^ ^^ ^ ^ ^ ^^^
                       | | || | | | |||
           narrow bar -+ | || | | | |||
           wide space ---+ || | | | |||
           narrow bar -----+| | | | |||
         narrow space ------+ | | | |||
             wide bar --------+ | | |||
         narrow space ----------+ | |||
             wide bar ------------+ |||
         narrow space --------------+||
           narrow bar ---------------+|
inter-character space ----------------+
  • The start and stop character * will need to be output at the start and end of the bar code.
  • No quiet space will need to be included before or after the bar code.
  • No check digit will need to be calculated.
  • Full ASCII Code39 encoding is not required, just the standard 43 characters.
  • No text needs to be printed below the ASCII bar code representation to identify the output contents.
  • The character # can be replaced with another character of higher density if wanted. Using the full block character U+2588, would allow the bar code to actually scan when printed.

Test cases

Input:
ABC
Output:
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 
#   # ### ### # ### # #   # ### # ### #   # ### ### ### #   # # #   # ### ### # 

Input:
1/3
Output:
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 
#   # ### ### # ### #   # # ### #   #   # #   # ### ###   # # # #   # ### ### # 

Input:
- $     (minus space dollar)
Output:
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 
#   # ### ### # #   # # ### ### #   ### # ### # #   #   #   # # #   # ### ### # 

Code count includes input/output (full program).

Was it helpful?

Solution

J, 102 characters

8#,:' #'{~,0,.~#:(3 u:'䝝啕啕啕䑅儑啕啕啕啕䗝䔑啕䕷煝䑑凝瑗屗眕凗瑵屵具瑝屝啕啕啕啕啕啕啕甗崗睅圗病巅呷甝崝圝畇嵇睑均痑巑嗇畱嵱坱煗䝗燕䗗煵䝵'){~32-~a.i.'*'(,,[)

Explanation. Read from the bottom up.:

8#,:         NB. Copy 8 times
' #'{~       NB. Turn binary 0 and 1 into space and #
,            NB. Link the array into a list
0,.~         NB. Append a 0 to the end of each row of the array.
#:           NB. Turn the list of numbers into a binary array where each row is the base-2 representation of the corresponding number
(3 u:'䝝啕啕啕䑅儑啕啕啕啕䗝䔑啕䕷煝䑑凝瑗屗眕凗瑵屵具瑝屝啕啕啕啕啕啕啕甗崗睅圗病巅呷甝崝圝畇嵇睑均痑巑嗇畱嵱坱煗䝗燕䗗煵䝵') NB. Turn this wchar string into a list of ints in range 0-65535.
{~           NB. Select numbers from the string-list whose indices are...
32-~         NB. ... 32 less than ...
a.i.         NB. ... the ascii values of ...
'*'(,,[)     NB. ... the input string with a '*' on either side!

OTHER TIPS

Ruby (1.9) - 121 132 141 166 170 289 295

Hats-off to David

puts"*#{$_}*
".tr(" --9*$+%A-Z","䝝䕷煝䑑凝瑗屗眕凗瑵屵具瑝屝䗝䑅䔑儑甗崗睅圗病巅呷甝崝圝畇嵇睑均痑巑嗇畱嵱坱煗䝗燕䗗煵䝵").gsub(/./){|c|c.ord.to_s(2).tr"01"," #"}*8


echo "ABC" | ruby -ne 'puts"*#{$_}*
".tr(" --9*$+%A-Z","䝝䕷煝䑑凝瑗屗眕凗瑵屵具瑝屝䗝䑅䔑儑甗崗睅圗病巅呷甝崝圝畇嵇睑均痑巑嗇畱嵱坱煗䝗燕䗗煵䝵").gsub(/./){|c|c.ord.to_s(2).tr"01"," #"}*8'

Only stores the 44 characters required and uses Ruby's transliteration function to map these

<space>
<-> to <9>
<*>
<$>
<+>
<%>
<A> to <Z>

to the encoded values.

Python, 304 characters

No fancy Unicode compression. Only trick is to reorder the characters to maximize overlap. My first Python program.

b="BWbwbwBwbWBwbwbwBWbwBwbwbWBwbwBwbWbwBwbwBWbwbwBWBwbwbwbWBwBwbwbWbwBwBwbWbwbwBwBWbwbwbwBWBwbWbWbWbwbWbWbWb"
s=t=""
for x in"*"+raw_input()+"*":
 i=".NI5VRD9YLH4 OB8XSE2?J6WKG0ZMA7*PC1-TF3UQ????$/+%".find(x)*2
 s+=b[i:i+9]+"w"
for x in s:t+=["#"," ","###","   "]["bwBW".find(x)]
for k in b[-8:]:print(t)

Assembler

Assembles to 220 bytes.

    mov di,ds
    mov al,42
    call a3
    mov dh,[80h]
    mov si,82h
 a1:lodsb
    call a3
    dec dh
    jnz a1
    mov al,42
    call a3
    mov ax,2573
    stosw
    mov al,36
    stosb
    mov cl,8
 a2:mov dx,ds
    mov ah,9
    int 21h
    loop a2
 a3:sub al,97
    cmp al,26
    ja a4
    sub al,32
 a4:mov bx,a6-3
 a8:add bx,3
    cmp bx,a7
    jae ret
    cmp al,[bx]
    jne a8
    mov bp,[bx+1]
 a5:rcr bp,1
    mov al,36
    sbb al,0
    and al,35
    stosb
    or bp,bp
    jnz a5
    mov al,32
    stosb
    ret
 a6:dd 0D05DC5CFh,01DD17517h,05477D275h,0D475C5D3h,01DD55717h,07745D657h,0D85D17D7h,057E05D1Dh
    dd 0745DE174h,0E35177E2h,0D7E47475h,051DDE551h,0E77715E6h,05DE85C57h,05C75E95Ch,0EB7157EAh
    dd 077EC715Dh,07175ED45h,0EF45D7EEh,0D5F045DDh,04757F171h,0F3475DF2h,047F44775h,07571F575h
    dd 0F755C7F6h,047F875D1h,05771F957h,0CD7751CCh,071BF5D47h,05111C35Dh,0CA4511CEh,045C44451h
    dd 05DD1C944h
 a7:

Not much scope for doing clever tricks here.

Python 3.1, without Unicode (213 215 223 240 248 249 chars)

o=""
for c in"%r"%input():
 u="W3YZ56C$EF. 89'0HIJM/OP+%RSTUV12X4ABD-7GKLNQ".find(c);n=sum(b"))&&&,(*&2&&&)),&/8(*&1)<&/V&&&)),&/5);D&/S"[u:])-930+35*u
 while n:o+="###"[n%2*2:]+"   "[n&2:];n>>=2
print((o+"\n")*8)

Explanation:

The code 39 sequence is encoded into a base-4 number (left-most = least significant) with:

  • bw → 3
  • Bw → 2
  • bW → 1
  • BW → 0

The sequence is then sorted, e.g.

20333   Q
21233   N
21323   L
...

The difference of adjacent entries are taken, giving a list like [48, 12, 3, …]. Then 35 is added to this list to ensure the numbers fall in the ASCII range. This gives the "))&&&,…" string.

This code also has taken advantaged of the * will not appear in the input, so we may replace it by any invalid character, including '. In CPython repr("ABC") == "'ABC'", so we could get rid of 2 characters.

Python 3.1, with Unicode (154 158 chars)

Based on the J solution, taking advantage of the "The character # can be replaced with another character of higher density if wanted" rule, by defining density as area of dark parts divided by the smallest bounding rectangle of the glyph. :)

print((''.join(" #"[int(c)]for d in"%r"%input()for c in bin(2*ord("䝝啕啕啕䑅儑啕䗝啕啕啕䔑啕䕷煝䑑凝瑗屗眕凗瑵屵具瑝屝啕啕啕啕啕啕啕甗崗睅圗病巅呷甝崝圝畇嵇睑均痑巑嗇畱嵱坱煗䝗燕䗗煵䝵"[ord(d)-32]))[2:])+"\n")*8)

Python (2.6) -- 430 312 302 characters

Third go at the problem, still room for improvement. Character count by wc -m.

#coding:UTF8
k=""
for c in"*%s*"%raw_input():
 i=" $*.02468BDFHJLNPRTVXZ%+-/13579ACEGIKMOQSUWY".find(c)*2
 for j in"%05d%s"%tuple(map(ord,u"ಊҺ௖ூ௄Һ姢ҺЈҺӎϴЈϴӐϲ刦ҺҺ௄ϴ௄Ҽூ划ಊϴಊҺЈϴЈҼІ划ӎϴӎಊϴ௄ϴಌϲІ௖ூ௖ூҼ௖І刦ϴ勮ϲ刨ϲІҼӎҺ划௄勚ூ刔ூϲಌҺಊ划Ј勚І刔ІϲӐҺӎ姢ϴ媪ϲ姤ϲ"[i:i+2])):k+=["#"," ","###","   "][int(j)]
 k+=" "
exec"print k;"*8

Lua, 318 Characters

z={"1358ACEHKMORUWY.","UVWXYZ-. $/+*","2369BCFILMPSVWZ ","0123456789$/%","0456DEFJNOPTXYZ*","ABCDEFGHIJ$+%","0789GHIJQRST-. *","KLMNOPQRST/+%","1247ABDGKLNQUVX-",""}i="*"..(...).."*"o=""for c in i:gfind(".")do for j=1,10 do o=o..((j%2==0 and" "or"#"):rep(z[j]:find(c,1,true)and 3 or 1))end end for j=1,8 do print(o)end

I don't expect to win any code-golf questions with Lua, so I don't feel bad answering my own challenge here. It was also using a different encoding I thought might be interesting to others.

Other observations

After looking closely at the encoding, it looks as if there may be a way to dispense with table look-up, and compute the bar code's encoding directly. However, I found that my attempts to build the computations took more code than the table. (This may not be the case in other languages.)

Having divided the characters into groups that indicated where the wide bars and spaces were, I saw some interesting patterns. It seems that there is only one wide space for 40 of the characters, with $/+% being exceptions (they each have three spaces.) The 40 characters being split with 10 in each slot. And, there are two wide bars for the same 40 characters. The wide bars seem to have a binary encoding with the last bar being a parity bit. The bar's bit patterns being 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 where the numbers having more then 2 bits set being avoided.

1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ-._*
1 3 5  8  A C E  H  K M O  R  U W Y  .   1010100100
 23  6  9  BC  F  I  LM  P  S  VW  Z  _  0110010010
   456   0   DEF   J   NOP   T   XYZ   * 0001110001
      7890      GHIJ      QRST      -._* 0000001111
12 4  7   AB D  G   KL N  Q   UV X  -    1101001000 --> Parity

I guess it is a challenge for another day to see if the bar codes could be encoded without look-up tables.

I've done code to work with code 39 barcodes on embedded systems. There are two styles of codes, which I think of as the 39 "regular" codes and the four "oddballs". The regular codes have one of ten patterns of bar widths (two wide three narrow), and one of four patterns of space widths (one wide three narrow). The oddballs have five narrow bars and one of four patterns of bar widths (three wide one narrow). To render a barcode with compact code, convert the character into a number 0-39 (for normal codes), or 40, 50, 60, or 70 for "oddballs". Then divmod 10. The upper digit will select one of eight patterns of space widths; if the upper digit is three or less the lower digit will select one of ten patterns of bar widths. If the upper digit is 4-7, all five bars should be narrow.

The code works out very compactly using a few small lookup tables. Because lookup tables may be compactly represented as strings in source code, approaches with larger lookup tables may have shorter source code (though I think for Code Golf source code size should be counted in bytes using the most favorable coding; an approach with a string of oddball characters that would take three bytes to store in UTF-8 and two bytes for UTF-16 should either be 'charged' 3 bytes each for oddball characters, or two bytes each for all characters, whichever yields a smaller total). An approach which uses a selection of oddball characters that fit entirely within some particular single-byte code page should be charged one byte per character.

spam spam spam spam lovely spam

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top