# Shifting Caesars Shifts

### Description

A Caesar Shift is a very simple monoalphabetic cipher where each letter gets replaced by the one after it in the alphabet. Example:

Hello world! -> IFMMP XPSME!

(IBSLR, EGUFV! is the output for the actual challenge, this was an example of shifting by 1.)

As you can see, spacing and punctuation remain unattuned. However, to prevent guessing the message, all letters are capitalized. By shifting the letters back, the message was deciphered, convenient, but also really easy to decipher by other persons who are supposed not to know what the message means.

So, we'll be helping Caesar a bit by using an advanced form of his cipher: the Self-shifting Caesar Shift!

### Challenge

Your task is to write a program or function, that, given a string to encipher, outputs the encrypted string corresponding to the input. The advanced Caesar Shift works like this:

1. Compute letter differences of all adjacent letters:
1.1. Letter difference is computed like this:

Position of 2nd letter in the alphabet
-Position of 1st letter in the alphabet
=======================================
Letter difference

1.2. Example input: Hello
H - e|e -  l|l  -  l|l  -  o
7 - 5|5 - 12|12 - 12|12 - 15 Letter differences: 3; -7; 0; -3
=3|   =-7|     =0|    =-3

2. Assign the letters continously a letter difference from the list,
starting at the second letter and inverting the differences:
2.1. 2nd letter: first difference, 3rd letter: second difference, etc.

2.2. The first letter is assigned a 1.

2.3. Example input: Hello with differences 3; -7; 0; -3

Letter || Value
=======||======
H   ||   1
E   ||  -3
L   ||   7
L   ||   0
O   ||   3

3. Shift the letters by the value x they have been assigned:
3.1. In case of a positive x, the letter is shifted x letters to the right.
3.2. In case of a negative x, the letter is shifted |x| letters to the left.
3.3. In case of x = 0, the letter is not shifted.

3.4. If the shift would surpass the limits of the alphabet, it gets wrapped around
Example: Y + Shift of 2 --> A

3.5. Example input: See the table under 2.3.

||       || Shifted
Letter || Value || Letter
=======||=======||=========
H   ||   1   ||    I
E   ||  -3   ||    B     Program output:
L   ||   7   ||    S     IBSLR
L   ||   0   ||    L
O   ||   3   ||    R

Spaces and other special symbols, such as punctuation are skipped in this process. It is guaranteed that your program will be given a string containing only printable ASCII characters. The output of your function/program must only be in upper case.

This is , so standard loopholes apply, and may the shortest answer in bytes win!

• Isn't E -3? Jul 18, 2017 at 16:25
• What if the letter difference brings the letter out of the alphabet? Like ZEN, for example. Z shifted by 1 is... A? (as a side note, the 05AB1E answer turns Z into A) Jul 18, 2017 at 17:00
• Test cases please. Also, which characters are skipped exactly? And what does it mean for them to be skipped? Are they removed altogether, or must they remain in the output? Jul 18, 2017 at 17:08
• @Giuseppe see the upvoted answers for test cases, they've been validated by OP as correct, I'd assume, or they'd have downvotes. Jul 18, 2017 at 19:15
• Did you mean for words like RELIEF and RELIES to both encipher to the same result SRSFAG? Jul 18, 2017 at 19:50

# 05AB1E, 2827 24 bytes

láÇ¥RXIlvyaiAyk+Aèëy}u?

Try it online!

Explanation

l                          # convert input to lower case
á                         # keep only letters
Ç¥                       # compute deltas of character codes
R                     # reverse and push separated to stack
X                    # push 1
Ilv                 # for each char y in lower case input
yai              # if y is a letter
Ayk           # get the index of y in the alphabet
+          # add the next delta
Aè        # index into the alphabet with this
ëy             # else push y
}            # end if
u?             # print as upper case
• We both get IBSLR, EGUFV! for Hello, World!, is that correct? Did OP just mess up that example? Jul 18, 2017 at 17:16
• @MagicOctopusUrn: His example in the beginning is just showing what a shift is. It just shifts by 1 letter so it's pretty misleading. Jul 18, 2017 at 17:18

# Python 3, 100 bytes

b=0
for c in map(ord,input().upper()):
if 64<c<91:b,c=c,(c+c-(b or~-c)-65)%26+65
print(end=chr(c))

