16
\$\begingroup\$

Rotonyms 1

ROT13 ("rotate by 13 places") is a simple letter substitution cipher that replaces a letter with the 13th letter after it, in the alphabet. So, A becomes N, N becomes A, B <-> O, and so on to M <-> Z.

ROT13('abcdefghijklmnopqrstuvwxyz') == 'nopqrstuvwxyzabcdefghijklm'

A "Rotonym" is a word (pair) that ROT13s into another word (in the same language).

For example:

ROT13('Terra') == 'Green'

The Challenge

Write a program or function that accepts a dictionary/word list and prints or returns a complete list of rotonyms.

  1. Order doesn't matter.
  2. Comparisons should be case-insensitive. Since the code can accept a dictionary, you can assume it will be passed a lower-case-only dictionary.
  3. Result should be expressed as single words (not the pairs) and contain no duplicates.
  4. This is .

Example

Given

ask
green
irk
me
terra
vex
you

Return

green
irk
terra
vex

A Real Test

Given

ab aba abba abe abjurer abo acieral acock adoxy advised adviser aefald affeer agena ah aha ahaunch aho ajowan albe alula alypin amesite amidic amidin amylin an ana anakes analogy anan anil ann anorexy ant apaid aparai ar arba arc areek argyle argyria arn arne aro arsheen arshin asaphic assegai atresic audian aum avar avertin avo avoid awesome ba babiism baler balita balk ban bana bar baraca bare batino bauson bawra baywood be beamage beamed bean becuna bedaub beg begrime bel bell ben ber bes beshlik beyond bhang bickern bimane bin birl bizonia bloat blunter bolero bonded bonnie boozer bor borasca boun boxhaul brava bromoil bronc bu bub bucksaw buggy built bullism bunga bunny bunt burion buttery byerite cabinda cadjan cadrans calas calends callus cameist cant capulet carpent cater caution cayuga censor cha chab chack chal chat chatta che chechen chee cheer cheery cheney chevon chian chirr cho chob cholo chopin city clerk clouted clover coach coder codworm coeval coff colic color conopid consul contra coraise corneum coster coueism cougnar couxia cowbind coz crag craggan crax crea creel crete crex crissal cross crowder cub cuba cuculus cullen cullion cur cuvy cymar czarian dabb dalles damson dand darger decapod decream deeping delible demi deworm dhanush dhoon didym diehard dill dineric disglut diss doghole donnish dorab doubled downy drop droshky dubb ducker dudish duit dungan durance ebony ehlite ejam eleven ella elohism eluder en enation endear endew enrut envy er erava erg erikite erne err ers evasive facient faden falisci fant faro fetish figment filite finless fipenny fitchet fiuman flabby flap flirter flyboat fogon foiler footle forgot fra fracas fraghan frank frater freir fu fub fubby fun fundic funt fur fury fusc gangdom ganglia gaonate garbel gast gaul gear geat gel gen gena genny gent genu gerenuk gers ghan ghat ghee gist gledy glee gnar gnat gnawing godpapa gordian gouda gra graddan granter grat greeny grr grummet grutch guacin guesten gul gun guna gunj gur gurl gurr ha hack haler hallage han haught haver he hein hen henotic her hern hetaery hexine hin hippus hiro hirudin hissing hoer hoghood homo hooklet horned howe hundi huspil hydrula hyppish ideally illeck imbed imburse immi impasse incog ing integer iowan iraq irk isobare isocrat istle ithacan ivan ivin ivoried jaunce jerry jitters juergen juha jun june junior jura kalends keacorn kemple kialee kinch kippeen kittul kohen koli komati koniga kulimit la laine lamb lapel laurate led leeward lexia liman linin linten lipan lisper loave lobcock loom luite maestri magiric mahra maimer mannose mano manuao map marcher marcid married mary maun maundy maxim medal meddler mentum merfold mew mho miamia midwise milchy molary molpe moslem mousse mudden mun muricid mysidae mysore myxa na naa nag nakhod namer nan nana navy ne nea neb neon nep nettler newtake nib nine ninon nizamut no nob nobby nodding nodiak non noon nor nourice nowhere nu nub nucleus numeral nun nunnery obe octose odso oenin off ogam ogor oh oho omasum omitter on ona onan one oner oniscus onyx oppidan or ora ore orf orlo orna orotund orphan ort ory osamine ourie outpay ova overget ovey palama paludic panical panisic pavia penk pent perjury perk pern perry phil pho phon phonics pickee picture pien pimpled piously pirl pit platty pledger pollack pomato ponerid poria postic poteye poulter pounce powdry prefer privy profile pross pruner psaltes psylla pub pun punatoo pung punicin puno puny pur purpura purr purre purrel pusscat pyrex pyropen pyropus quader qubba ra rabi rabitic rail rappage rarity re reaal rear rebend redcoat redweed ree rees ref regrasp reluct renin replate reseize residua ret retour retral rheic rhymer rife rifling ripping robing rohuna romanly romic rookish rumor rupial sairve saltant saltery salvo samekh scissel scraw scrubby seafolk seaware seldor sen serer serve setness seton setsman setting settlor sex sexto sh sha shag shave she shedded shel sher sho shool showish shrinal shrip shrove sievy sinus sinusal sirrah sis skither slait sley slicken slinker sloven smoker snag snap snath sneb sniping snithe soiling sort sourer spalax spent spex spidger spirt spiry spryly spyship squalor stilt strive strue styrian sucuriu suevi summary sumpter sundry swahili sylphy sync taccada talao tane tang tanghin tanglad tankert tarazed tarve taxon tealery teaser tecuna tee telical ten teng tercio terral terrify testily tha than thaw the thecate thee theft they thistle thob thole thone thorny thy thymoma timawa tiphead titrate toadess tomnoup tomosis toplike toryess tra trag trah train tran tref tremble triarch trilobe try tubbie tueiron tumored tuna tung tuning turfdom turr tweil tyrr ulcery un una unaloud unfrank unionid unkeyed unlit unmount unoften unpiety unscent unspike unurban unwhig unwon upperch uprid ur ura ure urea urocyon urva usurp uta utopian uva vacancy vacuist valkyr valois vapored vari vat vejoces vend verd vesbite vesicae vex victim vina vitals viva walloon warori warp waucht wearily weblike wedded weftage wha whample whar when whence whites whorish whun wilhelm wincey wog woodlet wouch wuzzer yakona yamp yaru yerava yezdi ym yn za zimme

