22
\$\begingroup\$

The Caesar Cypher is a very simple substitution cypher where each letter is shifted by a fixed offset (looping around Z to A). Similarly, we can also a Caesar cypher for the set of printable ASCII characters. These are the 95 characters from code points 0x20 to 0x7E. For a given offset d, we map the code point C to

(C - 32 + d) % 95 + 32

which shifts all characters by a d and loops around from ~ to space. Characters outside this range (control characters like newlines, tabs, and characters outside the ASCII range) are unaffected.

You're to write two programs or functions (potentially in different languages), which take an offset d and a string. The first program should return or print the Caesar cypher of the input. The second program should return or print the inverse Caesar cypher (i.e. using offset -d). You may take input via STDIN, command-line argument or function argument.

To make things more interesting, the second program must be a Caesar cypher of the first program. That is, if you pass the source code of the first program to itself, for some non-zero offset d, the output has to be the second program.

Both programs, as well as the input strings, must contain only printable ASCII characters, newlines and tabs. Neither program may contain any comments or read its own source code, file name or process ID directly or indirectly.

This is code golf, so the shortest answer (in bytes) wins. Since both programs must have the same size, you only need to count it once.

\$\endgroup\$
12
\$\begingroup\$

Cjam, 40 38 37 bytes

Forward Cypher:

 q~'~),32>_@m<er "o|%|'*10<]>k<cpZ"_-

Inverse Cypher:

"s!)!+.54@aBo>gt"$q~'~),32>_@m>er\$a/

and the second program is the cypher of first one with difference of 2


How it works

I came up with this answer on pure luck while testing things out.

First, the Cypher parts:

q~'~),32>_@m<er
q~                 "Take the input and evaluate it";
  `~)              "Get the next character after the printable ASCII range";
     ,32>          "Get all printable ASCII characters":
         _@        "Copy the printable ASCII string and bring the cypher difference"
                   "on top of stack";
           m<      "Forward rotate the copy of printable ASCII string by difference";
                   "In case of inverse Cypher, this is m> to reverse rotate the string";
             er    "Transliterate to complete the forward/inverse Cypher";

Now comes the explanation of the tricky part.

Key transformations are

<space> -> "     // Empty space to string conversion
Z -> \           // Character Z in an useless string to swap operation
_ -> a           // Copy operation to wrapping in an array
- -> /           // Set subtraction to string splitting

So the first program is

 q~'~),32>_@m<er "o|%|'*10<]>k<cpZ"_-
 q~'~),32>_@m<er                          "no-op space, Forward cypher, no-op space";
                 "o|%|'*10<]>k<cpZ"       "Useless String (Actually not)";
                                   _      "Copy it and ..."
                                    -     "remove all alphabets of copy from original";

And the second program is

"s!)!+.54@aBo>gt"$q~'~),32>_@m>er\$a/
"s!)!+.54@aBo>gt"                       "Cypher of first part of first program"
                                        "with difference of 2";
                 $q~'~),32>_@m>er\$a/   "Cypher of the useless string of first program";
                                        "with difference 2";
                 $                      "Sort the first program's main part's cypher";
                  q~'~),32>_@m>er       "Program to reverse cypher";
                                 \$     "Swap the cypher to the top of stack and sort it";
                                   a    "Wrap it in array";
                                    /   "Split the output string on an array, which";
                                        "always returns the output in an array as there";
                                        "are no occurrences of an array in a string";

Input is like "<escaped string to be cyphered>" <difference>

For example:

"abcd" 4

and output of the first program is

efgh

and of the second program is

]^_`

Try it online here

\$\endgroup\$
  • \$\begingroup\$ aren't that 40 bytes? also it gives an error in the online interpreter (something on Arraylists not being implemented) \$\endgroup\$ – Def Dec 17 '14 at 15:00
  • \$\begingroup\$ @Deformyer corrected the byte count. What are you giving the input as ? \$\endgroup\$ – Optimizer Dec 17 '14 at 15:08
  • \$\begingroup\$ yeah my bad, i used the arguments in the wrong order. \$\endgroup\$ – Def Dec 17 '14 at 15:15
  • \$\begingroup\$ '" q~'~),32>_@m<er "9}o|%|'*10<]>k<cp}]"_-" 2' doesn't work (java.lang.RuntimeException: Unexpected }) \$\endgroup\$ – Def Dec 17 '14 at 15:21
  • 1
    \$\begingroup\$ @Deformyer You have to escape the quotes in that string \$\endgroup\$ – Optimizer Dec 17 '14 at 15:24
