Codici QR ... e tutto quel Jazz!


18

Questa sarà una sfida relativamente impegnativa nel code-golf.

Input: qualsiasi URL, deve avere il protocollo allegato, ad esempio http://codegolf.stackexchange.com (che sarà il nostro caso di test)

Output: un codice QR generato che rappresenta questo URL che, se scansionato da un dispositivo intelligente, ti porterà a quell'URL sul browser del dispositivo intelligente.

Regole per questo codice-golf

  1. Come al solito, vince il codice più piccolo.
  2. Nessuna risorsa web esterna, librerie o plugin per generare il codice per te. Il tuo codice deve calcolare l'immagine del codice QR.
  3. L'output può essere presentato da un'immagine, generata da HTML5 / CSS3, o anche usando i blocchi Unicode appropriati, o se l'ASCII della tua piattaforma lo ha disponibile, tramite caratteri ASCII che possono formare il codice QR (quest'ultimo è diretto a Commodore 64 Basic, Amiga QBasic, Amstrad Basic, ecc.), Ma deve generare un output del codice QR in modo che io possa scansionare il codice.
  4. Le voci del codice devono essere seguite con l'output generato, o da una schermata dell'output dopo aver eseguito il codice, oppure con un collegamento che mostri l'output (a seconda della situazione più adatta)
  5. Devi testare il tuo codice con l'URL " http://codegolf.stackexchange.com " e segnalare l'output secondo le Regole da 3 a 4.
  6. Devi anche testare il tuo codice con un URL a tua scelta e segnalare l'output secondo le Regole da 3 a 4.

Riferimenti:

1) http://it.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders

2) http://www.pclviewer.com/rs2/calculator.html

3) http://it.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction

4) http://it.wikipedia.org/wiki/QR_code

5) http://www.qrstuff.com/ per ispirazione ...;)



@ace Ben individuato ... questo problema è stato risolto
WallyWest,

1
Dopo aver letto della documentazione, penso che "relativamente impegnativo" sia un eufemismo.
Danny,

Possiamo avere un chiarimento sul significato di "il tuo codice deve calcolare l'immagine del codice QR"? Sto prendendo a dire che noi dobbiamo fare i due punti più importanti nel codice presentato : 1) codifica RS , e 2) il layout del modulo .
Nick T,

regola 3: così è ascii art stampata da un terminale benissimo, o deve andare in un vero file di immagine?

Risposte:


17

Python 3: 974 caratteri [nb]

Batti ancora con il brutto bastone, vedi il taccuino su GH-Gist . Python 3 ha la codifica ASCII-85 integrata, che aiuta con la salsiccia zippata. Gli algoritmi di compressione integrati (LZMA) più avanzati di 3 non sembrano funzionare bene con cose così piccole.

Lo zipping è molto instabile nel cambiare i personaggi, era quasi tentato di scrivere qualcosa che provasse a caso diversi nomi di 1 lettera per le variabili per minimizzare le dimensioni zippate.

Python 2: 1420 1356 1085 1077 caratteri

inserisci qui la descrizione dell'immagine

Ho letto il primo argomento passato quando chiamato, che può essere una stringa lunga fino a 106 caratteri. L'output è sempre un codice QR 5-L versione e una maschera 4, il che significa che è di grandi dimensioni 37x37 moduli e può gestire solo il danno del 5% circa.

Le uniche dipendenze del programma sono numpy(manipolazioni di array) e matplotlib(solo visualizzazione); tutta la codifica Reed-Solomon, l'imballaggio dei dati e il layout del modulo sono gestiti nel codice fornito . Per RS, ho praticamente derubato le funzioni di Wikiversità ... è ancora una specie di scatola nera per me. Ho imparato molto sul QR in ogni caso.

Ecco il codice prima di batterlo con il brutto stick:

import sys
import numpy as np
import matplotlib.pyplot as plt
# version 5-L ! = 108 data code words (bytes), 106 after metadata/packing

### RS code stolen from https://en.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders#RS_generator_polynomial
gf_exp = [1] + [0] * 511
gf_log = [0] * 256
x = 1
for i in range(1,255):
    x <<= 1
    if x & 0x100:
        x ^= 0x11d
    gf_exp[i] = x
    gf_log[x] = i
for i in range(255,512):
    gf_exp[i] = gf_exp[i-255]

def gf_mul(x,y):
    if x==0 or y==0:
        return 0
    return gf_exp[gf_log[x] + gf_log[y]]

