Mapeamento entre palavra inteira e pronunciável

10

Objetivo

A idéia é fornecer o código necessário para mapear um número inteiro de 32 bits de / para uma palavra pronunciável de no máximo 9 caracteres. Isso pode ser útil, por exemplo, para facilitar a lembrança de um número de série ou digitar um formulário.

É necessário o método para traduzir um número inteiro para a palavra correspondente e para converter novamente uma palavra para o número inteiro correspondente.

Regras

Deve haver um mapeamento individual entre números inteiros e palavras, e todo o conjunto de números inteiros de 32 bits (ou, de outra forma, qualquer número inteiro de 0 a 4294967295) deve ser mapeado. Embora, obviamente, nem todas as palavras sejam significativas, e a inserção de palavras que não são mapeadas para um número inteiro pode ter um comportamento não especificado.

Você é livre para decidir exatamente qual conjunto de palavras "pronunciáveis" é significativo e como o mapeamento é feito, mas as palavras devem pelo menos seguir estas regras:

  • Somente as 26 letras básicas (A ... Z) devem ser usadas como caracteres. Acentos, revestimento, etc ... não devem ser usados ​​para estender as combinações possíveis.
  • Máximo de 9 caracteres por palavra.
  • duas consoantes (BCDFGHJKLMNPQRSTVWXZ - 20 possibilidades) não devem ser colocadas próximas uma da outra (elas devem estar rodeadas de vogais).
  • duas vogais (AEIOUY - 6 possibilidades) não devem ser colocadas próximas uma da outra (elas devem estar cercadas por consoantes).

Nota: o esquema mais simples no qual todas as palavras são construídas como CVCVCVCVC( Csendo uma consoante e Vuma vogal) fornece combinações 4147200000 e um número inteiro de 32 bits possui 4294967296 valores possíveis, portanto, não é suficiente. Você precisa expandir o número de combinações, permitindo palavras mais curtas ou permitindo VCVCVCVCVcombinações também.

Aplicam-se outras regras padrão e as brechas padrão são proibidas.

Entradas saídas

Para cada envio, dois códigos devem ser fornecidos:

  • Um que recebe um número inteiro como argumento / entrada e retorna / imprime a palavra correspondente
  • Uma que pega uma palavra como argumento / entrada e retorna / imprime o número inteiro correspondente

Como alternativa, você pode optar por enviar um único trecho de código que lida com as duas operações:

  • Quando um número inteiro é fornecido como entrada, ele gera a palavra correspondente
  • Quando recebe uma string como entrada, gera o número inteiro correspondente

Condição vencedora

Este é um , a resposta que possui o menor número de bytes (ao somar os dois trechos de código, para soluções que optam por trechos separados) ganha.

pouca fé perdida no SE
fonte
Existem restrições de espaço ou tempo? Temos que caber dentro de 32 GB de memória?
John Dvorak
@JanDvorak Bem, poderemos testar seu programa em um computador "padrão". Mas o algoritmo deve ser simples, o que você tem em mente que requer uma quantidade tão grande de memória?
dim perdeu a fé em SE
Eu poderia gerar todas as palavras possíveis de nove letras que correspondam à sua fórmula e depois indexá-las no conjunto ou fazer uma pesquisa binária.
John Dvorak
@JanDvorak Devo admitir que não pensei nisso. Eu estava pensando mais em soluções que estavam basicamente fazendo conversões de base 26, com alguns ajustes para satisfazer a restrição de vogal / consoante. Mas, de alguma forma, duvido que a maneira "brutal" que você tinha em mente possa ser eficiente no código de golfe. De qualquer forma, se eu realmente precisar esclarecer isso, digamos que você não tenha permissão para alocar mais de 4 GB de memória.
dim perdeu a fé em SE
Você pode exigir que os respondentes executem o código para alguns valores predeterminados (0,1,10,2 ** 32-1 e outros) e depois retornem e incluam os resultados na resposta.
John Dvorak

Respostas:

1

JavaScript (ES6), 205 bytes

p=>(a='bcdfghjklmnpqrstvwxzaeiouy',1/p)?[...Array(9)].map(_=>r=a[p%(n=26-n)+(p=p/n|0,n<7)*20]+r,n=p>(p%=4e9)?20:6,r='')&&r:[...p].map(c=>r=r*(n=26-n)+a.search(c)%20,n=a.search(p[r=0])<20?6:20)&&r+(n<7)*4e9

O ponto de corte entre CVCVCVCVC e VCVCVCVCV é 4e9, portanto, começa a dar errado em 5244160000 (entrada numérica) ou zesuwurib(entrada de sequência).

Neil
fonte
Seis meses depois ... Eu concedo a você os pontos de aceitação, já que você é o mais curto (e não posso aceitar a resposta de rturnbull, que não satisfaz os esclarecimentos que fiz nos comentários).
dim perdeu a fé no SE
2