Return

ab aba abba abe abjurer abo ah aha aho an ana anan anil ann ant ar arba arc arn aro avar avo ba balk ban bana bar bare be bean becuna beg bel ben ber bes bin birl bor brava bu bub cha chab chal chat che chechen chee cheer cheery cho clerk crag crax crea creel crex cub cuba cuvy dhoon en envy er erava erg erne err ers fant faro flap fra freir fu fub fubby fun funt fur fury gel gen gena gent genu gers ghan ghat ghee glee gnar gnat gra grat greeny grr gul gun guna gunj gur gurl gurr ha han he hein hen her hern hin ing iraq irk ivan ivin juha jun june jura la na naa nag nan nana navy ne nea neb neon nep nib nine no nob non noon nor nowhere nu nub nun obe oenin oh oho on ona onan one oner onyx or ora ore orf orna orphan ort ory ova ovey penk pent perk pern perry phil pho phon pub pun pung puno puny pur purpura purr purre purrel pyrex qubba ra rail re rear ree ref renin ret sen serve sh sha shag she shel sho shool snag sneb sync tane tang tee ten teng terral tha than thaw the thee they thy tra trag trah tran tref try tuna tung turr tyrr un una ur ura ure urea urva uva vat vend vex vina viva wha whar when whun yn
\$\endgroup\$
3
  • \$\begingroup\$ May we instead take an uppercase dictionary? \$\endgroup\$
    – Adám
    May 29, 2018 at 15:08
  • \$\begingroup\$ Yes. My intention with point 2 was to remove case as a consideration, so, either way is fine. \$\endgroup\$
    – Umbrella
    May 29, 2018 at 15:10
  • \$\begingroup\$ I added a larger test set. Take a shot at it! \$\endgroup\$
    – Umbrella
    May 30, 2018 at 14:56