def main():
    s = sys.argv[1]

    version = 5
    mode = 4 # byte mode
    dim = 17 + 4 * version
    datamatrix = 0.5 * np.ones((dim, dim))
    nsym = 26

    # PACK
    msg = [mode * 16, len(s) * 16] + [ord(c) << 4 for c in s]
    for i in range(1, len(msg)):
        msg[i-1] += msg[i] // 256
        msg[i] = msg[i] % 256

    pad = [236, 17]
    msg = (msg + pad * 54)[:108]

    # MAGIC (encoding)
    gen = [1]
    for i in range(0, nsym):
        q = [1, gf_exp[i]]
        r = [0] * (len(gen)+len(q)-1)
        for j in range(0, len(q)):
            for i in range(0, len(gen)):
                r[i+j] ^= gf_mul(gen[i], q[j])
        gen = r
    msg_enc = [0] * (len(msg) + nsym)
    for i in range(0, len(msg)):
        msg_enc[i] = msg[i]
    for i in range(0, len(msg)):
        coef = msg_enc[i]
        if coef != 0:
            for j in range(0, len(gen)):
                msg_enc[i+j] ^= gf_mul(gen[j], coef)
    for i in range(0, len(msg)):
        msg_enc[i] = msg[i]


    # PATTERN
    # position marks
    for _ in range(3):
        datamatrix = np.rot90(datamatrix)
        for i in range(4):
            datamatrix[max(0, i-1):8-i, max(0, i-1):8-i] = i%2
    datamatrix = np.rot90(datamatrix.T)

    # alignment
    for i in range(3):
        datamatrix[28+i:33-i, 28+i:33-i] = (i+1)%2

    # timing
    for i in range(7, dim-7):
        datamatrix[i, 6] = datamatrix[6, i] = (i+1)%2

    # the "dark module"
    datamatrix[dim-8, 8] = 1

    # FORMAT INFO
    L4 = '110011000101111' # Low/Mask4
    ptr_ul = np.array([8, -1])
    steps_ul = [0, 1] * 8 + [-1, 0] * 7
    steps_ul[13] = 2 # hop over vertical timing
    steps_ul[18] = -2 # then horizontal

    ptr_x = np.array([dim, 8])
    steps_x = [-1, 0] * 7 + [15-dim, dim-16] + [0, 1] * 7

    for bit, step_ul, step_x in zip(L4, np.array(steps_ul).reshape(-1,2), np.array(steps_x).reshape(-1,2)):
        ptr_ul += step_ul
        ptr_x += step_x
        datamatrix[tuple(ptr_ul)] = int(bit)
        datamatrix[tuple(ptr_x)] = int(bit)

    # FILL
    dmask = datamatrix == 0.5

    cols = (dim-1)/2
    cursor = np.array([dim-1, dim]) # starting off the matrix
    up_col = [-1, 1, 0, -1] * dim
    down_col = [1, 1, 0, -1] * dim
    steps = ([0, -1] + up_col[2:] + [0, -1] + down_col[2:]) * (cols/2)
    steps = np.array(steps).reshape(-1, 2)
    steps = iter(steps)

    # bit-ify everything
    msg_enc = ''.join('{:08b}'.format(x) for x in msg_enc) + '0' * 7 # 7 0's are for padding
    for bit in msg_enc:
        collision = 'maybe'
        while collision:
            cursor += steps.next()
            # skip vertical timing
            if cursor[1] == 6:
                cursor[1] = 5
            collision = not dmask[tuple(cursor)]
        datamatrix[tuple(cursor)] = int(bit)

    # COOK
    mask4 = lambda i, j: (i//2 + j//3)%2 == 0
    for i in range(dim):
        for j in range(dim):
            if dmask[i, j]:
                datamatrix[i, j] = int(datamatrix[i, j]) ^ (1 if mask4(i, j) else 0)

    # THE PRESTIGE
    plt.figure(facecolor='white')
    plt.imshow(datamatrix, cmap=plt.cm.gray_r, interpolation='nearest')
    plt.axis('off')
    plt.show()

if __name__ == '__main__':
    main()

Dopo:

import sys
from pylab import*
n=range
l=len
E=[1]+[0]*511
L=[0]*256
x=1
for i in n(1,255):
 x<<=1
 if x&256:x^=285
 E[i]=x;L[x]=i
for i in n(255,512):E[i]=E[i-255]
def f(x,y):
 if x*y==0:return 0
 return E[L[x]+L[y]]
m=sys.argv[1]
m=[ord(c)*16 for c in'\4'+chr(l(m))+m]
for i in n(1,l(m)):m[i-1]+=m[i]/256;m[i]=m[i]%256
m=(m+[236,17]*54)[:108]
g=[1]
for i in n(26):
 q=[1,E[i]]
 r=[0]*(l(g)+l(q)-1)
 for j in n(l(q)):
    for i in n(l(g)):r[i+j]^=f(g[i],q[j])
 g=r
e=[0]*134
for i in n(108):
 e[i]=m[i]
for i in n(108):
 c=e[i]
 if c: 
    for j in n(l(g)):e[i+j]^=f(g[j],c)
for i in n(108):e[i]=m[i]
m=.1*ones((37,)*2)
for _ in n(3):
 m=rot90(m)
 for i in n(4):m[max(0,i-1):8-i,max(0,i-1):8-i]=i%2
m=rot90(m.T)
for i in n(3):m[28+i:33-i,28+i:33-i]=(i+1)%2
for i in n(7,30):m[i,6]=m[6,i]=(i+1)%2
m[29,8]=1
a=array
t=tuple
g=int
r=lambda x:iter(a(x).reshape(-1,2))
p=a([8,-1])
s=[0,1]*8+[-1,0]*7
s[13]=2
s[18]=-2
P=a([37,8])
S=[-1,0]*7+[-22,21]+[0,1]*7
for b,q,Q in zip(bin(32170)[2:],r(s),r(S)):p+=q;P+=Q;m[t(p)]=g(b);m[t(P)]=g(b)
D=m==0.1
c=a([36,37])
s=r(([0,-1]+([-1,1,0,-1]*37)[2:]+[0,-1]+([1,1,0,-1]*37)[2:])*9)
for b in ''.join('{:08b}'.format(x) for x in e):
 k=3
 while k:
    c+=s.next()
    if c[1]==6:c[1]=5
    k=not D[t(c)]
 m[t(c)]=g(b)
a=n(37)
for i in a:
 for j in a:
    if D[i,j]:m[i,j]=g(m[i,j])^(j%3==0)
imshow(m,cmap=cm.gray_r);show()

(basandosi su una scheda per contare come 4/8 / qualunque numero di spazi> = 2., non sono sicuro di come copierà)

Perché è così lungo, possiamo comprimerlo (visto qualcuno farlo da qualche altra parte, dimenticato chi però :() per salvare altri personaggi, portando il totale a 1085 1077 perché pylabè sporco:

import zlib,base64
exec zlib.decompress(base64.b64decode('eJxtU0tzmzAQvvSkX6FLaglkyiM2hHRvyS2HZNobo3QwwY6IBVjQFrfT/96V3KR4Wg5I+/6+3ZXSfWdGOhwHsjWdpv1xX26oclqPtGDKdleTPezrltxCEUm/CKW3iiJyB/YWr9ZkgohsO0MVVS1tWSTi1YrnhE4fP6KFqi2d3qNfPj1CnK0IvS2UhOn6rpgkqHkkxolVFPPceeBviRpJnuot3bJJHG1Sm807AoS5qcevpqUhoX9ut4VN6d8VRymJBuQUlGb3DUGjVHTmiVXci9bUVqyw4uLdwq+eDdszzbmv5TkJp801gkDSgKf8gCSu7cVJF5a6Bqb9Ik7WIkqxLZe8yKMwk2RnW3VGbW3BH1AtLDmJoF3/sPiO+3t24MuIEwetOUVYnY3Bb5bHuvPcFMpv5CNs2Q6TiUPRSAzegSG1yxoll2dkwsxmql+h/8dWgbW69lY5favazKvWs6qNFBX/J8/fChqCyOvaemAsSQX34pPzl5NzYktqMN14FWKbyZzhpW26LicWCmw9z7OlEucibs1FTN7Cg89nQBIbH2e+ypMEQ99uEpjyI46RM+dUJKEbslhb4Gsxc8MsVyKTuMIllMaURzLC+LXf1zhd1Y7EwL7Um6eSTrkaa8NKNvHA1MNz2ddsia+Ac9JDyYpM4ApxMuBoRCS9zC/QilNKyVBEiYTYnlhoGZN7648Ny9D/E7z6YUAci9g9PpshdRQ24iAeLI0fqmcbhczjKA15EedSGDZw/H3CqfU+HK7vfXjA1R1ZzyXs2IY74f6PQG5A44sKIlK5+muRpA6wYQwr2gfALBZEYwUvSV0V/832j4l7V6ehbCzAxSJoOgS4+JmH2ebXIkCLLkfslxv8ZH1quxIvkBD6/Vnta/pyWv3KhyFo62lk3Ml2P/FpAaxzd66c9gXabqQ3SKniuMT6dDlxKwE7k85WpMxn76zMX9Pe4BI00u1CY0NPF/7ImosEm8OJ0sNz951pUemyh0oHO9yJL4ZfOzX/DQ2mdSs='))

inserisci qui la descrizione dell'immagine

Se si sostituisce l'ultima riga con la seguente (aggiunge 62 caratteri), si ottiene un output quasi perfetto, ma l'altro esegue ancora la scansione, quindi qualunque cosa.

figure(facecolor='white');imshow(m,cmap=cm.gray_r,interpolation='nearest');axis('off');show()

Buon codice QR


Ottimo lavoro! È un peccato che Python non sia il migliore nelle soluzioni di golf, ma questo è un codice straordinario, @NickT!
WallyWest,

Probabilmente potrei risparmiare un po 'di più se perdo la structchiamata e un po' inutile spingendo semplicemente troncando la mia "stringa principale" ...
Nick T

Cordiali saluti, il secondo livello di rientro può essere di soli due spazi. Ho notato che usi quattro / tab.
Decadimento beta

1
@BetaDecay dovrebbe essere solo 1 scheda (1 scheda> 1 spazio per quanto riguarda il rientro ... Penso che SE rompa le schede?)
Nick T

@NickT sì, lo fa.
R
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.