Given a string you must move each letter (starting from the first letter) by its position in the alphabet. If you reach the end of the string you must wrap around. Non-letters don't need to be moved.



D is the fourth letter in the alphabet so we move it four spots to the right. After wrapping around, that changes the string to oDg. o is the 15th letter, (15 mod 3) = 0, so it does not move. g is the 7th letter - (7 mod 3) = 1, so the string becomes goD.


  • h is the 8th letter, move it 8 spots - hi*bye => i*hbye
  • i is the 9th letter, move it 9 spots - i*hbye => *hbiye
  • b is the 2nd letter, move it 2 spots - *hbiye => *hiybe
  • y is the 25th letter, move it 25 spots - *hiybe => *hibye
  • e is the 5th letter, move it 5 spots - *hibye => *hibey

Non-letters don't need to be moved, but they still take up space.

  • cat => tca
  • F.U.N => .F.NU
  • mississippi => msiisppssii
  • \$\begingroup\$ Do we have to do a standalone program or a function is enough? Also, do we have to print the string? \$\endgroup\$
    – Katenkyo
    Dec 14, 2015 at 8:51
  • \$\begingroup\$ What characters can appear in the input? Printable ASCII? Linefeeds? Any ASCII? Any Unicode? \$\endgroup\$ Dec 14, 2015 at 9:44
  • 3
    \$\begingroup\$ Also a test case with repeated letters would be good. \$\endgroup\$ Dec 14, 2015 at 10:00
  • \$\begingroup\$ @Martin Any ASCII. \$\endgroup\$
    – geokavel
    Dec 14, 2015 at 15:31
  • \$\begingroup\$ @Katenkyo function is allowed. If you are using a function, then output is the return value. \$\endgroup\$
    – geokavel
    Dec 14, 2015 at 15:33

5 Answers 5


CJam, 44 42 40 bytes


Output contains a trailing linefeed.

Test it here.


Instead of moving the letters through the string, I repeatedly remove a letter, rotate the string accordingly, and then reinsert the letter. There's one catch for doing this: we need to be able to distinguish the beginning of the string from the end of the string (which we can't after a simple rotation). That's why we insert a linefeed at the end as a guard (letter before the linefeed is the end of the string, letter after it is the beginning). The bonus is that this automatically returns the final string to the correct rotation where the linefeed actually is at the end of the string.

lN+     e# Read input and append a linefeed.
ee      e# Enumerate the array, so input "bob" would become [[0 'b] [1 'o] [2 'b] [3 N]]
        e# This is so that we can distinguish repeated occurrences of one letter.
_{      e# Duplicate. Then for each element X in the copy...
  Xa/   e# Split the enumerated string around X.
  ~     e# Dump the two halves onto the stack.
  \+    e# Concatenate them in reverse order. This is equivalent to rotating the current
        e# character to the front and then removing it.
  XW=   e# Get the character from X.
  eu    e# Convert to upper case.
  _     e# Duplicate.
  _el=! e# Check that convert to lower case changes the character (to ensure we have a
        e# letter).
  \'@-  e# Swap with the other upper-case copy and subtract '@, turning letters into 1 to
        e# 26 (and everything else into junk).
  *     e# Multiply with whether it's a letter or not to turn said junk into 0 (that means
        e# everything which is not a letter will be moved by 0 places).
  m<    e# Rotate the string to the left that many times.
  Xa+   e# Append X to the rotated string.
Wf=     e# Extract the character from each pair in the enumerated array.

To see why this ends up in the right position, consider the last iteration of the hi*bye example. After we've processed the e, the enumerated string is in this position:

[[4 'y] [6 N] [2 '*] [0 'h] [1 'i] [3 'b] [5 'e]]

First, we split around the linefeed and concatenate the parts in reverse order:

[[2 '*] [0 'h] [1 'i] [3 'b] [5 'e] [4 'y]]

The linefeed would now be either at the beginning or the end of this string. But since the linefeed is just a guard that marks the end of the string, this means that the characters are actually in the right order. Now the linefeed is not a letter, so that the array is not rotated at all. Thus, when we append the linefeed, it goes where it belongs, and everything is in the order we're looking for:

[[2 '*] [0 'h] [1 'i] [3 'b] [5 'e] [4 'y] [6 N]]

Some additional results if someone wants to compare longer test cases:

Hello, World!
,W oeHlo!lrld

Programming Puzzles & Code Golf
ago fgliPomomnrr elP& uC dezzsG

The quick brown fox jumps over the lazy dog
t eg chbi ko qfTounyzrj omw epx ueoahs rlvd



I like that last one. :)

  • \$\begingroup\$ Pyth needs chop list on list. \$\endgroup\$
    – isaacg
    Dec 14, 2015 at 23:04
  • \$\begingroup\$ @isaacg Nah, I'm sure it doesn't. ;) \$\endgroup\$ Dec 14, 2015 at 23:11
  • \$\begingroup\$ Could you make it so it supports multi-line strings? \$\endgroup\$
    – geokavel
    Dec 15, 2015 at 0:01
  • \$\begingroup\$ @geokavel Oh right, fixed. \$\endgroup\$ Dec 15, 2015 at 13:34
  • \$\begingroup\$ The sith is pleased, Darth Büttner. \$\endgroup\$
    – geokavel
    Dec 21, 2015 at 3:14

