# Letters, Get Moving!

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.

Example:

Dog

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.

hi*bye

• 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
• Do we have to do a standalone program or a function is enough? Also, do we have to print the string? Dec 14, 2015 at 8:51
• What characters can appear in the input? Printable ASCII? Linefeeds? Any ASCII? Any Unicode? Dec 14, 2015 at 9:44
• Also a test case with repeated letters would be good. Dec 14, 2015 at 10:00
• @Martin Any ASCII. Dec 14, 2015 at 15:31
• @Katenkyo function is allowed. If you are using a function, then output is the return value. Dec 14, 2015 at 15:33

## CJam, 4442 40 bytes

qN+ee_{Xa/~\+XW=eu__el=!\'@-*m<Xa+}fXWf=


Output contains a trailing linefeed.

Test it here.

### Explanation

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.
}fX
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

abcdefghijklmnopqrstuvwxyz
aqbrcdsetfguhivjwklxmnyozp

zyxwvutsrqponmlkjihgfedcba
abcdefghijklmnopqrstuvwxyz


I like that last one. :)

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

# Ruby 125 130 132 139 bytes

->q{a=q.chars.map{|c|[c,c=~/[a-z]/i&&c.ord%32]}
while i=a.index{|c,s|s}
c,s=a.delete_at i
a.insert (i+s)%q.size,[c]
end
a*''}


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.)

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

# Python 3, 278275273270260258249248243 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():
a=p[i][0];p[i][0]=m=(a+ord(s[i])%32)%l;z=1
if a>m:a,m=m,a;z=-z
for j in r:p[j][0]-=z*(j!=i)*(a<=p[j][0]<=m)
return''.join(dict(p).values())


Ungolfed:

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:
places[j][0]-=1
elif mov <= k <= a and j != index:
places[j][0]+=1
return''.join(dict(places).values())

• 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] Dec 17, 2015 at 5:10
• @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. Dec 17, 2015 at 5:58

# J, 92 84 bytes

{~(g=.i.@#@[)([/:g(]+]-*@-)#@[|g+(={.)*1{])~&;/@([|.@;;/@,.)[:(26&|+52&>)Alpha_j_&i.


Attempt This Online!

-8 thanks to rdm!

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

# K (ngn/k), 46 45 bytes

-1 byte from @Traws' improvement

{x{?[x^z;(#x)!y+x?z;z]}/[;a*27>a:96!_x].&=#x}


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

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