PHP, 353 bytes

Codificação + decodificação

is_numeric($argn)contém o booleano. É verdade se a entrada for um número inteiro.

$c=array_diff(range(A,Z),$v=[A,E,I,O,U,Y]);sort($c);if(is_numeric($a=$argn)){$r=($a)%26<6?$v[$a%26]:$c[$a%26-6];$a=$a/26^0;while($a){$z=count($t=in_array($r[0],$v)?$c:$v);$r=$t[$n=$a%$z].$r;$a=$a/$z^0;}echo$r;}else{for($p=1;$i++<strlen($a);){$u=($b=in_array($a[-$i],$c))?$c:$v;$s+=array_flip($u)[$a[-$i]]*$p+($b&$i<2?6:0);$p*=$i>1?count($u):26;}echo$s;}

PHP, 190 bytes (codificação) + 195 bytes (decodificação) = 385 bytes

Codificação

$c=array_diff(range(A,Z),$v=[A,E,I,O,U,Y]);sort($c);$r=($a=$argn)%26<6?$v[$a%26]:$c[$a%26-6];$a=$a/26^0;while($a){$z=count($t=in_array($r[0],$v)?$c:$v);$r=$t[$n=$a%$z].$r;$a=$a/$z^0;}echo$r;

5391360000 = 26 * 120 ** 4 combinações estão disponíveis

Codificação de versão online sem E_NOTICE

Expandido

$c=array_diff(range(A,Z),$v=[A,E,I,O,U,Y]);
sort($c); # End of Prepare the two array
$r=($a=$argn)%26<6?$v[$a%26]:$c[$a%26-6]; #base 26 decision input mod 26 <6 end with vowel
$a=$a/26^0; #integer division input with 26
while($a){
    $z=count($t=in_array($r[0],$v)?$c:$v); # use vowel if last entry is consonant and viceversa
    $r=$t[$n=$a%$z].$r; # base 6 or base 20 decision
    $a=$a/$z^0; # divide through base
}echo$r; # Output result

Entrada => Saída

4294967296 => TYPYQACOV 
333 => DAT 
1 => E 
7 => C 
4294967276 => UTOPOQAMI

Se você precisar sempre de um resultado de 9 bytes, substitua while($a)por while(strlen($r)<9)+ 10 bytes

Decodificação

$c=array_diff(range(A,Z),$v=[A,E,I,O,U,Y]);sort($c);for($p=1;$i++<strlen($a=$argn);){$u=($b=in_array($a[-$i],$c))?$c:$v;$s+=array_flip($u)[$a[-$i]]*$p+($b&$i<2?6:0);$p*=$i>1?count($u):26;}echo$s;

Expandido

$c=array_diff(range("A","Z"),$v=["A","E","I","O","U","Y"]);
sort($c); # End of Prepare the two array
for($p=1;$i++<strlen($a=$argn);){ 
    $u=($b=in_array($a[-$i],$c))?$c:$v; # find use array for $a[-$i]
    $s+=array_flip($u)[$a[-$i]]*$p+($b&$i<2?6:0); # sum value
    $p*=$i>1?count($u):26; # raise multiple for next item
}echo$s;

Entrada => Saída

ABABABABE => 1
E => 1
UTOPOQAMI => 4294967276
BABABADAT => 333
DAT => 333
TYPYQACOV => 4294967296

Decodificação de versão online sem E_NOTICE

Verificação Adicional

Se precisarmos verificar se uma string é válida.

Adicione $x.=$b?:0;no final do loop de decodificação + 10 bytes

Substitua echo$s;por echo!preg_match('#([01])\1$#',$x)?$s:_;+ 32 bytes

Jörg Hülsermann
fonte
1

R, 165 bytes

Codificação e decodificação em uma função.

Essa função usa o método de força bruta para criar todos os valores possíveis e, em seguida, simplesmente retornar o índice quando receber uma entrada de string e retornar a string quando receber uma entrada inteira. Como conseqüência, é muito lento e usa 16 GB ou mais de memória!

function(x){i=c(1,5,9,15,21,25)
d=apply(expand.grid(c<-letters[-i],v<-letters[i],c,v,c,v,c,v,c(c,"")),1,paste,collapse="")
`if`(mode(x)=="numeric",d[x],which(d==x))}

4.354.560.000 valores são possíveis. Isso abrange todas as seqüências de caracteres do formulário CVCVCVCV (C), com o último C sendo opcional.

rturnbull
fonte
@ mbomb007 Gigabytes, desculpe pelo erro de digitação. A função codifica e decodifica, dependendo se o argumento é uma sequência ou um número inteiro. Atualizei a postagem para esclarecer isso.
rturnbull
O downvoter pode deixar um comentário para sugerir melhorias? Obrigado.
Rdb # r17 # 18
11
Nos comentários da questão, esclarece dim que você não pode usar mais de 4 GB de memória ....
socrático Phoenix