8
\$\begingroup\$

You know those riddles where every letter is swapped for another letter?

E.g. you get a text like

JME JG EPP IFAPE EPJE CJPPPC BP,
      UIJCG JC EPP EFE GPJB EJIP EJ EJIP,
F EPJIG MPJEPPPP AJUC BJL UP
      GJP BL MICJIJMPPJUIP CJMI.

and are supposed to find out that it stands for

OUT OF THE NIGHT THAT COVERS ME,
      BLACK AS THE PIT FROM POLE TO POLE,
I THANK WHATEVER GODS MAY BE
      FOR MY UNCONQUERABLE SOUL.

This example was created by the following replacement matrix:

ABCDEFGHIJKLMNOPQRSTUVWXYZ
ODSXHKARFYGNBIQTJVCEWZMULP

Try to unscramble any given text by doing a letter frequency analysis. Assume that the most common letters in the given input are (left to right): EARIOTNSLCUDPMHGBFYWKVXZJQ

  • Replace the most common letter in the input by E, the next most common by A, and so on
  • Producing a correctly unscrambled text is actually outside the scope of this challenge. That is, we assume that you get a correct result if only the input is large enough. (Testcase 1)
  • If there is insufficient data, your return value must be consistent with the data provided. (Testcase 2)
  • You may expect uppercase text only. It can contain digits, punctuations etc., which are not scrambled and to be output as is.

This is a code golf, shortest answer in bytes wins. Standard loopholes apply.

Testcase 1 - The shortest completely solvable one

CCCCCCCCCCCCCCCCCCCCCCCCCCPPPPPPPPPPPPPPPPPPPPPPPPPIIIIIIIIIIIIIIIIIIIIIIIIFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEELLLLLLLLLLLLLLLLLLLLLPPPPPPPPPPPPPPPPPPPPFFFFFFFFFFFFFFFFFFFGGGGGGGGGGGGGGGGGGEEEEEEEEEEEEEEEEEIIIIIIIIIIIIIIIITTTTTTTTTTTTTTTMMMMMMMMMMMMMMJJJJJJJJJJJJJAAAAAAAAAAAAAAAAAAAAAAAWWWWWWWWWWDDDDDDDDDBBBBBBBBBBBBBBBFFFFFFTTTTTJJJJWWWIIP

must output

EEEEEEEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAARRRRRRRRRRRRRRRRRRRRRRRRIIIIIIIIIIIIIIIIIIIIIIIOOOOOOOOOOOOOOOOOOOOOOTTTTTTTTTTTTTTTTTTTTTNNNNNNNNNNNNNNNNNNNNSSSSSSSSSSSSSSSSSSSLLLLLLLLLLLLLLLLLLCCCCCCCCCCCCCCCCCUUUUUUUUUUUUUUUUDDDDDDDDDDDDDDDPPPPPPPPPPPPPPMMMMMMMMMMMMMHHHHHHHHHHHHGGGGGGGGGGGBBBBBBBBBBFFFFFFFFFYYYYYYYYWWWWWWWKKKKKKVVVVVXXXXZZZJJQ

Testcase 2

HALLO WORLD must output ??EEA<space>?A?E?:

  • The 3 Ls turn into E
  • The 2 Os turn into A
  • The remaining letters are each replaced by an undefined permutation of the letters "RIOTN", without any of these repeating.
\$\endgroup\$
  • 2
    \$\begingroup\$ @ZsoltSzilagy Didn't vote to close, but I think the only thing that needs clarification is what to do in test case 2. I think I can infer the correct thing to do, but in the actual explanation (in the third bullet point after the example), it just refers to test case 2 without a very clear explanation of what to do exactly. \$\endgroup\$ – Redwolf Programs Oct 18 at 1:28
  • 6
    \$\begingroup\$ Also, your first test case doesn't seem to be correct. \$\endgroup\$ – Redwolf Programs Oct 18 at 1:35
  • 4
    \$\begingroup\$ Your initial example doesn't seem to match the replacement matrix. Too many letters have been replaced by P. \$\endgroup\$ – xnor Oct 18 at 3:30
  • 3
    \$\begingroup\$ @ZsoltSzilagy I will gladly vote to reopen if you fix those two things. I (and, it appears, many other people!) think this is a good challenge, it just needs a few points clarified. \$\endgroup\$ – Redwolf Programs Oct 18 at 14:02
  • 1
    \$\begingroup\$ May we write code that instead expects only lower-case characters? \$\endgroup\$ – Jonathan Allan Oct 18 at 18:50
1
\$\begingroup\$

JavaScript (V8), 185 bytes

c=>(l={},[...c].map(i=>l[i]=(l[i]|0)+1),e=Object.entries(l).sort((a,b)=>b[1]-a[1]).map(i=>i[0]).filter(i=>parseInt(i,36)>9),[...c].map(i=>"EARIOTNSLCUDPMHGBFYWKVXZJQ"[e.indexOf(i)]||i))

Try it online!

Doesn't currently pass the second test case, but instead is based on OP's description of how the unscrambling works. The test case seems to be incorrect at the moment, as some groups of letters (like F or P) repeat letters.

Explanation:

c=>(                            // Define arrow function with argument c
l={},                           // Create an empty object l
[...c].map(i=>                  // For each character i in c...
  l[i]=(l[i]|0)+1),               // Increment l[i] (the number of times i appears)
e=Object.entries(l)             // Format l as an array ["x", <number of times "x" appears>] in variable e
.sort((a,b)=>b[1]-a[1])         // Sort e so most common characters are first
.map(i=>i[0])                   // Get rid of number of times appeared
.filter(i=>parseInt(i,36)>9),   // Filter out non-letters using base 36 conversion :)
[...c].map(i=>                  // For each character i in c...
  "EARIOTNSLCUDPMHGBFYWKVXZJQ"[   // Get the nth item from the frequency chart...
    e.indexOf(i)]                   // Where n is the index of i in e
    ||i))                         // Unless it isn't a letter, where i stays i
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Jelly, 35 bytes

“@u@Rṭ$3=ỊẈṘ’œ?ØA;0
QfØAċ@ÞðṚiⱮị¢ðo

Try it online!

Like Redwolf Programs' JS solution, this technically fails both given test cases, but seems to be consistent with the intent of the challenge.

| improve this answer | |
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.