Implementare un hash di lunghezza variabile


10

Io e il mio amico abbiamo questo gioco a cui giochiamo a parole. È un passatempo divertente e implica "cancellare" le lettere in una parola fino a quando non rimane più nulla. Sono davvero stanco che sia molto più veloce di me, quindi è il tuo compito implementarlo e lasciarmi finalmente battere. Ovviamente, dato che devo rendere il programma il più semplice possibile da nascondere, deve essere il più piccolo possibile.

Come funziona questo gioco?

Il gioco è un algoritmo piuttosto semplice. Riduce una stringa alfabetica fino a quando non può essere ulteriormente ridotta, rendendola così una sorta di hash. Il gioco reale che noi umani facciamo è molto difficile da implementare, ma può essere semplificato nel seguente algoritmo:

Si inizia piegando l'alfabeto a metà e allineando i due pezzi in questo modo:

a b c d e f g h i j k l m
z y x w v u t s r p q o n

Quindi, a partire dalla metà, assegni gli interi positivi alla metà superiore e il negativo alla fine:

a  b  c  d  e f g h i j k l m
13 12 11 10 9 8 7 6 5 4 3 2 1

z   y   x   w   v  u  t  s  r  p  q  o  n
-13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1

Quindi prendi la tua stringa (che useremo hello world) e ignorando tutti i caratteri non alfabetici, traducila:

h e l l  o w   o  r  l d
6 9 2 2 -2 -10 -2 -5 2 10

Quindi sommi i valori delle lettere. Quelle allineate nel diagramma precedente (ad es. dE w, le o) verranno annullate, mentre le altre verranno sommate.

sum(6 9 2 2 -2 -10 -2 -5 2 10 )=12

12 è il numero per b, quindi l'hash di hello worldèb

Per una parola che cancella completamente fuori (ad esempio love), è uscita la "0 carattere": -. Si noti che nell'input -verrà comunque ignorato. Importa solo nell'output.

Se grandezza del numero è maggiore di 13, poi si inizia il raddoppio sulle a's e la z' s Che, fondamentalmente, prendere come molti a's o z' s misura nel numero e prendere tutto ciò che è a sinistra per l'ultima lettera in questo modo:

code golf: 43.

Adatto a 3 ae ne ha ancora 4:

aaa 4: j
result: aaaj

