2

I'm tasked with creating a Caesar cipher for a project I am working on. A Caesar cipher takes each letter in a string of text and replaces it with a letter a fixed number of places away from it (dictated by the cipher key). For instance if my text is "cat" and my cipher key is 3, my new word would be "fdw" (I'm assuming positive numbers move the letters to the right). I've been able to get my code to solve correctly for most strings of text, but I am finding that if my string includes > ? or @ it will not work. Their ASCii codes are 62,63 and 64 if that helps. Any input is appreciated!

def caesar_cipher(str, num)
strArray = str.split('')

cipherArray = strArray.collect do |letter|
 letter = letter.ord

  if (65...90).include?(letter + num) || (97...122).include?(letter + num)
    letter = letter + num
  elsif (91...96).include?(letter + num) || (123...148).include?(letter + num)
    letter = (letter - 26) + num
  else
    letter
  end

end

 cipherArray = cipherArray.collect {|x| x.chr}
 cipher = cipherArray.join('')

end


caesar_cipher("Am I ill-prepared for this challenge?", 3)
#ord 62-64 DON'T work >, ?, @
2
  • 4
    What characters would you consider three letters right of >, ? or @? Commented Sep 20, 2017 at 20:50
  • @spickermann Hi! I'm using the ASCii codes for each symbol. Using that, > is equal to 62, ? is equal to 63, and @ is equal to 64. Adding 3 to each would gives us 65 ("A"), 66 ("B") and 67 ("C"). Commented Sep 21, 2017 at 21:29

2 Answers 2

1

You should create an alphabet variable, just think in if you use both ends then you will have 2 problems: negative numbers and an ASCii number that doesn't exist. You can handle this with module operator % or with a single subtraction.

alphabet = "abcde"

text_to_cipher= "aaee" => 0044 #number based in his position at aphabet var
key = 3

result will be 3377 => dd¡? or any other symbol since 7 is out of the string length "abcde" same happens with ASCii at its ends. With module operator, you can restrict that.

size_of_your_alphabet = 5 # For this case
7%size_of_your_alphabet = 2
Sign up to request clarification or add additional context in comments.

Comments

1

The Ruby builtin tr is ideal to implement substitution ciphers.

Step 1: assemble the characters you wish to transform.

chars = ["A".."Z", "a".."z", ">".."@"].flat_map(&:to_a)

Step 2: create a 1:1 array of the transformed characters

transformed = chars.map{|c| (c.ord + 3).chr}

Step 3: apply tr to transform the string.

str.tr(chars.join, transformed.join)

Full working example:

def caesar_cipher(str, num)
  chars = ["A".."Z", "a".."z", ">".."@"].flat_map(&:to_a)
  transformed = chars.map{|c| (c.ord + num).chr}
  str.tr(chars.join, transformed.join)
end

Output:

> caesar_cipher("Am I ill-prepared for this challenge?", 3)
#=> "Dq L mpp-tvitevih jsv xlmw gleppirkiC"

Notes:

  • Most substitution ciphers actually rely on letter rotation, not ASCII values. My inital assumption was that you wanted a rotation, e.g. ("a".."z").to_a.rotate(num). See prior edit for a working example of that.
  • You can use ranges in tr() to create a really simple Caesar cipher: str.tr('A-Za-z','B-ZAb-za')
  • Edit: Also, because of the range specification feature, the \ is an escape character so that you can use literals like -. See this SO answer for details. I think the above exhibits a bug due to this, because it contains a \ which should be escaped by another \.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.