Barcodegolf: Gere UPC de um número

12

Hoje em dia, praticamente todas as lojas usam códigos de barras UPC ( Universal Product Code ) para simplificar o processo de check-out. Se o nome não significa nada para você, você certamente reconhecerá como eles são:

Exemplo de código de barras UPC-A

Formato

O sistema mais comum é o UPC-A, que usa 12 dígitos para representar cada produto específico. Cada dígito é codificado em uma série de faixas em preto e branco para permitir que as máquinas leiam o código, com um comprimento de sete bits. Há um total de 11 bits de padrões que indicam o início, o meio e o fim do código de barras. Isso resulta em um comprimento total de código de barras de 12 × 7 + 11 = 95 bits. (A partir de agora, quando binário for usado para se referir à cor de cada bit, 0será branco e 1preto).

O começo e o fim têm um padrão de 101. Os dígitos são então divididos em 2 grupos de 6 e codificados como mostrado abaixo, com um padrão 01010entre os grupos esquerdo e direito. Esta tabela lista o padrão para cada número. Observe que o padrão é diferente dependendo se o dígito estiver no lado direito ou esquerdo (Isso permite que o código de barras seja lido de cabeça para baixo). No entanto, o padrão da direita é o oposto (troque o preto pelo branco e vice-versa) do da esquerda.

Tabela de conversão UPC

Se você não conseguir ver a imagem acima, esse é o equivalente binário de cada número.

#   Left    Right
0   0001101 1110010
1   0011001 1100110
2   0010011 1101100
3   0111101 1000010
4   0100011 1011100
5   0110001 1001110
6   0101111 1010000
7   0111011 1000100
8   0110111 1001000
9   0001011 1110100

Exemplo

Digamos que você tenha o UPC 022000 125033. (Esses não são números aleatórios. Deixe um comentário se você descobrir o significado deles.) Você começa com este padrão que é igual em todos os códigos de barras:

101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx01010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx101

Para os dígitos, você substitui cada um pela codificação correspondente do lado (esquerdo ou direito) em que está. Se você ainda estiver confuso, veja a imagem abaixo.

Repartição da codificação UPC

Aqui está a saída em binário com |tubos que separam as peças.

101|0001101|0010011|0010011|0001101|0001101|0001101|01010|1100110|1101100|1001110|1110010|1000010|1000010|101

Desafio

Escreva um programa que emita o código de barras UPC-A para a entrada do usuário. As dimensões da imagem devem ter 95 × 30 pixels, com cada "bit" com um pixel de largura e 30 pixels de altura. As listras pretas estão inseridas rgb(0, 0, 0)e as brancas são consistentemente transparentes ou rgb(255, 255, 255).

Notas

  • Pegue a entrada do stdin ou da linha de comando ou escreva uma função que use uma string ou um número inteiro (observe que a entrada pode ter zeros à esquerda e a maioria dos idiomas os remove ou converte o número em octal).
  • Envie a imagem de uma das seguintes maneiras:
    • Salve-o em um arquivo com um nome e formato (PNG, PBM etc.) de sua escolha.
    • Exibi-lo na tela.
    • Envie seus dados de arquivo para stdout.
  • Você não pode usar bibliotecas ou componentes internos que geram códigos de barras ( estou olhando para você, Mathematica ), embora você possa usar bibliotecas de imagens ou gráficos.
  • O último dígito de um UPC geralmente é um dígito de verificação , mas para esses fins, você não precisa se preocupar com isso.

Exemplos

Aqui estão mais alguns exemplos para testar seu código. A saída binária também é fornecida por conveniência.

Entrada: 012345678910

Resultado:

10100011010011001001001101111010100011011000101010101000010001001001000111010011001101110010101

Entrada: 777777222222

Resultado:

10101110110111011011101101110110111011011101101010110110011011001101100110110011011001101100101

Pontuação

Este é o código de golfe , portanto, o envio mais curto (em bytes vence). O desempatador vai para o primeiro post.

NinjaBearMonkey
fonte
Mmm ... fruta suculenta.
Dennis
A entrada pode ser recebida como uma matriz? por exemplo["777777","222222"]
Downgoat
@vihan Hmm, acho que é um pouco exagerado. Eu vou dizer não.
NinjaBearMonkey
2
Código de barras UPC digitalizado pela primeira vez!
Dennis
1
Isto é brilhante. Os códigos de barras sempre me fascinou
Beta Decay

Respostas:

3

CJam, 58 57 bytes

'P1N95S30N[A1r:~"rflB\NPDHt":i2fbf=:R6<::!0AAR6>A1]s30*S*

Imprime um BitMap portátil (ASCII) em STDOUT. Experimente online.

Como funciona

'P1N95S30N     e# Push 'P', 1, '\n', 95, ' ', 30 and '\n'.

