Mappage entre un entier et un mot prononçable

10

Objectif

L'idée est de fournir le code nécessaire pour mapper un entier 32 bits vers / depuis un mot prononçable de 9 caractères maximum. Cela pourrait être utile, par exemple, pour faciliter la mémorisation d'un numéro de série ou la saisie d'un formulaire.

La méthode de traduction d'un entier en mot correspondant et de traduction en arrière d'un mot en entier correspondant est requise.

Règles

Il doit y avoir un mappage un à un entre les entiers et les mots, et l'ensemble des entiers 32 bits (ou, autrement dit, tout entier compris entre 0 et 4294967295) doit être mappable. Bien que, évidemment, tous les mots ne soient pas significatifs, et la saisie de mots qui ne correspondent pas à un entier peut avoir un comportement non spécifié.

Vous êtes libre de décider exactement quel ensemble de mots "prononçables" est significatif et comment le mappage est effectué, mais les mots doivent au moins suivre ces règles:

  • Seules les 26 lettres de base (A ... Z) doivent être utilisées comme caractères. Les accents, le boîtier, etc ... ne doivent pas être utilisés pour étendre les combinaisons possibles.
  • 9 caractères maximum par mot.
  • deux consonnes (BCDFGHJKLMNPQRSTVWXZ - 20 possibilités) ne doivent pas être placées l'une à côté de l'autre (elles doivent être entourées de voyelles).
  • deux voyelles (AEIOUY - 6 possibilités) ne doivent pas être placées l'une à côté de l'autre (elles doivent être entourées de consonnes).

Remarque: le schéma le plus simple où tous les mots sont construits comme CVCVCVCVC( Cétant une consonne et Vune voyelle) donne 4147200000 combinaisons, et un entier 32 bits a 4294967296 valeurs possibles, donc ce n'est pas suffisant. Vous devez augmenter le nombre de combinaisons, soit en autorisant des mots plus courts, soit en autorisant également des VCVCVCVCVcombinaisons.

D'autres règles standard s'appliquent et les failles standard sont interdites.

Entrées / Sorties

Pour chaque soumission, deux morceaux de code doivent être fournis:

  • Celui qui prend un entier comme argument / entrée et retourne / imprime le mot correspondant
  • Celui qui prend un mot comme argument / entrée et renvoie / imprime l'entier correspondant

Alternativement, vous pouvez choisir de soumettre un seul morceau de code qui gère les deux opérations:

  • Lorsqu'il reçoit un entier en entrée, il génère le mot correspondant
  • Lorsqu'une chaîne est donnée en entrée, elle génère l'entier correspondant

Condition gagnante

C'est un , la réponse qui a le moins d'octets (lors de la sommation des deux morceaux de code, pour les solutions optant pour les morceaux de code séparés) gagne.

faible
la source
Y a-t-il des contraintes d'espace ou de temps? Doit-on tenir dans les 32 Go de mémoire?
John Dvorak
@JanDvorak Eh bien, nous devrions pouvoir tester votre programme sur un ordinateur "standard". Mais l'algorithme doit être simple, à quoi pensez-vous avoir besoin d'une telle quantité de mémoire?
dim
Je pourrais simplement générer tous les mots de neuf lettres possibles qui correspondent à votre formule, puis indexer dans l'ensemble ou faire une recherche binaire.
John Dvorak
@JanDvorak Je dois admettre que je n'y ai pas pensé. Je pensais davantage à des solutions qui faisaient essentiellement des conversions en base 26, avec quelques ajustements pour satisfaire la contrainte voyelle / consonne. Mais je doute que la façon "brutale" que vous aviez en tête puisse être efficace en matière de code-golf. Quoi qu'il en soit, si je dois vraiment clarifier cela, disons que vous n'êtes pas autorisé à allouer plus de 4 Go de mémoire.
dim
Vous pouvez demander aux répondeurs d'exécuter leur code pour certaines valeurs prédéterminées (0,1,10,2 ** 32-1 et autres), puis de revenir et d'inclure les résultats dans la réponse.
John Dvorak

Réponses:

1

JavaScript (ES6), 205 octets

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

Le point de coupure entre CVCVCVCVC et VCVCVCVCV est 4e9, donc commence à mal tourner à 5244160000 (entrée numérique) ou zesuwurib(entrée de chaîne).

Neil
la source
Six mois plus tard ... Je vous attribue les points d'acceptation, puisque vous êtes le plus court (et je ne peux pas accepter la réponse de rturnbull, qui ne satisfait pas la clarification que j'ai faite dans les commentaires).
dim
2

PHP, 353 octets

Encodage + décodage

is_numeric($argn)contient le booléen. C'est vrai si l'entrée est un entier.

$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 octets (encodage) + 195 octets (décodage) = 385 octets

Codage

$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 combinaisons sont disponibles

Encodage de la version en ligne sans E_NOTICE

Étendu

$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

Entrée => Sortie

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

Si vous avez toujours besoin d'un résultat de 9 octets, veuillez le remplacer while($a)par while(strlen($r)<9)+ 10 octets

Décodage

$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;

Étendu

$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;

Entrée => Sortie

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

Décodage de version en ligne sans E_NOTICE

Chèque supplémentaire

Si nous avons besoin de vérifier si une chaîne est valide.

Ajouter $x.=$b?:0;à la fin de la boucle de décodage + 10 octets

Remplacer echo$s;par echo!preg_match('#([01])\1$#',$x)?$s:_;+ 32 octets

Jörg Hülsermann
la source
1

R, 165 octets

Encodage et décodage en une seule fonction.

Cette fonction utilise la méthode de force brute pour créer toutes les valeurs possibles, puis renvoyer simplement l'index lorsqu'il reçoit une entrée de chaîne et renvoyer la chaîne lorsqu'elle reçoit une entrée d'entier. En conséquence, il est très lent et utilise 16 Go + de mémoire!

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 valeurs sont possibles. Cela couvre toutes les chaînes de la forme CVCVCVCV (C), le dernier C étant facultatif.

rturnbull
la source
@ mbomb007 Gigabytes, désolé pour la faute de frappe. La fonction effectue à la fois le codage et le décodage selon que l'argument est une chaîne ou un entier. J'ai mis à jour le message pour clarifier cela.
rturnbull
Le downvoter peut-il laisser un commentaire pour suggérer une amélioration? Merci.
rturnbull
1
Dans les commentaires de la question, dim précise que vous ne pouvez pas utiliser plus de 4 Go de mémoire ....
Socratic Phoenix