7
\$\begingroup\$

Python 2, 147

Clearly I didn't think too hard about this one, as it would be futile in Python. There are simply two seperate programs, with the unused one encased in a string.

The offset between the two programs is 39.

Forward

Defines the function Z accepting a Unicode string and an offset.

Z=lambda s,d:s.translate({i+32:(i+d)%95+32for i in range(95)})or u''and Z
"uE:F;=:XLd=rLfMK:GLE:M>`TBckjr`Be=a]qmckj?HKXBXBGXK:G@>`qmaVaHKXN__:G=X"

Inverse

Defines the function I accepting a Unicode string and an offset.

"d4)5*,)G;S,a;U<:)6;4)<-OC1RZYaO1R,PL`\RZY.7:G1G16G:)6/-O`\PEP7:G=NN)6,G"
I=lambda s,d:s.translate({i+32:(i-d)%95+32for i in range(95)})or u''and I
\$\endgroup\$
5
\$\begingroup\$

Python 3 - 248 bytes

My goal was to do this as a Python one-liner. Goal success, but now I can't be bothered golfing.

Encrypt:

r=q="".__doc__[2];eval("p"+q+"int(''.join([c,ch"+q+"((o"+q+"d(c)-32+d)%95+32)][31<o"+q+"d(c)<127]fo"+q+" d in[int(input())]fo"+q+" c in input()))")or'\^UZ`smmyV[UZsGOwOT^ss[^PsOtx~}xPtp%!v~}tIG~|([^PsOt(|}$IR[^kPkUZGUZ`sUZ\a`sttIR[^kOkUZkUZ\a`sttt'

Decrypt:

'Q&Q66Bssx$wssoFqOy+u!<6%6?&?6}#)<;;B~$}#<ow@w|6?&?6<<$6?&?6x<w=AGF?x=9MI?GF=qoGEP$6?&?6x<w=PEFKqz$6?&?64x4}#o}#)<}#%*)<==qz$6?&?64w4}#4}#%*)<===6=$';print("".join([c,chr((ord(c)-32-d)%95+32)][31<ord(c)<127]for d in[int(input())]for c in input()));

Edit: Fixed to not affect chars outside the printable ASCII range

Offset from encrypt to decrypt is 20. Use by inputting the offset first, then the string, e.g.

5
hello

Explanation

The following transformations are the key:

r -> '
' -> ;

The first allows the use of or, while the second ignores a string by semicolons.

Note that "".__doc__[2] returns the string r (taken from str). This is necessary to prevent the single quoted string in the decryption program from having stray quotes in the middle.

\$\endgroup\$
5
\$\begingroup\$

Ruby, 131 125 bytes

Here is my own submission (which I had written earlier as a proof of concept, but I managed to violate my own rules somehow). I'm not reusing any code between the two submissions (I want you guys to beat this, after all), but instead it consists of two lines, one of which is turned into a string with gibberish.

Forward cypher:

Y=->d,s{s.chars{|c|x=c.ord;$><<(x<32?x:(x-32+d)%95+32).chr}};Y
"tdu<cKSKe;@9JKST;TPt;eGJ<r[uss_PsjivPq_Pdjid<`\plbji`e;@JUUr"

Inverse cypher:

"eUf-T<D<V,1*;<DE,EAe,V8;-cLfddPAd[ZgAbPAU[ZS-QMa]S[ZQV,1;FFc"
J=->d,s{s.chars{|c|x=c.ord;$><<(x<32?x:(x-32-d)%95+32).chr}};J

Both snippets define a function (called Y in the first one, and J in the second one), which takes an integer and a string and prints the transformed string to STDOUT. The offset between the two pieces of code is 40.

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

oOo CODE, 750 744 bytes, all code used in both programs

Too long but it's probably the right tool doing that...

Encrypt:

CcCcccccccccCcYcccCCCccCcCcCccccccCcCcccccCcCcccCcCccCccCcCCccccCcCccccCCcCccccCCccCccCcCCcccCCCcCccccCcCCcCCcCCcCcCcCccccCCccCccCccCccCccCccCccCccccccCCCcCccCccCCcCcCcccCCcCcccCcCCcCCcCcCCccCCcCCcCCcCCcCCcCCcCCcCCcCCcCCcCcccccccCccccCccccCCccccCCcCccCCcccCccccccccccCcCccCccCccCccCcCCccCCcccCcCcCccCCcccCCCcCcccccccccccccCCccCccCcCcCcccCCccccccccccCcCccccccCcCccccCCcCccCccCCcCccccccccccCCccCcCcCcccccCcCccCcCCCcCccCccCCcCccCccCccCcCcccccCcCcccCCCcCcCccccCcCccCCcCCcCCcCcCCcccCcCCcCCcCCcCCcCCcCCcCCcCCcCCcCcCcccCccCCcccccCcCcccCcccccCcccCcccCccCccCCcCcccccccccccccCCCcccCcCcCcccCcccCCCcCccCccCccCcCCccCccCcCCCcCccccCcCccccccccCcCccCccCcCCccccccCccccccccCcccCCccCccCccCCcCCcCCcCCcCcCcCcccccCcCCcCCcCCcCCcCCcCCcCCcCccCcCCcccCCccCcCcccCCcccCCCcCC

Decrypt:

SsSsssssssssSsisssSSSssSsSsSssssssSsSsssssSsSsssSsSssSssSsSSssssSsSssssSSsSssssSSssSssSsSSsssSSSsSssssSsSSsSSsSSsSsSsSssssSSssSssSssSssSssSssSssSssssssSSSsSssSssSSsSsSsssSSsSsssSsSSsSSsSsSSssSSsSSsSSsSSsSSsSSsSSsSSsSSsSSsSsssssssSssssSssssSSssssSSsSssSSsssSssssssssssSsSssSssSssSssSsSSssSSsssSsSsSssSSsssSSSsSsssssssssssssSSssSssSsSsSsssSSssssssssssSsSssssssSsSssssSSsSssSssSSsSssssssssssSSssSsSsSsssssSsSssSsSSSsSssSssSSsSssSssSssSsSsssssSsSsssSSSsSsSssssSsSssSSsSSsSSsSsSSsssSsSSsSSsSSsSSsSSsSSsSSsSSsSSsSsSsssSssSSsssssSsSsssSsssssSsssSsssSssSssSSsSsssssssssssssSSSsssSsSsSsssSsssSSSsSssSssSssSsSSssSssSsSSSsSssssSsSssssssssSsSssSssSsSSssssssSssssssssSsssSSssSssSssSSsSSsSSsSSsSsSsSsssssSsSSsSSsSSsSSsSSsSSsSSsSssSsSSsssSSssSsSsssSSsssSSSsSS

Brainfuck translations:

+>>>+>,<[->[->+>+<<]>[-<+>]<<]>,[>++++[-<-------->]+<<+[<+>+++]<++++++++++>>[>-<-<+<-[>>>+<<<<]<-[+<-]+>>>>]<<[-]>>>[->[-<+<<+>>>]<[->+<]+<<+<<<[>[-]+[>+<+++]>++++++++++[<<->+>->-[<<<+>>>>]-[+>-]+<<<]<<]+>[->>+<<]>>->>-]<<<++++[->++++++++<]>.[-]>,]
+>>>->,<[->[->+>+<<]>[-<+>]<<]>,[>++++[-<-------->]+<<+[<+>+++]<++++++++++>>[>-<-<+<-[>>>+<<<<]<-[+<-]+>>>>]<<[-]>>>[->[-<+<<+>>>]<[->+<]+<<+<<<[>[-]+[>+<+++]>++++++++++[<<->+>->-[<<<+>>>>]-[+>-]+<<<]<<]+>[->>+<<]>>->>-]<<<++++[->++++++++<]>.[-]>,]

oOo CODE is a Brainfuck variant where only the case of letters matters.

It take the first byte and use its character code as d (so a newline means d=10). The rest of input is the string. EOF is 0.

\$\endgroup\$
4
+100
\$\begingroup\$

GolfScript, 95 64 bytes, all code used in both programs

Encrypt:

0 0z{ 1)'[}??)9t:z21,--/; [84;%zt*84*84$|)21*|$Z!!\~'---|}`{)}%~

Decrypt:

1!1{|!2*(\~@@*:u;{32-..0<!\95<&{u+95+95%}*32+}%[""] (...}~a|*~& 

Input format:

1 "0 0z{ 1)'[}??)9t:z21,--/; [84;%zt*84*84$|)21*|$Z!!\~'---|}`{)}%~"

Explanation

Decrypt:

1!1                            # Push 0 1.
{                              # Define a block and evaluate it.
    |                          # Or.
    !2*(                       # Get 1 for encryption, or -1 for decryption.
    \~                         # Evaluate the input string.
    @@*:u;                     # u = d for encryption, or -d for decryption.
    {                          # For each character:
        32-                    # Subtract 32.
        ..0<!\95<&             # Test if it is in the printable range.
        {u+95+95%}*            # If so, add u (mod 95).
        32+                    # Add 32 back.
    }%
    [""] (...                  # Push an empty array and 4 empty strings.
}~
a                              # No-op.
|*~                            # Evaluate ""*(""|"") which does nothing.
&                              # Calculate []&"" which is empty.

Encrypt:

0 0                            # Push 0 0.
z                              # No-op.
{                              # Define a block and get its string representation.
    ...                        # See decryption code.
    |                          # This will be decoded into a }. The string will be truncated here when evaluated.
}`                             # Only the closing } will be truncated, but it is still used as the end of the block.
{)}%                           # Increment each character. Note that the braces before and after the block will also be incremented.
~                              # Evaluate the string.
\$\endgroup\$
3
\$\begingroup\$

Javascript (ES7 Draft) - 167 165 bytes

Borrowing from @feersum 's use of strings and @MartinButtner 's use of semicolon ;)

Encrypt:

J=(s,d)=>s.replace(/[ -~]/g,x=>String.fromCharCode((x.charCodeAt()-32+d)%95+32));J
"eP<T-Qef<V;.95*,.PW$HUG&W0TAef{=;270V/;86k1*;k8-.PPAV,1*;k8-.i=PQS^[U-QMa]S[ZQQc"

Decrypt:

"t_Kc<`tuKeJ=HD9;=_f3WdV5f?cPtu+LJAF?e>JGEz@9JzG<=__Pe;@9JzG<=xL_`djib<`\plbji``r"
Y=(s,d)=>s.replace(/[ -~]/g,x=>String.fromCharCode((x.charCodeAt()+63-d)%95+32));Y

Offset to use: 55

\$\endgroup\$
  • 1
    \$\begingroup\$ Fails for empty strings. That's why I had to put or <empty string> and <function> rather than only or <function>. \$\endgroup\$ – feersum Dec 18 '14 at 0:36
  • \$\begingroup\$ @feersum it's fixed now... and 2 bytes shorter :) \$\endgroup\$ – nderscore Dec 18 '14 at 15:57
  • \$\begingroup\$ Hm, this looks familiar. ;) \$\endgroup\$ – Martin Ender Dec 18 '14 at 15:58
  • \$\begingroup\$ @MartinBüttner I don't know what you mean... ;) \$\endgroup\$ – nderscore Dec 18 '14 at 16:01
2
\$\begingroup\$

><> (Fish), 467 bytes

Encrypt:

ffii{{~~__:0a('0'*!.0a('0'*22(!'(~$~_:}-}$-a*}+{{if~~:i:0({}?;__:{}84{}*__({}?\__:{} _{}70{}g_{})_{}?\4__{}8*-_{}+{}80{}g_%4_{}8*{}+\\sl||||||||||||||||||||||||||||9||||||||||||||9||||||||||||||||||||||||||||||||||||||||||||||||||||9
                                                                              >                      >                              >!;7f7-_{}!%_{}!<872-d_{}!&_{}!<[755(7(%~~_{}!<[55(7(_{}!*!*23a(_{}!'_{}!"55(7((~~_{}~~~o__'4'0.{{{o,

Decrypt:

iill~~""bb=3d+*3*-$13d+*3*-55+$*+"'"b=!0!'0d-!.~~li""=l=3+~!B>bb=~!;7~!-bb+~!B_bb=~!#b~!:3~!jb~!,b~!B_7bb~!;-0b~!.~!;3~!jb(7b~!;-~!.__vo                            <              <                                                    <
##############################################################################A######################A##############################A$>:i:0b~!$(b~!$?;:50gb~!$)b~!$?^:88+:+(""b~!$?^88+:+b~!$-$-56d+b~!$*b~!$%88+:++""b~!"""rbb*7*31~~~r/

The two programs are offset by 3, and they take input of the form:

<2-digit offset> <text>

The offset must be 2 digits, so an offset of 5 needs to be entered as 05.

This is a long submission, but nearly all non-filler chars are used by both programs. There's a lot of whitespace that can definitely be golfed out, but I thought the program would be more interesting this way.

This image highlights the chars used by both programs.

Explanation

The main construct that makes this possible is _{} -> b~!, which allows arbitrary skipping of chars in the decryption program. How?

Encrypt:
  _ : Mirror, but is a no-op if the program flow is horizontal
  { : Shift stack left
  } : Shift stack right

Decrypt:
  b : Push 11 to stack
  ~ : Pop top of stack
  ! : Skip the next instruction

All in all, the encryption program does nothing, but the decryption program skips the next instruction. This can then be extended to _{}! -> b~!$, which allows arbitrary skipping of chars in the encryption program instead.

Aside from this, most of the rest of the program is pushing numbers, performing operations on those numbers then finding ways to pop them. For example, one useful construct is ~~ -> "", which pops two values for the encryption program, but pushes nothing in the decryption program.


><>, 149 bytes

Here's the less interesting version, which uses the fact that instructions not passed through are effectively comments in 2D languages.

Encrypt:

i68*:@-a*i@@-+i~v
4:v?)g31:;?(0:i:/8
(?v48*-+03g%48*+\*
_~\of0.   .1+1fo/
j*+:zq<6B99A6=qz6g
53Ji?C58/8;?r0?C5:
C?EiJ4r?<EFJ3;EtEg
:tAC5EK8l5tKK86t*i

Decrypt:

^+-~/5"V~^55" ^sk
)/k4}\(&/04|%/^/$-
|4k)-~" %(\y)-~ Q~
TsQd[%#ttt#& &[d$
_~ /of1+7..6+2fo+\
*(?^48*-$-04g%48*/
84:^?)g41:;?(0:i:\
/i68*:@-a*i@@-+i~^

The two programs are offset by 84, and take input the same way as above. The first instruction decides which half of the program to execute, with i (input) maintaining program flow rightward in the encryption program, and ^ redirecting program flow upward (looping around and coming back from the bottom) in the decryption program.

Explanation

For the relevant half of the encryption program (decryption program is similar):

i                       read first input digit as char
68*:@-a*                subtract 48 (ASCII "0") and multiply by 10, keeping another 48 on the stack
i                       read second input digit as char
@@-+                    subtract 48 and add to 10*(first digit), giving the offset
i~                      read in space and discard it

--- LOOP ---
:                       copy the offset
i:                      read input char
:0)?;                   check if less than 0 (i.e. EOF) and terminate if so
:13g)?v                 check if greater than ~ in cell (1,3) and drop down if so
48*(?v                  check if less than 32 and drop down if so
48*-+03g%48*+           calculate Caesar shift of the char, fetching 95 from (0,3)

of1+1.                  repeat loop
of0.                    repeat loop

Coding tool

This isn't related to the rest of the post above, but I thought I'd post this because I need to use it :P

for(var i=0;i<95;++i){var option=document.createElement("option");option.text=i;document.getElementById("offset").add(option)};function update(m){if(m==1)var code=document.getElementById("in").value;else var code=document.getElementById("out").value;var offset=parseInt(document.getElementById("offset").value);var output="";for(var i=0;i<code.length;i++){var n=code[i].charCodeAt(0);if(n<32||n>127)output+=code[i];else{var c=(n-32+offset*m)%95;output+=String.fromCharCode(c<0?c+95+32:c+32)}}if(m==1)document.getElementById("out").value=output;else document.getElementById("in").value=output};
<html><body><textarea id="in" onkeyup="update(1)" rows=5 style="width:100%"></textarea><textarea id="out" rows=5 style="width:100%" onkeyup="update(-1)"></textarea><select id="offset" onchange="update(1)"></select></body></html>

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

Perl - 131

It takes input from command line args.

We;{for(split//,$ARGV[1]){print chr(((ord$_)-32+$ARGV[0])%95+32)}};q!LUXmYVROZttqi'8-<AvCnaVXOTZeINXmmmUXJiEnrxwri'8-<AuCnj~zpxwnc!

Shifting it by 26 gives the other one:

q U6!*-B.+'$/IIF>[lapuKwC6+-$)/:}#-BBB*-~>yCGMLE>[lapuJwC?SOEMLC88U,;for(split//,$ARGV[1]){print chr(((ord$_)-32-$ARGV[0])%95+32)};
\$\endgroup\$
  • \$\begingroup\$ @Martin Büttner Woah, an upvote! It actually does work? \$\endgroup\$ – KSFT Dec 31 '14 at 0:26
  • \$\begingroup\$ it does as far as I can tell ;) \$\endgroup\$ – Martin Ender Dec 31 '14 at 12:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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