[              e#
  A1           e#   Push 10 and 1.
  r            e#   Read a token from STDIN.
  :~           e#   Caluate each character ('0' -> 0).
  "rflB\NPDHt" e#   Push that string.
  :i           e#   Cast each character to integer.
               e#   This pushes [114 102 108 66 92 78 80 68 72 116].
  2fb          e#   Convert each integer to base 2.
               e#   This pushes the representations for the right side.
  f=           e#   Select the proper representation of each digit in the input.
  :R           e#   Save the result in R.
  6<           e#   Keep the representations of the first six digits.
  ::!          e#   Negate each binary digit to obtain the "left" representation.
  0AA          e#   Push 0, 10, 10.
  R6>          e#   Push the representations of the last six digits.
  A1           e#   Push 10, 1.
]s             e# Collect in an array and cast to string.

30*            e# Repeat the resulting string 30 times.
S*             e# Join it, using spaces as separators.
Dennis
fonte
4

Rev 1 BBC BASIC, 155 caracteres ASCII, tamanho de arquivo tokenizado 132 bytes

INPUTn$
FORi=91TO185p=i MOD2j=i MOD47IFj<42j+=i DIV141*42p=(j>41EORASC(MID$("XLd^bFznvh",VAL(MID$(n$,j/7+1,1))+1)))>>(j MOD7)AND1
IFp LINEi*2,60,i*2,0
NEXT

salvou alguns bytes incorporando o deslocamento de 43 no iloop. Para evitar a quebra, MOD247 adicionais foram adicionados, totalizando 90.

Isso move o código de barras para mais longe da origem, como mostrado, se isso for aceitável:

insira a descrição da imagem aqui

Rev 0 BBC BASIC, 157 caracteres ASCII, tamanho de arquivo tokenised 137 bytes

INPUTn$
FORi=1TO95p=i MOD2j=(i+43)MOD47IFj<42j+=i DIV51*42p=(i>50EORASC(MID$("XLd^bFznvh",VAL(MID$(n$,j/7+1,1))+1)))>>(j MOD7)AND1
IFp LINEi*2,0,i*2,60
NEXT

Faça o download do intérprete em http://www.bbcbasic.co.uk/bbcwin/bbcwin.html

O modo de tela padrão é texto em preto sobre fundo branco. Isso difere do original BBC BASC.

Versão ungolfed com impressão de teste

O cálculo de uma barra de dados depende IF j<42e tudo deve ser feito em uma linha. Na versão não destruída, isso é feito em três etapas. Na versão golfed, os dois últimos passos são combinados em uma única expressão enormep=...

Eu tive que reverter a ordem dos bitmaps, porque eu costumava >>(j MOD 7)acessar os bits, o que significa que eu acessava o bit menos significativo primeiro. Feito isso, todos os bitmaps esquerdos estão convenientemente no intervalo ASCII.

  INPUTn$
  FOR i=1TO95                            :REM iterate through 95 bars
    p=i MOD2                             :REM calculate colour of format bar 1=black
    j=(i+43)MOD47                        :REM repetition is 42 data bars + 5 format bars. offset and modulo. if j<42 it is a data bar and we must change p.

    REM if i DIV 51=1 we are in the second half, so add 42 to j. Find the bitmap for left hand value, from character j/7 of the input.
    REM i>50 evaluates to false=0 true=-1. XOR this with p to invert bitmap for right hand side. Shift and AND with 1.  
    IF j<42 j+=i DIV51*42:p=ASC(MID$("XLd^bFznvh",  VAL(MID$(n$,j/7+1,1))+1  )) :p=(i>50EORp)>>(j MOD7) AND 1

    IF j MOD 7 = 0 PRINT                  :REM format test output
    PRINT ;p;                             :REM print test output
    IF p LINEi*2-2,0,i*2-2,60             :REM if p=1 plot bar. there are 2 logical units for each pixel.
  NEXT

Saída típica, versão não destruída, com saída de teste

insira a descrição da imagem aqui

Level River St
fonte
2

JavaScript ES6, 225 bytes

s=>`P1
30 90
`+([...`101${(f=(z,j)=>[...j].map(i=>`000${z[+i].toString(2)}`.slice(-7)).join``)([13,25,19,61,35,49,47,59,55,11],s[0])}01010${f([114,102,108,66,92,78,80,68,72,116],s[1])}101`].join` `+`
`).repeat(30).slice(0,-1)

Poderia ser mais curto com os recursos do ES7, mas não tenho certeza sobre o suporte deles, por isso estou mantendo o ES6. Também estou assumindo uma entrada como uma matriz. A saída é um arquivo PBN . Há também muito golfe para fazer.

Se fiz algo errado, deixe um comentário e eu vou corrigi-lo

Downgoat
fonte
Eu acho que você quer dizer arquivo PBM ...
sergiol
2

Perl, 153 bytes

substr($_=<>,6,0)=A;y/0-9A/=ICmSa_kg;0/;$s.=sprintf("%07b",-48+ord$1^($k++>6?127:0))while/(.)/g;$s=~s/0{7}/01010/;print"P1
95 30
".('101'.$s.'101'.$/)x30

Copie para um arquivo barcode.perl e execute como este:

perl barcode.perl > output.pbm

depois insira o número do código de barras.

Explicação:

Os padrões de bits para os dígitos do código de barras são armazenados em uma string e substituídos pelos dígitos de entrada usando o y///operador de transliteração Perl . Cada valor na cadeia de substituição possui 48 (ASCII '0') adicionados, para evitar caracteres não imprimíveis. Os dígitos na segunda metade do código de barras são inversos aos da primeira metade.

O padrão central é definido como 0000000 (um padrão que nunca poderia aparecer, codificado como 'A' e depois '0') e depois substituído por 01010, em vez de manipular seu comprimento diferente como um caso especial quando sprinting.

samgak
fonte
1

Oitava, 115 bytes

function b(s)
n='rflB\MPDHt'-0;r=dec2bin(n(s-47)',7)'(:)-48;v=[a=[1 0 1] ~r(1:42)' 0 a r(43:84)' a];v(ones(30,1),:)

Versão multilinhas:

function b(s)
   n='rflB\MPDHt'-0;
   r=dec2bin(n(s-47)',7)'(:)-48;
   v=[a=[1 0 1] ~r(1:42)' 0 a r(43:84)' a];
   v(ones(30,1),:)

né o equivalente ASCII dos códigos de dígitos do lado direito (eram mais fáceis de inserir do que o lado esquerdo, pois eram todos caracteres exibidos). Depois disso, uma conversão decimal para binária direta com algum tipo irritante muda de char para numérico. vconstrói a sequência binária final e depois a repetimos 30 vezes e produzimos para o console.

Exemplo de saída com apenas 2 das 30 linhas mostradas por questões de brevidade:

s = '777777222222';
ans =

 Columns 1 through 30:

   1   0   1   0   1   1   1   0   1   1   0   1   1   1   0   1   1   0   1   1   1   0   1   1   0   1   1   1   0   1
   1   0   1   0   1   1   1   0   1   1   0   1   1   1   0   1   1   0   1   1   1   0   1   1   0   1   1   1   0   1
...

 Columns 31 through 60:

   1   0   1   1   1   0   1   1   0   1   1   1   0   1   1   0   1   0   1   1   1   0   1   1   0   0   1   1   0   1
   1   0   1   1   1   0   1   1   0   1   1   1   0   1   1   0   1   0   1   1   1   0   1   1   0   0   1   1   0   1
...

 Columns 61 through 90:

   1   0   0   1   1   0   1   1   0   0   1   1   0   1   1   0   0   1   1   0   1   1   0   0   1   1   0   1   1   0
   1   0   0   1   1   0   1   1   0   0   1   1   0   1   1   0   0   1   1   0   1   1   0   0   1   1   0   1   1   0
...

 Columns 91 through 94:

   0   1   0   1
   0   1   0   1
...

Saída comprimida:

1010111011011101101110110111011011101101110110101110110011011001101100110110011011001101100101

Originalmente, eu pretendia exibir a imagem, mas o envio para o console me salvou 9 bytes. Você pode exibir os resultados usando imshow, mas eles são exibidos 1em branco e 0em preto; portanto, é necessário inverter os dados primeiro.

imshow(~v(ones(30,1),:));
taça
fonte
1

Cobra - 218

do(s='')
    print'P1\n95 30'+('\n'+('101'+(for n in 12get Convert.toString(if((t=139+[2,14,8,50,24,38,36,48,44,0][s[n]to int-48])and n<6,t,~t),2)[-7:]+if(n-5,'','01010')).join('')+'101').toCharArray.join(' ')).repeat(30)
Furioso
fonte
1

Javascript ES6, 199 bytes

n=>`P1 95 30 `+(101+(g=(a,...s)=>(``+1e12+n).slice(...s,-6).split``.map(m=>(1e3+a[m].toString(2)).slice(-7)).join``)(a=[13,25,19,61,35,49,47,59,55,11],-12)+`01010`+g(a.map(i=>~i&127))+101).repeat(30)
Dendrobium
fonte
"o envio mais curto (em bytes ganha)". Você precisa contar seu código em bytes; portanto, se você estiver usando Unicode, isso significa 2 bytes por caractere, eu acho.
mbomb007
Bah, sim, eu acho que a minha resposta un-unicoded é mais curto, então
Dendrobium
0

Python 2, 174 bytes

Eu sei que pode ser jogado golfe.

A string sé a tabela binária na pergunta com a metade esquerda da tabela como a metade esquerda da string. Os valores são ANDed por 63 primeiro se estiver na metade direita (remova o primeiro 1), depois deslocados por 63 para ser ASCII imprimível.

ERRO: Atualmente tentando corrigir um erro. A saída do primeiro exemplo está desativada em um dígito do código de barras. Se você descobrir, me avise, por favor.

I=raw_input()
s="LXR|bpnzvJcekA[MOCGs"
x="".join(format(ord(s[int(I[i])+10*(i>5)])-63|1+63*(i>5),'07b')for i in range(len(I)))
L=len(x)/2
print"101%s01010%s101"%(x[:L],x[L:])
mbomb007
fonte
Ou, eu fiz ter feito o desafio completamente errado. Deixe-me saber nesse caso também.
mbomb007