Purpose
The idea is to provide the code necessary to map a 32-bit integer to/from a pronouncable word of 9 characters maximum. That could be useful, for example, to make a serial number easier to remember, or type in a form.
Both the method for translating an integer to the corresponding word and for translating back a word to the corresponding integer are required.
Rules
There must be a one-to-one mapping between integers and words, and the whole set of 32-bit integers (or, put in another way, any integer from 0 to 4294967295) must be mappable. Although, obviously, not all words will be meaningful, and inputting words that don't map to an integer may have unspecified behavior.
You are free to decide on exactly which set of "pronouncable" words is meaningful, and how the mapping is done, but words must at least follow these rules:
- Only the basic 26 letters (A...Z) should be used as characters. Accents, casing, etc... should not be used to extend the possible combinations.
- 9 characters maximum per word.
- two consonants (BCDFGHJKLMNPQRSTVWXZ - 20 possiblities) should not be placed next to each other (they must be surrounded by vowels).
- two vowels (AEIOUY - 6 possibilities) should not be placed next to each other (they must be surrounded by consonants).
Note: the simplest scheme where you have all words constructed as CVCVCVCVC (C being a consonant and V a vowel) gives 4147200000 combinations, and a 32 bit integer has 4294967296 possible values, so it is not enough. You need to expand the number of combinations, either by allowing shorter words, or by allowing VCVCVCVCV combinations, as well.
Other standard rules apply, and standard loopholes are forbidden.
Inputs/Outputs
For each submission, two pieces of code must be provided:
- One that takes an integer as argument/input and returns/prints the corresponding word
- One that takes a word as argument/input and returns/prints the corresponding integer
Alternatively, you can choose to submit a single piece of code that handles both operations:
- When given an integer as an input, it outputs the corresponding word
- When given a string as an input, it outputs the corresponding integer
Winning condition
This is a code-golf, the answer which has the fewest bytes (when summing both pieces of code, for solutions opting for the separated pieces of code) wins.
-
\$\begingroup\$ Are there any space or time constraints? Do we have to fit within 32GB of memory? \$\endgroup\$John Dvorak– John Dvorak2017年04月06日 07:47:58 +00:00Commented Apr 6, 2017 at 7:47
-
\$\begingroup\$ @JanDvorak Well, we should be able to test your program on a "standard" computer. But the algorithm should be simple, what do you have in mind that requires such a massive amount of memory? \$\endgroup\$dim– dim2017年04月06日 07:49:55 +00:00Commented Apr 6, 2017 at 7:49
-
\$\begingroup\$ I could just generate all possible nine-letter words that match your formula and then index into the set or do a binary search. \$\endgroup\$John Dvorak– John Dvorak2017年04月06日 07:51:22 +00:00Commented Apr 6, 2017 at 7:51
-
\$\begingroup\$ @JanDvorak I must admit I didn't think of that. I was more thinking about solutions that were basically doing base-26 conversions, with some adjustments to satisfy the vowel/consonant constraint. But I somehow doubt the "brutal" way you had in mind can be code-golf efficient. Anyway, if I must really clarify this, let's say you are not allowed to allocate more than 4GB of memory. \$\endgroup\$dim– dim2017年04月06日 08:00:19 +00:00Commented Apr 6, 2017 at 8:00
-
\$\begingroup\$ You could require the answerers to run their code for some predetermined values (0,1,10,2**32-1 and such) and then back and to include the results in the answer. \$\endgroup\$John Dvorak– John Dvorak2017年04月06日 08:03:21 +00:00Commented Apr 6, 2017 at 8:03
3 Answers 3
PHP, 353 Bytes
Encoding + Decoding
is_numeric($argn) contains the boolean. It is true if the input is an integer.
$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 (Encode) + 195 Byte (Decode) = 385 Bytes
Encoding
$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 combinations are available
Online Version Encoding without E_NOTICE
Expanded
$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
Input => Output
4294967296 => TYPYQACOV
333 => DAT
1 => E
7 => C
4294967276 => UTOPOQAMI
If you need always 9 Byte result please replace while($a) with while(strlen($r)<9) + 10 Bytes
Decoding
$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;
Expanded
$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;
Input => Output
ABABABABE => 1
E => 1
UTOPOQAMI => 4294967276
BABABADAT => 333
DAT => 333
TYPYQACOV => 4294967296
Online Version Decoding without E_NOTICE
Additional Check
If we need a check if a string is valid.
Add $x.=$b?:0; in the end of the decoding loop + 10 Bytes
Replace echo$s; with echo!preg_match('#([01])1円$#',$x)?$s:_; + 32 Bytes
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
Cutoff point between CVCVCVCVC and VCVCVCVCV is 4e9, so starts going wrong at 5244160000 (numeric input) or zesuwurib (string input).
-
\$\begingroup\$ Six months later... I award you the accept points, since you're the shortest (and I can't accept rturnbull's answer, which does not satisfies the clarification I made in the comments). \$\endgroup\$dim– dim2017年09月11日 18:40:05 +00:00Commented Sep 11, 2017 at 18:40
R, 165 bytes
Encoding and decoding in one function.
This function uses the brute-force method of creating all possible values and then simply returning the index when it's given string input and returning the string when given integer input. As a consequence, it's very slow and uses 16GB+ of memory!
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 values are possible. This covers all strings of form CVCVCVCV(C), with the last C being optional.
-
\$\begingroup\$ @mbomb007 Gigabytes, sorry for the typo. The function does both encoding and decoding depending on whether the argument is a string or an integer. I've updated the post to clarify that. \$\endgroup\$rturnbull– rturnbull2017年04月06日 14:22:38 +00:00Commented Apr 6, 2017 at 14:22
-
\$\begingroup\$ Can the downvoter leave a comment to suggest improvement? Thanks. \$\endgroup\$rturnbull– rturnbull2017年04月06日 18:59:53 +00:00Commented Apr 6, 2017 at 18:59
-
1\$\begingroup\$ In the comments of the question, dim clarifies that you cannot use more than 4gb of memory.... \$\endgroup\$Socratic Phoenix– Socratic Phoenix2017年04月24日 15:53:43 +00:00Commented Apr 24, 2017 at 15:53