20 Answers 20

7
\$\begingroup\$

Jelly, 7 bytes

Two bytes were saved by turning this into a function, as suggested by @EriktheOutgolfer.

A function expecting a list of strings in lowercase and returning a list of Jelly strings.

O_5ịØaf

Try it online!

How?

O_5ịØaf    - link taking a list of strings such as ['irk','me','vex']
O          - convert to ASCII codes         --> [[105,114,107], [109,101], [118,101,120]]
 _5        - subtract 5 ((-96 + 13) mod 26) --> [[100,109,102], [104, 96], [113, 96,115]]
    Øa     - yield the lowercase alphabet   --> 'abcdefghijklmnopqrstuvwxyz'
   ị       - pick new letters from there
             (modulo 26)                    --> ['vex','zr','irk']
      f    - filter out elements that are
             not in the original list       --> ['vex','irk']
\$\endgroup\$
1
  • \$\begingroup\$ This also works against the extended test I added! \$\endgroup\$
    – Umbrella
    May 31, 2018 at 19:03
6
\$\begingroup\$

Attache, 12 bytes

{Rot=>_∩_}

Try it online! (10 chars)

I thought I'd never see the day where Rot came in handy... :D

On Attache's showcase entry, I said that Rot is a residual command from its days of being a joke language. It's default behaviour is Rot13.

Explanation

{Rot=>_∩_}
{        }    anonymous lambda. argument: _
 Rot=>_       calculate all rot-13 shifts of each item in _
       ∩_     and keep only those that were in _ (by using an intersection)

Extended test case

Try it online!

Alternatives

14 bytes: {_&Has\Rot=>_}

