Mapeo entre entero y palabra pronunciable

10

Propósito

La idea es proporcionar el código necesario para asignar un número entero de 32 bits a / desde una palabra pronouncable de 9 caracteres como máximo. Eso podría ser útil, por ejemplo, para que un número de serie sea más fácil de recordar, o escriba un formulario.

Se requieren tanto el método para traducir un número entero a la palabra correspondiente como para volver a traducir una palabra al número entero correspondiente.

Reglas

Debe haber un mapeo uno a uno entre enteros y palabras, y todo el conjunto de enteros de 32 bits (o, dicho de otra manera, cualquier entero de 0 a 4294967295) debe ser mapeable. Aunque, obviamente, no todas las palabras serán significativas, y la introducción de palabras que no se asignan a un número entero puede tener un comportamiento no especificado.

Usted es libre de decidir exactamente qué conjunto de palabras "pronouncables" es significativo y cómo se realiza el mapeo, pero las palabras deben al menos seguir estas reglas:

  • Solo las 26 letras básicas (A ... Z) deben usarse como caracteres. Los acentos, las carcasas, etc. no deben usarse para extender las posibles combinaciones.
  • Máximo 9 caracteres por palabra.
  • dos consonantes (BCDFGHJKLMNPQRSTVWXZ - 20 posibilidades) no deben colocarse una al lado de la otra (deben estar rodeadas de vocales).
  • dos vocales (AEIOUY - 6 posibilidades) no deben colocarse una al lado de la otra (deben estar rodeadas de consonantes).

Nota: el esquema más simple donde tiene todas las palabras construidas como CVCVCVCVC( Csiendo una consonante y Vuna vocal) da 4147200000 combinaciones, y un entero de 32 bits tiene 4294967296 valores posibles, por lo que no es suficiente. Necesita expandir el número de combinaciones, ya sea permitiendo palabras más cortas o también permitiendo VCVCVCVCVcombinaciones.

Se aplican otras reglas estándar, y las lagunas estándar están prohibidas.

Salidas, entradas

Para cada envío, se deben proporcionar dos piezas de código:

  • Uno que toma un número entero como argumento / entrada y devuelve / imprime la palabra correspondiente
  • Una que toma una palabra como argumento / entrada y devuelve / imprime el entero correspondiente

Alternativamente, puede optar por enviar una sola pieza de código que maneja ambas operaciones:

  • Cuando se le da un entero como entrada, emite la palabra correspondiente
  • Cuando se le da una cadena como entrada, genera el entero correspondiente

Condición ganadora

Este es un , la respuesta que tiene la menor cantidad de bytes (al sumar ambas partes del código, para las soluciones que optan por las partes separadas del código) gana.

tenue fe perdida en SE
fuente
¿Hay alguna limitación de espacio o tiempo? ¿Tenemos que caber dentro de 32 GB de memoria?
John Dvorak
@ JanDvorak Bueno, deberíamos poder probar su programa en una computadora "estándar". Pero el algoritmo debería ser simple, ¿qué tienes en mente que requiere una cantidad de memoria tan grande?
tenue fe perdida en SE
Podría generar todas las palabras posibles de nueve letras que coincidan con su fórmula y luego indexarlas en el conjunto o hacer una búsqueda binaria.
John Dvorak
@ JanDvorak Debo admitir que no pensé en eso. Estaba más pensando en soluciones que básicamente estaban haciendo conversiones de base 26, con algunos ajustes para satisfacer la restricción vocal / consonante. Pero de alguna manera dudo que la forma "brutal" que tenía en mente puede ser eficiente en el código de golf. De todos modos, si realmente debo aclarar esto, digamos que no se le permite asignar más de 4 GB de memoria.
tenue fe perdida en SE
Puede requerir que los respondedores ejecuten su código para algunos valores predeterminados (0,1,10,2 ** 32-1 y tal) y luego retrocedan e incluyan los resultados en la respuesta.
John Dvorak

Respuestas:

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

El punto de corte entre CVCVCVCVC y VCVCVCVCV es 4e9, por lo que comienza a fallar en 5244160000 (entrada numérica) o zesuwurib(entrada de cadena).

Neil
fuente
Seis meses después ... te otorgo los puntos de aceptación, ya que eres el más bajo (y no puedo aceptar la respuesta de rturnbull, que no satisface la aclaración que hice en los comentarios).
tenue fe perdida en SE
2

PHP, 353 bytes

Codificación + Decodificación

is_numeric($argn)contiene el booleano. Es cierto si la entrada es un número entero.

$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 (codificación) + 195 bytes (decodificación) = 385 bytes

Codificación

$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 combinaciones disponibles

Codificación de versión en línea sin 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 => Salida

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

Si siempre necesita un resultado de 9 bytes, reemplácelo while($a)con while(strlen($r)<9)+ 10 bytes

Descodificación

$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 => Salida

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

Decodificación de versión en línea sin E_NOTICE

Cheque adicional

Si necesitamos verificar si una cadena es válida.

Agregue $x.=$b?:0;al final del ciclo de decodificación + 10 bytes

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

Jörg Hülsermann
fuente
1

R, 165 bytes

Codificación y decodificación en una función.

Esta función utiliza el método de fuerza bruta para crear todos los valores posibles y luego simplemente devolver el índice cuando se le da una entrada de cadena y devolver la cadena cuando se le da una entrada entera. Como consecuencia, es muy lento y usa 16GB + de memoria.

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 son posibles. Esto cubre todas las cadenas de la forma CVCVCVCV (C), siendo la última C opcional.

rturnbull
fuente
@ mbomb007 Gigabytes, perdón por el error tipográfico. La función codifica y decodifica dependiendo de si el argumento es una cadena o un entero. He actualizado la publicación para aclarar eso.
rturnbull
¿Puede el votante dejar un comentario para sugerir mejoras? Gracias.
rturnbull
1
En los comentarios de la cuestión, aclara tenues que no se puede utilizar más de 4 GB de memoria ....
socrático Phoenix