Suggerimento: questa parte è fondamentalmente divmodtranne per il fatto che si arrotonda verso lo zero, non -infinity(ad esempio -43 diventerebbe 3 z'e e a -4che è pcosì zzzp).

Nota: il trattino non arriva se la a"o z" si adatta perfettamente, solo se è esattamente 0.

chiarimenti:

  • L'hash è case in sensitive
  • Non sono ammesse scappatoie standard
  • L'I / O può essere in qualsiasi formato che non sia troppo stravagante, stdin, stdout, arg della riga di comando, funzione, ecc.
  • Si tratta di quindi vince la dimensione più breve in byte .

Esempi:

hello world  -->  b

love  -->  -

this is an example -->  aak

hello *&*(&(*&%& world  -->  b

good bye --> ae

root users --> zzs

3
loveè vuoto ...
Giustino

Risposte:


4

CJam, 46 byte

Provalo online o prova la suite di test online .

lel{'n-_W>+_zE<*}%:+{_De<C~e>___0>-'n+'-?o-}h;

Spiegazione

L'algoritmo funziona come ci si potrebbe aspettare: leggere l'input, convertire in minuscolo, mappare ogni carattere su un valore, sommare i valori e stampare i caratteri e regolare la somma di conseguenza fino a quando la somma è zero. Probabilmente l'ottimizzazione più interessante (anche se salva solo due byte) è che vengono invece utilizzate mappature di caratteri negate, in quanto ciò evita lo scambio di argomenti di sottrazione per correggere il segno durante il calcolo del valore mappato ed evita lo scambio di nuovo quando si esegue il mapping a una lettera a causa del sottrazione di un valore negato sostituibile con l'aggiunta.

lel             "Read a line of input and convert all letters to lowercase.";
{               "Map each character:";
  'n-_W>+         "Map each character to its negated value by subtracting 'n'
                   and incrementing if the result is nonnegative.";
  _zE<*           "If the value is out of the letter range, use 0 instead.";
}%
:+              "Compute the sum of the mapped character values.";
{               "Do...";
  _De<C~e>        "Compute the sum clamped to the letter range.";
  __              "If the clamped sum is nonzero, ...";
  _0>-'n+         "... then produce the clamped sum mapped back to a letter by
                     decrementing if it is positive and adding 'n', ...";
  '-              "... else produce '-'.";
  ?
  o               "Output the character produced above.";
  -               "Subtract the clamped sum out of the sum.";
}h              "... while the sum is nonzero.";
;               "Clean up.";

4

Pyth, 79 78 77 65 61 58

J+\-GK+0fTr13_14=ZsX@JzJKMe,pk*G/H13%H13@JxK?g\aZ>Z0_g\z_Z

Puoi usare al @Jzposto di f}YJzC'è probabilmente di più, ma ora devo dormire. Buona fortuna;)
FryAmTheEggman

@FryAmTheEggman Cool, non ero a conoscenza dell'intersezione di @!
orlp

2

Clip 10 , 87

Fr+`m[y?cAyg#Ay-v,-RRZ]0]}m.U`[Fx?x?<x0,:-/xR'z*m'm%xR!!%xR],:/xR'a*m'n%xR!!%xR]]'-[R13

1

R, 258 byte

function(s){a=13;r=data.frame;z=strsplit(gsub("[^a-z]","",tolower(s)),"")[[1]];d=r(l=rev(letters),h=c(-1*a:1,1:a));m=merge(r(l=z),d);n=sum(m$h);q=abs(n);v=rep(ifelse(n>0,"a","z"),q%/%a);paste0(paste(v,collapse=""),d$l[d$h==sign(n)*q%%a],ifelse(n==0,"-",""))}

Questo deve essere il codice R più grossolano di sempre. Ho pensato che R potesse essere una scelta decente poiché ha un vettore di tutte le lettere da "a" a "z" come variabile globale incorporata. Ma il resto è un casino.

Ungolfed + spiegazione:

function(s) {
    a <- 13              # Store the value associated with a
    r <- data.frame      # Store the `data.frame` function

    # Split the input into a vector, ignoring case and non-letters
    z <- strsplit(gsub("[^a-z]", "", tolower(s)), "")[[1]]

    # Create a data frame where the first column is the letters
    # z through a and the second is the associated scores
    d <- data.frame(l=reverse(letters), h=c(-1*a:1, 1:a))

    # Merge the split vector with the data frame of scores
    m <- merge(data.frame(l=z), d)

    # Get the total score for the input
    n <- sum(m$h)
    q <- abs(n)

    # Pad the output with a or z as necessary
    v <- rep(ifelse(n > 0, "a", "z"), q %/% a)

    # Collapse the vector of a's or z's into a string
    out1 <- paste(v, collapse="")

    # Look up the letter associated with remainder
    out2 <- d$l[d$h == sign(n)*q%%a]

    # If n = 0, we still want a dash
    out3 <- ifelse(n == 0, "-", "")

    # Return the concatenation of all pieces of the output
    paste0(out1, out2, out3)
}

Ciò crea un oggetto funzione senza nome che accetta una stringa come input e restituisce il valore hash associato. Per chiamarlo, dagli un nome, ad es f=function(s){...}.

Esempi:

> f("this is an example")
[1] "aak"

> f("root users")
[1] "zzs"

> f("love")
[1] "-"

> f("People like grapes.")
[1] "aaag"

Provalo online!

Domande? Sarò felice di fornire ulteriori spiegazioni. Suggerimenti? I suggerimenti sono più che benvenuti!


1

Haskell, 171 byte

import Data.Char
m=13
l=zip['a'..'z'][-i|i<-[-m..m],i/=0]
p 0="-"
p n|n>m='a':p(n-m)|n<(-m)='z':p(n+m)|1<2=[c|(c,i)<-l,i==n]
f n=p$sum[y|Just y<-[lookup(toLower x)l|x<-n]]

Prova:

> map f ["hello world", "love", "this is an example", "hello *&*(&(*&%& world", "good bye", "root users"]
["b","-","aak","b","ae","zzs"]

Come funziona: lè una tabella di ricerca dalle lettere al valore corrispondente. Cerca tutti i caratteri dalla stringa di input e scarta quelli non trovati. Somma l'elenco risultante. A seconda della somma delle pstampe -o forse prima qualche as o zs e infine (indietro) cerca la lettera da l.


1

R - 200

function(s){l=letters
N=setNames
x=strsplit(tolower(s),'')[[1]]
n=(13:-13)[-14]
v=sum(N(n,l)[x[x%in%l]])
o=''
while(v){d=min(max(v,-13),13)
o=paste0(o,N(l,n)[as.character(d)])
v=v-d}
if(o=='')o='-'
o}

+1, decisamente migliore della mia risposta R. Bel lavoro!
Alex A.
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.