Try it online!

b keeps track of the last letter’s ASCII code, or is initially zero; the formula c+c-(b or~-x) means a letter with ASCII code c gets shifted by c-b if b is non-zero, and c-(c-1) == +1 if b is zero (for the very first letter).

b will never become zero again, as the string is guaranteed to consist of printable ASCII characters.

Finally, 64<c<91 checks if c is an uppercase ASCII letter, and (…-65)%26+65 wraps everything back into the A-Z range.

ovs saved a byte. Thanks!

• 100 bytes
– ovs
Jul 18, 2017 at 17:43

# 05AB1E, 3230 29 bytes

lDáÇ¥1¸ìUvyaiAX¾èAyk+sè¼ëy}Ju

Try it online!

# ES6 ( Javascript ) , 138 bytes :

s=>((s,a,f)=>((r=i=>s[i]&&(a[i]=String.fromCharCode((2*s[f](i)-(s[f](i-1)||71)-38)%26+64),r(i+1)))(0),a))(s.toUpperCase(),[],"charCodeAt")

http://jsbin.com/manurenasa/edit?console

• doesn´t skip non-letters, it seems? May 1, 2018 at 17:18

# MATL, 27 bytes

tXkt1Y2mXH)tlwdh+64-lY2w)H(

Try it online!

I think this is the shortest I can get, but there are lots of different varieties since there is a lot of re-use of 'variables' (there are 3 t (duplication), and 2 w (swap) operations, clipboard H is used, and even then there is still a duplicate 1Y2...). Sadly, I couldn't save bytes with the automatic M clipboard.

Over half of the program is dedicated to making it uppercase and ignoring non-alphabetic characters - just the cipher is no more than 13 bytes (Try it online!)

## Perl, 9089

Though non-codegolf languages are rarely competitive, we can go below 100 ;)

@a=split//,<>;say uc(++$a[0]).join'',map{uc chr(2*ord($a[$_+1])-ord($a[$_])+!$_)}0..$#a-1 I've decided to ungolf this: @a = split//,<>; Takes input from STDIN, stores character list (with newline!) in @a. say uc(++$a[0]) output uppercase first letter shifted by 1. Turns out you can increment a letter in perl if you use a prefix ++. This is a mutator ofc.

2*ord($a[$_+1])-ord($a[$_])+!$_ We are asked to take character at x, and add the difference + (x-(x-1)). Well that's 2x - (x-1). However: I changed the first letter! So I've got to correct that error, hence +!$_, which will correct for having subtracted one too many at position 0 (only case !$_ is not undef ). We then uc chr to get an uppercase letter from the calculated ASCII value. map{ ... }$#a-2 - $#a is the position to access the last array element. Since I'm adding one I want$#a-1, but because the newline from input needs ignoring, this is $#a-2. This is concatenated with the first letter, and we are done :) • This seems to have some problems dealing with offsets that wrap around the alphabet and with non-alphabetic characters. Try it online! May 1, 2018 at 16:01 # Perl 5-F, 7377 74 bytes /\w/&&($_=chr 65+(2*($n=ord uc)-65-($!||-1+ord uc))%26)&($!=$n)for@F;say@F

Try it online!

• This doesn´t totally skip non-letters; it just doesn´t convert them. I think Hello, World! should result in IBSLR, EGUFV!, not IBSLR, XGUFV!. May 1, 2018 at 17:08
• You're right. Fixed it with 4 more bytes to preserve the previous letter. May 1, 2018 at 17:18

# PHP, 106 98 bytes

pretty nasty that one ... if just base_convert wasn´t that long (or ctype_alpha) ...
but I got it under 100. satisfied.

for(;$a=ord($c=$argn[$i++]);print ctype_alpha($c)?chr(65+($p?(25-$p+2*$p=$a)%26:$p=$a)):$c)\$a&=31;

Run as pipe with -nR or try it online.

# JavaScript (Node.js), 868387 81 bytes

s=>s.replace(/[a-z]/gi,(x,i)=>Buffer(x).map(x=>((i?x%32-l:1)+26+(l=x%32))%26+64))

Try it online!

• @Nit fixed it :) May 2, 2018 at 3:25