14 bytes: {`in&_\Rot=>_}

(Both of these work by filtering using functions.)

\$\endgroup\$
3
  • \$\begingroup\$ This appears to be missing "no" from the extended test. It might be relevant that "no" is the ROT13 if "ab" which is the first element of the input. \$\endgroup\$
    – Umbrella
    May 31, 2018 at 19:23
  • \$\begingroup\$ @Umbrella Not sure what you mean. It seems to work just fine. See my edit for the extended test case. \$\endgroup\$ May 31, 2018 at 19:30
  • \$\begingroup\$ I'm not sure either... I opened your first link, pasted in the input and compared the output, came up short. I can see your new link yields the complete result, though. \$\endgroup\$
    – Umbrella
    May 31, 2018 at 21:13
5
\$\begingroup\$

Python 2, 70 63 bytes

lambda l:l&{''.join(chr((ord(c)-6)%26+97)for c in w)for w in l}

Try it online!

\$\endgroup\$
4
\$\begingroup\$

Python 2, 40 bytes

lambda l:l&{w.encode('rot13')for w in l}

Try it online!

\$\endgroup\$
3
  • \$\begingroup\$ Python is strange \$\endgroup\$
    – ovs
    May 30, 2018 at 21:53
  • \$\begingroup\$ @ovs OMG. Though, this might be helpful in character-restricted challenges \$\endgroup\$ May 31, 2018 at 12:13
  • \$\begingroup\$ What magic is this? \$\endgroup\$
    – Umbrella
    Jun 1, 2018 at 14:07
4
\$\begingroup\$

MATL, 16 bytes

tot2Y2t13YSXEXm)

Try it online!

Explanation

The stack is shown upside down, that is, the most recent element is below.

t        % Implicit input: cell array of strings. Duplicate
         % STACK: {'ask' 'green' 'irk' 'me' 'terra' 'vex' 'you'}
         %        {'ask' 'green' 'irk' 'me' 'terra' 'vex' 'you'}
o        % Convert to double. Gives a matrix, right-padding with 0
         % STACK: {'ask' 'green' 'irk' 'me' 'terra' 'vex' 'you'}
         %        [97 115 107   0   0; ...; 121 111 117   0   0]
t        % Duplicate
         % STACK: {'ask' 'green' 'irk' 'me' 'terra' 'vex' 'you'}
         %        [97 115 107   0   0; ...; 121 111 117   0   0]
         %        [97 115 107   0   0; ...; 121 111 117   0   0]
2Y2      % Push predefined literal 'abc...xyz'
         % STACK: {'ask' 'green' 'irk' 'me' 'terra' 'vex' 'you'}
         %        [97 115 107   0   0; ...; 121 111 117   0   0]
         %        [97 115 107   0   0; ...; 121 111 117   0   0]
         %        'abc...xyz'
t13YS    % Duplicate. Circularly shift by 13 positions
         % STACK: {'ask' 'green' 'irk' 'me' 'terra' 'vex' 'you'}
         %        [97 115 107   0   0; ...; 121 111 117   0   0]
         %        [97 115 107   0   0; ...; 121 111 117   0   0]
         %        'abc...xyz'
         %        'nop...klm'
XE       % Replace entries in the 1st input that are in the 2nd input by
         % those of the 3rd input 
         % STACK: {'ask' 'green' 'irk' 'me' 'terra' 'vex' 'you'}
         %        [97 115 107   0   0; ...; 121 111 117   0   0]
         %        [110 102 120   0   0; ...; 108  98 104   0   0]
Xm       % Ismember-rows: true for rows of 1st input that are in the 2nd
         % STACK: {'ask' 'green' 'irk' 'me' 'terra' 'vex' 'you'}
         %        [false; true; true; false; true; true; false]
)        % Index. Implicit display
         % STACK: {'green' 'irk' 'terra' 'vex'}
\$\endgroup\$
4
\$\begingroup\$

APL (Dyalog Unicode), 19 17 bytesSBCS

Anonymous tacit prefix function, taking a list of uppercase words. Assumes ⎕IO (Index Origin) to be 0, which is default on many systems.

⊢∩{⎕A[⍵⍳⍨13⌽⎕A]}¨

Try it online! (edit: now with big word list!)

 the argument's

 intersection with

{ the result of the following function applied to each word ( is the word):

⎕A[] index the uppercase Alphabet with:

  ⍵⍳⍨ the indices of the word into

  13⌽ the rot-13 of

  ⎕A the uppercase Alphabet

\$\endgroup\$
3
\$\begingroup\$

Retina 0.8.2, 42 bytes

.+
$&¶$&!
T`l`n-zl`.+!
O`
!`\b(.+)(?=¶\1!)

Try it online! Explanation:

.+
$&¶$&!

Duplicate all of the words, suffixing a ! to the duplicate.

T`l`n-zl`.+!

ROT13 all of the duplicates.

O`

Sort the words.

!`\b(.+)(?=¶\1!)

Find the duplicates.

\$\endgroup\$
3
\$\begingroup\$

JavaScript (Node.js), 59 bytes

Saved 1 byte thanks to @ovs

Takes input as an array of strings in lowercase. Returns an array of strings.

a=>a.filter(s=>a.some(S=>Buffer(S).map(c=>(c-6)%26+97)==s))

Try it online!

Commented

a =>                  // given the input array a[]
  a.filter(s =>       // for each string s in a[]:
    a.some(S =>       //   for each string S in a[]:
      Buffer(S)       //     create a buffer from S (deprecated method)
      .map(c =>       //     for each byte c in the buffer:
        (c - 6) % 26  //       apply rot13 transformation ((-97 + 13) mod 26 = -6)
        + 97          //       and convert it back to [a-z]
      ) == s          //     implicit coercion to string; compare with s
    )                 //   end of some()
  )                   // end of filter()
\$\endgroup\$
4
  • \$\begingroup\$ (c-84)%26 can be (c-6)%26. \$\endgroup\$
    – ovs
    May 29, 2018 at 16:07
  • \$\begingroup\$ @ovs Ugh. Indeed it can. Thanks! \$\endgroup\$
    – Arnauld
    May 29, 2018 at 16:10
  • \$\begingroup\$ @Arnauld I haven't used Buffer before. Can you explain how this works? \$\endgroup\$
    – Umbrella
    May 31, 2018 at 15:37
  • 1
    \$\begingroup\$ @Umbrella I've added a commented version. Note that Buffer does not exist on browsers. It's a Node thing. The deprecated method I'm using is this one. \$\endgroup\$
    – Arnauld
    May 31, 2018 at 15:54
2
\$\begingroup\$

Perl 6,  57  35 bytes

.say for ($/=lines.Set).keys.grep:{$/{TR/a..z/n..za..m/}}

Try it

{@^a.grep:{@a∋TR/a..z/n..za..m/}}

Try it

Expanded:

{  # bare block lambda with placeholder parameter @a

  @^a                # declare and use placeholder parameter
  .grep:             # find all the values in it that match the following
  {
    @a
    ∋                 # Set contains operator
    TR/a..z/n..za..m/ # do the rotation on the grepped value
  }
}
\$\endgroup\$
2
\$\begingroup\$

Ruby, 45 35 bytes

-10(!) thanks to G B

->a{a&a.map{|x|x.tr"a-z","n-za-m"}}

Try it online!

\$\endgroup\$
1
1
\$\begingroup\$

Python 2, 101 94 bytes

lambda d:[w for w in d if{''.join(chr((ord(c)+i)%26+97)for c in w)for i in range(26)}&(d-{w})]

Try it online!

Takes a set of words (lowercase), and returns a list of rotonyms.

\$\endgroup\$
1
\$\begingroup\$

Perl 5 -a, 40 bytes

y/a-z/n-za-m/;for$i(@F){/\b$i\b/&&say$i}

Try it online!

Input is as a space separated list of words.

\$\endgroup\$
1
\$\begingroup\$

C (gcc), 137 bytes

char*a,*b,x[99];f(_)char*_;{strcpy(x,_);for(a=strtok(x," ");a=strtok(0," ");strstr(_,a)&&printf("%s ",a))for(b=a;*b;++b)*b=(*b-6)%26+97;}

Try it online!

Description:

char*a,*b,x[99];                        // Variables
f(_)char*_;{                            // f(space separated string)
    strcpy(x,_);                        // copy input to x
    for(a=strtok(x," ");                // loop from first word
        a=strtok(0," ");                // to last word
        strstr(_,a)&&printf("%s ",a))   // at each step printing if found in original string
                                        // this occurs after the next loop which
                                        // rot13's the loop argument 'a'
        for(b=a;*b;++b)                 // for each character in a
            *b=(*b-6)%26+97;}           // set it to its rot13 variant (x-6)%26+97 for ascii
\$\endgroup\$
1
\$\begingroup\$

Python 3, 68 60 bytes

lambda d:d&{encode(w,"rot13")for w in d};from codecs import*

Although we could put the import on the previous line without penalty, it just seems more amusing this way. The function now only accepts the dictionary as a set, which makes a huge performance improvement for very large dictionaries.

\$\endgroup\$
1
\$\begingroup\$

05AB1E, 13 12 10 bytes

εAA2äRJ‡}Ã

-2 bytes thanks to @Emigna.

Try it online.

Explanation:

            # example input: ["ask","green","irk","terra"]
ε       }   # For-each over the input-list:
 A          #  Take the lowercase alphabet twice
  A2äRJ     #  Split the alphabet in halve, reverse both parts, and joined it back together
            #   → nopqrstuvwxyzabcdefghijklm
       ‡    #  Transliteral; changing the characters in the input-words, from 
            #  the letters in the alphabet, to the letters in the ROT-13 alphabet
            #   → ['nfx','terra','vex','green']
         Ã  # Remove all items from the input-list, that are not in the list above
            #  → ['green','terra']

Old 12-byte version:

Ç6-₂%εAsèJ}Ã

-1 byte thanks to @Emigna changing мм to à (couldn't find this builtin myself in the available commands).

Try it online.

Explanation:

               # example input: ["ask","green","irk","terra"]
Ç              # Convert all input-characters to their unicode values
               #  → [[97,115,107],[103,114,101,101,110],[105,114,107],[116,101,114,114,97]]
  6-₂%         # Subtract 6, and take modulo-26
               #  → [[13,5,23],[19,4,17,17,0],[21,4,23],[6,17,4,4,13]]
      ε    }   # For-each:
       Asè     #  Take the letters from the lowercase alphabet at the calculated indices
               #   → [['n','f','x'],['t','e','r','r','a'],['v','e','x'],['g','r','e','e','n']]
          J    #  Join all letters together again
               #   → ['nfx','terra','vex','green']
            Ã  # Remove all items from the input-list, that are not in the list above
               #  → ['green','terra']
\$\endgroup\$
2
  • 1
    \$\begingroup\$ εAA2äRJ‡}Ã should work. \$\endgroup\$
    – Emigna
    May 30, 2018 at 8:50
  • \$\begingroup\$ @Emigna Ah nice approach with and A2äRJ. Didn't even knew about .. I think I'll have to look at every command and make some basic test programs for myself to better understand their usages and what is available.. ;) \$\endgroup\$ May 30, 2018 at 9:04
1
\$\begingroup\$

Java (JDK 10), 97 bytes

l->l.stream().filter(s->l.contains(new String(s.chars().map(m->m%26+65).toArray(),0,s.length())))

Try it online!

\$\endgroup\$
0
1
\$\begingroup\$

Pyth, 11 bytes

@ms@LGm-Ck6

Try it online

Expects input as an array of lowercase words. Explanation:

@ms@LGm-Ck6dQQ   Q=input(), final 3 tokens are implicit

 m          Q    For each word d in input, map over...
      m    d       For each letter k in d, map over...
        Ck           Convert to ASCII code point
       -  6          Subtract 6
   @LG             Modular index each over the lowercase alphabet (G)
  s                Join each array of chars into a string
@            Q   Filter the input on presence in the resulting set
\$\endgroup\$
1
\$\begingroup\$

Julia 0.6, 49 bytes

W->filter(w->String(([w...].-'S')%26.+'`')∈W,W)

Try it online!

Takes a Set of words and returns a Set of rotonyms.

[w...] takes a string w and "explodes" it into an array of Chars, which enables us to do arithmetic on it. The String call does the reverse, making a string from an array of Chars after the arithmetic operations are done. We have to subtract 'S' and not 83, because Char-Char is an Int on which % works, whereas Char-Int is a Char which would lead to an error. Similarly, adding '`' changes the result of the mod from Int back to a Char, which is necessary for the String call to work.

\$\endgroup\$
0
\$\begingroup\$

JavaScript, 93 bytes

Takes input as an array of lowercase words, filters the array by the result of a lookup for the rot13 result.

d=>d.filter(t=>d.indexOf(t.replace(/[a-z]/ig,c=>((parseInt(c,36)+3)%26+10).toString(36)))>-1)
\$\endgroup\$
0
\$\begingroup\$

PHP, 60 bytes

Given an array of words, echos only those having a rotonym match

foreach($l as$w)if(in_array($j=str_rot13($w),$l))echo"$w\n";

Try it online!

\$\endgroup\$
2
  • 3
    \$\begingroup\$ It is recommended to wait at least a couple of hours -- or preferably a couple of days -- before answering your own question, especially in languages that have not been used so far. \$\endgroup\$
    – Arnauld
    May 29, 2018 at 14:36
  • 2
    \$\begingroup\$ That makes sense. I'll remember moving forward. Thanks! For now, I'll hide it in a spoiler tag. \$\endgroup\$
    – Umbrella
    May 29, 2018 at 15:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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