Ruby 125 130 132 139 bytes

while i=a.index{|c,s|s}
c,s=a.delete_at i
a.insert (i+s)%q.size,[c]

Online demo with tests: http://ideone.com/GYJm2u

The initial (ungolfed version): http://ideone.com/gTNvWY

Edit: Big thanks to manatwork for his suggestions!

Edit 2: fixed character count (I was initially counting CRLF line endings.)

  • \$\begingroup\$ Just barely tested: c.upcase.ord-64c.ord%32. \$\endgroup\$
    – manatwork
    Dec 14, 2015 at 10:50
  • \$\begingroup\$ @manatwork That works fine, thanks! \$\endgroup\$ Dec 14, 2015 at 11:35
  • \$\begingroup\$ Looking again… Wait! a.join??? Who are you and what have you done with w0lf? He would certainly write it as a*''. \$\endgroup\$
    – manatwork
    Dec 14, 2015 at 11:42
  • \$\begingroup\$ @manatwork :) I was so upset about having a while ... end in my code that I forgot to do that. Thanks for noticing! \$\endgroup\$ Dec 14, 2015 at 11:44
  • \$\begingroup\$ can't you turn that while ... end into (...)while ...? \$\endgroup\$ Dec 14, 2015 at 12:21

Python 3, 278 275 273 270 260 258 249 248 243 238 bytes

I should really golf this down better, but here is my solution, with thanks to katenkyo for his help with the logic, and to Cyoce and Mego for their help with the golfing.

Edit: At last, I got it down to one comparison statement. WOO! (And yes, I could move that z=-z into a,m=m,a bit, but that doesn't save bytes and it muddled the code more than I thought was necessary)

Edit: Byte count was off.

def m(s):
 l=len(s);r=range(l);p=[[i,s[i]]for i in r]
 for i in r:
  if s[i].isalpha():
   if a>m:a,m=m,a;z=-z
   for j in r:p[j][0]-=z*(j!=i)*(a<=p[j][0]<=m) 


def move(string):
 length = len(string)
 places = [[i,string[i]]for i in range(length)]
 for index in range(length):
  char = string[index]
  if char.isalpha():
   a = places[index][0]
   mov = (a + ord(char)%32) % length
   places[index][0] = mov
   for j in range(length):
    k = places[j][0]
    if a <= k <= mov and j!=index:
    elif mov <= k <= a and j != index:
  • \$\begingroup\$ I *believe* that p[j][0] can be reduced by setting J=p[j]; at the beginning, then replacing instances of p[j][0] with P[0] \$\endgroup\$
    – Cyoce
    Dec 17, 2015 at 5:10
  • \$\begingroup\$ @Cyoce I think the trouble is I need to edit p directly, and not a variable that had p[j] assigned to it. Also, if you look at my revision history, I did have a variable k = p[j][0] for a<=k<=m comparisons, but it turned out that dropping k was better because I saved more bytes on indents from the extra line to set k than I saved by using k. \$\endgroup\$
    – Sherlock9
    Dec 17, 2015 at 5:58

J, 92 84 bytes


Attempt This Online!

-8 thanks to rdm!

  • 1
    \$\begingroup\$ (26&|+52&>) would give the same result as (52&~:*1+26&|) here \$\endgroup\$
    – rdm
    Nov 15, 2022 at 16:59
  • \$\begingroup\$ Well observed, thanks @rdm. \$\endgroup\$
    – Jonah
    Nov 15, 2022 at 17:07
  • 1
    \$\begingroup\$ Another thing that would help: remove the &; from {~ on the left and use &;/ instead of &.>/ \$\endgroup\$
    – rdm
    Nov 15, 2022 at 17:31
  • \$\begingroup\$ Thanks, I'll take a look tonight. \$\endgroup\$
    – Jonah
    Nov 15, 2022 at 17:34
  • 1
    \$\begingroup\$ While I'm at it... you can replace (]+2%~*@-~) with (]+]-*@-) \$\endgroup\$
    – rdm
    Nov 15, 2022 at 17:46

K (ngn/k), 46 45 bytes

-1 byte from @Traws' improvement


Try it online!

A bit complicated to unpack. Takes input as x.

  • &=#x generate two copies of 0..count[input] (e.g., (0 1 2 3 4;0 1 2 3 4))

  • {...}/[;...]. set up a seeded-reduce, fixing the second (y) arg, and passing the pair of ranges as the first (x) and third (z) args. x represents the to-be-shuffled indices of the input, y the number of positions to shift each character in the input, and z the initial position of each character

    • a*27>a:96!_x determine the number of positions to shift each character in the input; non-letters are shifted 0 places, leaving them in the same position
    • {?[x^z;(#x)!y+x?z;z]}/ set up a ?[x;indices;values] splice. each iteration is run on the original input (x), a single number of positions to move (y), and a single initial position (z)
      • x^z remove the current item being shifted
      • (#x)!y+x?z determine where it should be after being moved (offset by where it is now (x?z), and with wrap-around (#x)!)
      • z re-insert the value/index at the correct position
  • {x{...}...} index back into the original input, and (implicitly) return

  • 2
    \$\begingroup\$ cool answer. you can save one byte with 0^(!27)? -> a*27>a: \$\endgroup\$
    – Traws
    Nov 16, 2022 at 20:41

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.