# Programming Challenge: Make a Caesar cipher!

The point of this thread is to post your code for solving the task. Other will comment with feedback and new ideas. Post what language (and version, if relevant) your code is written in.
Have fun!

Your task is to make a caesar cipher that takes a word and an integer as arguments.
An article explaining what the cipher does.

## Input description

A word followed by a space and an integer.

## Output description

The ciphered word.

## Sample onput

``````A 1
Caesar 5
Tildes 25
``````

## Sample output

``````B
Hfjxfw
Shkcdr
``````

# Bonus 1

Make the cipher work backwards.

## Sample input

``````B 1
Hfjxfw 5
Shkcdr 25
``````

## Sample output

``````A
Caesar
Tildes
``````

# Bonus 2

Make the cipher handle special characters.

## Sample onput

``````A_ 1
Cae?sar 5
Til!des 25
``````

## Sample output

``````B
Hfj?xfw
Shk!cdr
``````

1. 
kgz
(edited )
I like python. def caesar(s, i): return ''.join([[lambda _: list(filter( lambda _: _,[(__(), _()) for __, _ in { lambda: _ >= 97 and _ <= 122: lambda: ___(_, 96), lambda: _ >= 65 and _ <= 90:...

I like python.

``````def caesar(s, i):
return ''.join([[lambda _: list(filter(
lambda _: _,[(__(), _()) for __, _ in {
lambda: _ >= 97 and _ <= 122: lambda: ___(_, 96),
lambda: _ >= 65 and _ <= 90: lambda: ___(_, 64),
lambda: 1: lambda: chr(_)}.items()])) for ___ in [
lambda _, __: chr((_ - __ + i) % 26 + __)]
](ord(___)) for ___ in s])

print(caesar('A', 1))
print(caesar('Caesar', 5))
print(caesar('Tildes', 25))
``````
1. 
skosulor
Could you explain how your code works? I like python as well but am lacking a bit in experience of it and this makes no sense to me.

Could you explain how your code works? I like python as well but am lacking a bit in experience of it and this makes no sense to me.

1 vote
1. jgb
This program is intentionally very obtuse, but what it's doing is converting each character into an ASCII code, 'normalising' those codes so that they lie in the range 1...26 (regardless of...

This program is intentionally very obtuse, but what it's doing is converting each character into an ASCII code, 'normalising' those codes so that they lie in the range 1...26 (regardless of whether they are upper or lower case), shifting the codes by the required amount, then converting them back into ASCII codes in the required region of the table (for upper or lower case characters respectively). This program relies on the fact that the alphabet is contiguous in ASCII, so that ASCII(J) + 6 = ASCII(P), for example. It also relies on the fact that Caeser shift wraps around, allowing the shifted code to be coerced back into the 1...26 range with the modulo operator.

1 vote
2. Social

2. 
Elusive
(edited )
My solution in C/C++, including the bonus challenges: void caesar(char* message, int shift) { while (*message) { char base = 0; if (*message >= 'A' && *message <= 'Z') base = 'A'; if (*message >=...

My solution in C/C++, including the bonus challenges:

``````void caesar(char* message, int shift) {
while (*message) {
char base = 0;
if (*message >= 'A' && *message <= 'Z') base = 'A';
if (*message >= 'a' && *message <= 'z') base = 'a';
if (base) *message = ((*message - base + shift) % 26 + 26) % 26 + base;
++message;
}
}
``````
1. Wombat
Props. One of the cleanest solutions and in c++. That's a bamf right here

Props. One of the cleanest solutions and in c++. That's a bamf right here

1 vote
3. 
sniper24
(edited )
https://github.com/tsikorksi/historic-crypto I tried my hand hand at some simple cryptography a while ago, but here's the relevant functions : def shift_encode(message, shift): x = [] if shift >=...

https://github.com/tsikorksi/historic-crypto I tried my hand hand at some simple cryptography a while ago, but here's the relevant functions :

``````def shift_encode(message, shift):
x = []
if shift >= 26:
shift = shift % 26
for i in range(0, len(message)):
message_int = ord(message[i])
if message_int + shift > 122:
message_int = message_int + shift - 26
else:
message_int += shift
x.append(chr(message_int))
print(x)

def shift_decode(message, shift):
x = []
if shift >= 26:
shift = shift % 26
for i in range(0, len(message)):
message_int = ord(message[i])
if message_int - shift < 97:
message_int = message_int + 26
message_int -= shift
x.append(chr(message_int))
print(x)

def shift_brute(message):
x = []
for i in range(0, 26):
for j in range(0, len(message)):
temp = ord(message[j])
if temp + i > 122:
temp = temp + i - 26
else:
temp += i
x.append(chr(temp))
print(x)
x = []
``````

Its not the finest solution but fairly easy to understand, despite the lack of comments (I've gotten better about that since I wrote this) and the output is poorly formatted here, but its better on the github.

1. 
bel
As an ex-teaching assistant, I'm obligated to look for the weird stuff no one cares about. What about negative shifts? Then again, it'd probably be better to clean up negatives in a common...

As an ex-teaching assistant, I'm obligated to look for the weird stuff no one cares about. What about negative shifts? Then again, it'd probably be better to clean up negatives in a common preceding function, like when gathering input. Are negative shifts even legal in a Caesar cipher or are left and right shifts their own category?

1 vote
1. 
sniper24
Negatives work fine, because the code changes the ASCII value, rather than the actual char, so a -4 shift will work fine.

Negatives work fine, because the code changes the ASCII value, rather than the actual char, so a -4 shift will work fine.

1 vote
1. 
bel
Would a -50? I have not tested it, but I assume it would fail given your initial if shift >= 26

Would a -50? I have not tested it, but I assume it would fail given your initial `if shift >= 26`

1. 
sniper24
(edited )
Unexpectedly, it works fine. What does break it is a negative value > 255 (or less than -255, you know what I mean)

Unexpectedly, it works fine. What does break it is a negative value > 255 (or less than -255, you know what I mean)

1. bel
In case you didn't catch it on reddit the other day, Hitting this Block for 416 Years Crashes Paper Mario is now relevant.

In case you didn't catch it on reddit the other day, `Hitting this Block for 416 Years Crashes Paper Mario` is now relevant.

4. 
chewbacca
MoonScript caesar = (input, shift) -> coded = "" for index = 1, input\len! char = input\sub index,index byte = char\byte! local byteOffset if byte >= 97 and byte <= 122 byteOffset = 96 elseif byte...

# MoonScript

``````caesar = (input, shift) ->
coded = ""
for index = 1, input\len!
char = input\sub index,index
byte = char\byte!

local byteOffset
if byte >= 97 and byte <= 122
byteOffset = 96
elseif byte >= 65 and byte <= 90
byteOffset = 64
else
coded ..= char
continue

coded ..= string.char (byte - byteOffset + shift) % 26 + byteOffset
coded

-- Tests
print caesar("A", 1)		-- B
print caesar("Caesar", 5)	-- Hfjxfw
print caesar("Tildes", 25)	-- Shkcdr

print caesar("B", -1)		-- A
print caesar("Hfjxfw", -5)	-- Caesar
print caesar("Shkcdr", -25)	-- Tildes

print caesar("A_", 1)		-- B_
print caesar("Cae?sar", 5)	-- Hfj?xfw
print caesar("Til!des", 25)	-- Shk!cdr
``````
1. 
bel
MoonScript isn't the most prevalent language, yet you used it two days in a row. What got you started on it?

MoonScript isn't the most prevalent language, yet you used it two days in a row. What got you started on it?

1. 
chewbacca
MoonScript compiles to Lua, which I've had a lot of experience with. It's a cleaner syntax, allows for object-oriented programming (better than you'd get in Lua at least), and has more features....

MoonScript compiles to Lua, which I've had a lot of experience with. It's a cleaner syntax, allows for object-oriented programming (better than you'd get in Lua at least), and has more features.
If you're interested, I'd recommend looking at the reference or "Learn MoonScript in 15 Minutes".

1. 
sniper24
How mature would you say the language is? How useful do you find it for larger scripts?

How mature would you say the language is? How useful do you find it for larger scripts?

2. 
bel
I'm halfway through skimming your Learn MoonScript link, and this stuff is crazy. Dynamic typing is always pleasant to deal with, but the dependency on spacing for function calls and negation...

I'm halfway through skimming your `Learn MoonScript` link, and this stuff is crazy. Dynamic typing is always pleasant to deal with, but the dependency on spacing for function calls and negation makes me think debugging would be a nightmare. Do you use Lua professionally or for some hobby?

1. chewbacca
You don't have to use that spacing. You can always call functions normally (i.e., with parenthesis.) The spacing is just syntactic sugar for when you think it'd look nicer. The script behaves...

You don't have to use that spacing. You can always call functions normally (i.e., with parenthesis.) The spacing is just syntactic sugar for when you think it'd look nicer. The script behaves exactly the same when written as follows:

``````caesar = (input, shift) ->
coded = ""
for index = 1, input\len()
char = input\sub(index,index)
byte = char\byte()

local byteOffset
if (byte >= 97 and byte <= 122)
byteOffset = 96
elseif (byte >= 65 and byte <= 90)
byteOffset = 64
else
coded ..= char
continue

coded ..= string.char((byte - byteOffset + shift) % 26 + byteOffset)
coded
``````

I don't use it professionally, just as a hobby.

5. Kremor
Here's my solution in rust. It has a very basic argument parsers: The first argument must be the string that you want to encrypt. The second argument is the number of times you want to shift a...

Here's my solution in rust. It has a very basic argument parsers:

1. The first argument must be the string that you want to encrypt.
2. The second argument is the number of times you want to shift a letter, if the argument is not a valid number, it uses 0 instead.
3. Adding more arguments will shift backwards, it doesn't matter what the arguments are or how many.
``````    use std::env;

fn cipher (string: &str, offset: u8, backwards: bool) -> String {
let mut bytes: Vec<u8> = Vec::new();

let offset = offset % 26;

for b in string.as_bytes() {
match b {
65...90 => bytes.push(
if backwards {
(*b - 13 - offset) % 26 + 65
} else {
(*b - 13 + offset) % 26 + 65
}
),
97...122 => bytes.push(
if backwards {
(*b - 19 - offset) % 26 + 97
} else {
(*b - 19 + offset) % 26 + 97
}
),
_ => bytes.push(*b),
}
}

match String::from_utf8(bytes) {
Ok(s) => s,
Err(_) => String::from("Error!: Unable to process string"),
}
}

fn main() {
let args: Vec<_> = env::args().collect();

if args.len() < 3 {
println!("Not enought arguments.");
return;
}

let string = &args;
let offset = match args.parse::<u8>() {
Ok(n) => n,
Err(_) => 0
};
let backwards = if args.len() >= 4 {true} else {false};

println!("{}", cipher(string, offset, backwards));
}
``````
6. ABC
(edited )
def caesar(text, num): outstr = "" for i in range(len(text)): if ("A" <= text[i] and text[i] <= "Z"): outstr += chr( (((ord(text[i]) - ord("A")) + num) % 26) + ord("A") ) elif ("a" <= text[i] and...
``````def caesar(text, num):
outstr = ""
for i in range(len(text)):
if ("A" <= text[i] and text[i] <= "Z"):
outstr += chr( (((ord(text[i]) - ord("A")) + num) % 26) + ord("A") )
elif ("a" <= text[i] and text[i] <= "z"):
outstr += chr( (((ord(text[i]) - ord("a")) + num) % 26) + ord("a") )
else:
outstr += text[i]
return outstr
``````
``````>>> caesar("test", 3)
'whvw'
>>> caesar("whvw", -3)
'test'
>>> caesar("te!st", 3)
'wh!vw'
>>> caesar("wh!vw", -3)
'te!st'
>>>
``````
7. tyil
Perl 6 Code #! /usr/bin/env false use v6.c; #| Specify an exported sub which takes and returns the format specified in the #| challenge. sub caesar ( Str:D \$input, --> Str ) is export { # Use a...

# Perl 6

## Code

``````#! /usr/bin/env false

use v6.c;

#| Specify an exported sub which takes and returns the format specified in the
#| challenge.
sub caesar (
Str:D \$input,
--> Str
) is export {
# Use a regex to extract the cleartext and the shift value from the input
if (\$input ~~ / ^ (.*) " " (\d+) \$ /) {
return shift-string(~\$0, +\$1);
}
}

sub caesar-reverse (
Str:D \$input,
--> Str
) is export {
# Use a regex to extract the cleartext and the shift value from the input
if (\$input ~~ / ^ (.*) " " (\d+) \$ /) {
return shift-string(~\$0, -+\$1);
}
}

#| Shift all characters in a given C<Str> a number of C<\$shift> times.
sub shift-string (
Str:D \$clear,
Int:D \$shift,
--> Str
) {
\$clear.comb.map({ shift-char(\$_, \$shift) }).join;
}

#| Shift a single character a number of C<\$shift> times.
multi sub shift-char (
Str:D \$character is copy where *.chars == 1,
Int:D \$shift where * > 0,
--> Str
) {
for ^(\$shift % 26) {
\$character = shift-forward(\$character);
}

\$character;
}

multi sub shift-char (
Str:D \$character is copy where *.chars == 1,
Int:D \$shift where * < 0,
--> Str
) {
for ^(-\$shift % 26) {
\$character = shift-backward(\$character);
}

\$character;
}

#| Shift a single character one time
sub shift-forward (
Str:D \$character where *.chars == 1,
--> Str
) {
return 'a' if \$character eq 'z';
return 'A' if \$character eq 'Z';

\$character.succ;
}

sub shift-backward (
Str:D \$character where *.chars == 1,
--> Str
) {
return 'z' if \$character eq 'a';
return 'Z' if \$character eq 'A';

\$character.pred;
}
``````

## Tests

### Challenge

``````#! /usr/bin/env perl6

use v6.c;

use Local::Tildes::Challenge;
use Test;

plan 3;

is caesar("A 1"), "B";
is caesar("Caesar 5"), "Hfjxfw";
is caesar("Tildes 25"), "Shkcdr";
``````

### Bonus 1

``````#! /usr/bin/env perl6

use v6.c;

use Local::Tildes::Challenge;
use Test;

plan 3;

is caesar-reverse("B 1"), "A";
is caesar-reverse("Hfjxfw 5"), "Caesar";
is caesar-reverse("Shkcdr 25"), "Tildes";
``````

### Bonus 2

``````#! /usr/bin/env perl6

use v6.c;

use Local::Tildes::Challenge;
use Test;

plan 3;

is caesar("A_ 1"), "B_";
is caesar("Cae?sar 5"), "Hfj?xfw";
is caesar("Til!des 25"), "Shk!cdr";
``````

## Notes

I've changed one test for the second bonus part, where the original challenge posed that `A_` should become `B`, dropping the trailing `_`. This behaviour looks odd, and since there's other typos in the OP as well I assumed that one to be a type as well.

Having looked through the comments a bit, I've noticed most people don't even pass the actual challenge, as they don't use a single string as output. Instead, they already split the clear-text string and the number of shift rounds manually when handing it over to a function.

8. thykka
No JavaScript solution? OK, I'll bite... JavaScript const cc = { A: 'A'.charCodeAt(0), Z: 'Z'.charCodeAt(0), a: 'a'.charCodeAt(0), z: 'z'.charCodeAt(0) } const toCharCode = letter =>...

No JavaScript solution? OK, I'll bite...

# JavaScript

``````const cc = {
A: 'A'.charCodeAt(0),
Z: 'Z'.charCodeAt(0),
a: 'a'.charCodeAt(0),
z: 'z'.charCodeAt(0)
}
const toCharCode = letter => letter.charCodeAt(0);
const fromCharCode = charCode => String.fromCharCode(charCode);
const isLowerCaseAlpha = lcc => lcc >= cc.a && lcc <= cc.z;
const isUpperCaseAlpha = lcc => lcc >= cc.A && lcc <= cc.Z;
const modulo = (n, m) => ((n % m) + m) % m;
const caesar = (lcc, shift) =>
isUpperCaseAlpha(lcc) ? modulo((lcc - cc.A + shift), 26) + cc.A :
isLowerCaseAlpha(lcc) ? modulo((lcc - cc.a + shift), 26) + cc.a :
lcc;
const cipher = (text, shift) =>
text.split('').map(toCharCode)
.map(lcc => caesar(lcc, shift))
.map(fromCharCode).join('');
const uncipher = (text, shift) => cipher(text, -shift);
``````

# tests

``````console.assert(cipher('A', 1)       === 'B');
console.assert(cipher('Caesar', 5)  === 'Hfjxfw');
console.assert(cipher('Tildes', 25) === 'Shkcdr');

console.assert(uncipher('B', 1)       === 'A');
console.assert(uncipher('Hfjxfw', 5)  === 'Caesar');
console.assert(uncipher('Shkcdr', 25) === 'Tildes');

console.assert(cipher('A_', 1)       === 'B_');
console.assert(cipher('Cae?sar', 5)  === 'Hfj?xfw');
console.assert(cipher('Til!des', 25) === 'Shk!cdr');
``````
9. 
ruspaceni
(edited )
So i just gave this a bit of a go since I haven't done much scratch programming recently. Just fixing bugs/logic errors in my discord bot and whatnot. Sorry for the abomonation i just created. I...

So i just gave this a bit of a go since I haven't done much scratch programming recently. Just fixing bugs/logic errors in my discord bot and whatnot. Sorry for the abomonation i just created. I think it works though

https://goplay.space/#FbAEPwlpkdX

``````
import (
"fmt"
"strings"
)

func main() {
fmt.Println(ceastheday("haha yes", 14))

}

func ceastheday(s string, n int) (c string) {
dontjudgemeforthis := "abcdefghijklmnopqrstuvwxyz"
enc := ""
for x := 0; x < len(s); x++ {
//fmt.Println(strings.ToLower(string(s[x])), x,strings.Contains(dontjudgemeforthis, string(s[x])))

if strings.Contains(dontjudgemeforthis, string(s[x])) {
//curletter := string(s[x])
curindex := (strings.Index(dontjudgemeforthis, string(s[x])) + n) % 26
fmt.Println(curindex)
enc += string(dontjudgemeforthis[curindex])
} else {
enc += " "
}
}

return enc
}
``````

e: A friend just gave this a go (wayyyy more experienced than me) so here's a more golang-ish approach
https://goplay.space/#G8OxQ-5ILq8

1 vote
1. planNine
I see what you did there...

So i just gave this a bit of a go

I see what you did there...

10. 
BBBence1111
C# code. Works forwards and backwards, should handle whatever special characters you code into it. Input is changed to: word number decrypt? Decrypts on "y". char[] chars = new char[] {'a', 'b',...

C# code. Works forwards and backwards, should handle whatever special characters you code into it. Input is changed to:

``````word number decrypt?
``````

Decrypts on "y".

``````        char[] chars = new char[] {'a', 'b', 'c', 'd' };
string output = "";
int increase = 0;
for (int i = 0; i < input.Length; i++)
{
for (int j = 0; j < chars.Length; j++)
{
if (input[i] == chars[j])
{
if (input == "y")
{
increase = j - int.Parse(input);
if (increase < 0)
{
increase = increase + chars.Length;
}
}
else
{
increase = j + int.Parse(input);
if (increase >= chars.Length)
{
increase = increase - chars.Length;
}
}
output = output + chars[increase];
increase = 0;
}
}
}
Console.WriteLine(output);
``````
1 vote
1. BBBence1111
I just noticed that this breaks if you use more than twice the number of characters. To fix that, change the if statement that checks if it's in range into a while loop.

I just noticed that this breaks if you use more than twice the number of characters. To fix that, change the if statement that checks if it's in range into a while loop.

11. 
Scion
(edited )
Edit: Found a bug where if the key is too large (like 2000) then it doesn't work properly. I'm not sure why so if anyone knows I'd appreciate if you could share. Very new to C (learning it through...

Edit: Found a bug where if the key is too large (like 2000) then it doesn't work properly. I'm not sure why so if anyone knows I'd appreciate if you could share.

Very new to C (learning it through CS50 ), but I actually was on the Caesar Cypher assignment today anyway, so good timing. I'm positive there are ways to do this infinitely better, but this works as far as I can tell. And yes, I'm using the library the course staff built for class use, which conveniently includes a get_string() function...

``````#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//Caesar Cypher -- shift all letters in plaintext by key
int main(int argc, string argv[]) {
int key;
// confirm only 1 command line argument, convert argument (key) to integer
if (argc == 2){
string arg = argv;
key = atoi(arg);
} else {
printf("Error: Only enter one argument\n");
return 1;
}
// Get plaintext to encrypt, store in string variable 'plain'
string plain = get_string("Enter your text here >> ");

// Get length of plaintext input
int len = strlen(plain);

// Shift each letter by the key, preserving case
int i;
for (i = 0; i < len; i++) {
if (islower(plain[i])) {
plain[i] = plain[i] - 'a';
plain[i] += key;
plain[i] = (plain[i] % 26) + 'a';
printf("%c", plain[i]);
} else if (isupper(plain[i])) {
plain[i] = plain[i] - 'A';
plain[i] += key;
plain[i] = (plain[i] % 26) + 'A';
printf("%c", plain[i]);
} else {
printf("%c", plain[i]);
}
}
printf("\n");
return 0;
}
``````
1 vote
1. 
Social
CS50 is a great course. Enjoy it! :)

CS50 is a great course. Enjoy it! :)

1. Scion
Thanks! So far so good.

Thanks! So far so good.

2. 
planNine
In response to the edit: why would you even need such a big key (2000)?

In response to the edit: why would you even need such a big key (2000)?

1. 
Scion