Calcular um dígito de verificação usando o algoritmo Damm


17

Existem algoritmos populares de dígito de verificação, como Luhn, e outros bons , por exemplo, o algoritmo Damm. A única razão possível por trás da popularidade de algoritmos como o Luhn é que existem implementações de código deles. Isso significa que nós, como comunidade, temos o poder de mudar o mundo, fornecendo implementações eficientes de algoritmos melhores.

Portanto, esse desafio é mudar o mundo escrevendo uma função ou um programa completo no seu idioma de escolha que calcula um dígito de verificação usando o algoritmo Damm . A resposta com o menor número de caracteres (não bytes) será escolhida como vencedora em algumas semanas. Observe que todas as funções de ajuda e a declaração da tabela de operações devem ser incluídas na contagem de caracteres. Em caso de empate, a resposta mais popular será escolhida.

Esse algoritmo gira em torno de uma tabela de operações que deve ser um quase-grupo fracamente totalmente anti-simétrico da ordem 10. A tabela de operações que pode ser encontrada no artigo da Wikipedia sobre o algoritmo Damm é a que deve ser usada neste desafio. Para completar, vou reproduzi-lo abaixo:

    |   0   1   2   3   4   5   6   7   8   9
----+----------------------------------------
0   |   0   3   1   7   5   9   8   6   4   2
1   |   7   0   9   2   1   5   4   8   6   3
2   |   4   2   0   6   8   7   1   3   5   9
3   |   1   7   5   0   9   8   3   4   2   6
4   |   6   1   2   3   0   4   5   9   7   8
5   |   3   6   7   4   2   0   9   5   8   1
6   |   5   8   6   9   7   2   0   1   3   4
7   |   8   9   4   5   3   6   2   0   1   7
8   |   9   4   3   8   6   1   7   2   0   5
9   |   2   5   8   1   4   3   6   7   9   0

Em resumo (para detalhes, consulte o artigo da Wikipedia ) o algoritmo funciona da seguinte maneira:

  1. Você começa com uma lista de dígitos a serem processados ​​e um dígito intermediário definido como 0.
  2. Para cada dígito da lista, você calcula um novo dígito intermediário usando o dígito como índice da coluna e o dígito intermediário anterior como o índice da linha.
  3. O dígito intermediário final é o dígito de verificação. Se você estiver validando um número que já possui um dígito de verificação adicionado, o dígito intermediário final será 0 se o número for válido.

Seu programa ou função deve aceitar uma sequência que possa conter caracteres exceto nulo, mas deve se preocupar apenas com os dígitos da sequência. Ele deve imprimir (se um programa) ou retornar (se uma função) a sequência original com o dígito de verificação calculado anexado. Se você optar por escrever um programa, o programa poderá aceitar a entrada como argumento ou como entrada padrão. Se a sequência de entrada estiver vazia ou não contiver nenhum dígito, você deverá retornar ou acrescentar um zero.

Alguns exemplos:

Input       |   Output
------------+-------------
42          |   427
427         |   4270
2 to 2      |   2 to 29
23 42 76-   |   23 42 76-5
-           |   -0

Estou ansioso para ver as entradas de Piet reivindicando a vitória.
Savic

Respostas:


3

Pitão, 49 caracteres

+z`u@sm>+0jCdT_6"Ľ򒉲򭉟񶯆𐱩򐞆󰆂򕟐򑽌򵋏󇋽򯴆󚙈𱑂񞑼쵥񪨶"+*TGvH:z"\D"k0

Contém que Deus sabe quais caracteres, então aqui está um programa Python3 para gerar o programa acima com precisão em sua máquina:

N = 317598642709215486342068713591750983426612304597836742095815869720134894536201794386172052581436790
M = 1000000
l = []
while N:
    l.insert(0, N % M)
    N //= M

n = "".join(chr(c) for c in l)

s = '+z`u@sm>+0jCdT_6"' + n + '"+*TGvH:z"\D"k0'

with open("golf.pyth", "wb") as f:
    f.write(s.encode("utf-8"))

print("Program length is {} characters.".format(len(s)))

Explicação:

+z`                                     Output the input followed by a
                                        stringified...
   u                         :z"\D"k0   Reduction starting with 0 of digits
                                        in input...
    @                  +*TGvH           Indexing ... by 10*prev + int(next).
     sm         "ZALGO"                 Sum all digits created by ... over the
                                        unicode garbage.
       >+0     6                        Prepend 0 if needed to...
          jCdT_                         Codepoint converted to sequence of
                                        digits.

3

CJam, 54 caracteres

q_o{A,s&},{~0"끼´慜䪝膞䝮芜㮜ꡞ靓渏縰蒆㣉倔쵶"2G#bAb+A/T==:T;}/T

Há um caractere não imprimível, portanto, convém usar o link permanente abaixo.

Teste aqui.

Explicação

O dígito intermediário está sendo rastreado T, que CJam inicializa como 0.

q_o                                  "Read STDIN, duplicate it and print it.";
   {A,s&},                           "Filter out all non-digit characters.";
          {                     }/   "For each digit character.";
           ~                         "Eval to get the digit itself.";
            0                        "Push a zero.";
             "..."2G#b               "Push that long string and interpret the character
                                      codes as the digits of a base-2^16 number.";
                      Ab+            "Get base-10 digits and prepend the 0.";
                         A/          "Split into rows of 10.";
                           T=        "Select row based on interim digit.";
                             =       "Select column based on current digit.";
                              :T;    "Store in T and discard.";
                                   T "Push the interim digit to be printed.";

3

Python 3, 149 141 138 caracteres

import re
l=""
for c in"ĽᝢႮ⏿ዿၮ∉᜝Ꮺൢ៫Njẜ᳼╭᛭ᰡඡᆸߡⓞ᠜ȍ῏᪆":l+="%04d"%ord(c)
def D(b):
 a="0"
 for i in re.sub("\D","",b):a=l[int(a+i)]
 return b+a

Exemplos:

 Input | Output
-------+--------
    42 | 427
   427 | 4270
2 to 2 | 2 to 29
   123 | 1234
  1234 | 12340
     - | -0

Agradecemos a @MegaTom e @Sieg por ajudar a remover um total de 11 caracteres


2
10 * int (a) + int (i) é int (a + i), não é?
MegaTom

Bom ponto! Obrigado, isso economiza 5 caracteres.
precisa

11
Para seguido por uma única declaração não precisa de uma nova linha no meio. (-3)
ver

2

Ruby, 149 caracteres

i="0";t="0#{'2uleblnnz0nbpv3kqkaufbjqebm57jdj6ubaba1mc2fyucqff69tbllrcvw393li'.to_i 36}";puts(gets.chomp.each_char{|c|i=(c=~/\d/?t[(i+c).to_i]:i)}+i)

Testado em repl.it


2

J, 117 bytes

Contém apenas ascii imprimíveis. (Eu tive dificuldade com J e unicode.) Gera a tabela de transição a partir dos índices de permutação das linhas.

3 :'y,":(((_4(87)&#:inv\40-~a.i.''(3/3+wGf*Dl:(zaW+Hhw*(1p+;~.,y>m-<MZ)JCs'')A.i.10){~<@,~)/|.0,(#~10>])(1":i.10)i.y'

Uso:

   damm=.3 :'y,":(((_4(87)&#:inv\40-~a.i.''(3/3+wGf*Dl:(zaW+Hhw*(1p+;~.,y>m-<MZ)JCs'')A.i.10){~<@,~)/|.0,(#~10>])(1":i.10)i.y'

   damm '23 42 76-'
23 42 76-5

   damm ''
0

Experimente online aqui.


2

Haskell, 131 caracteres

import Data.Char
f n=n++(show$foldl(\x y->read[('0':(show.ord=<<"౧⚈ક×ዿၮ∉ɏᵕₖ᧔İɕSʢ凞㷽ᰡ衎텴䘗↩倭῏᪆"))!!(x*10+y)])0[read[i]|i<-n,isDigit i])

Execução de teste:

> mapM_ (putStrLn.f) ["42", "427", "2 to 2", "23 42 76-", "-"]
427
4270
2 to 29
23 42 76-5
-0

0

k, 36 caracteres

/ declare quasi-group  
M:"H"$'"0317598642709215486342068713591750983426612304597836742095815869720134894536201794386172052581436790"

/ declare function
  f:{x,$0{M y+10*x}/"H"$'x@&x in .Q.n}

/ get length of function
  #$f
36

/ execute function against test input
  .q.show f@'{x!x}("42";"427";"2 to 2";"23 42 76-";,"-")
"42"       | "427"
"427"      | "4270"
"2 to 2"   | "2 to 29"
"23 42 76-"| "23 42 76-5"
,"-"       | "-0"

q, 40 caracteres (implementação equivalente a k)

 f:{x,string 0{M y+10*x}/"H"$'x inter .Q.n}

11
Devo dizer que admiro o uso de uma brecha questionável nas regras, mas realmente preciso esclarecer as regras para forçar a inclusão da declaração do quase-grupo e a declaração de qualquer tipo de função auxiliar na contagem de caracteres .
Fors
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.