in order to implement a cipher for a code challenge I have to add the integer representation of each key in the message and the key among other things. The integer representation: A becomes 1, B becomes 2 etc. We can ignore the offset in ASCII for now.
I tried to create a function that adds the codepoints of two chars a and b:
def combine(a, b), do: ?a + ?b
The problem is that the codepoints of the letters a and b are added, not the parameter’s codepoints. Hence I’m always adding 97 + 98, regardless which chars I passed to combine.
Is there an alternative way to get the code point of a parameter/variable?
I’m trying to implement the Solitaire cipher. For this I have a message and a key of the same length which only contain uppercased letters of the latin alphabet.
In the next step I have to add the numerical representations (e.g. A being 1 in the alphabet or 65 in ASCII) of each letter in the message and the key. The result is the encrypted message.
I wrote a zipWith helper function (borrowed from Haskell) to add the letters of the key and message:
zipWith(msg, key, &combiner/2)
As you already saw in the implementation of the combiner method it takes two letters and adds their numerical representation.
The point where I’m struggling is that I can’t get the ASCII code for the letters in order to add them.
thank you for sharing your ideas and posting the detailed code examples
At the beginning I might have thought to complex about the problem with the goal to reduce the number of list operations. However, with your appraoch and some inspiration from the submitted solutions of RubyQuiz #1 I came up with the following:
Feel free to suggest improvements.
defmodule SolitaireCipher do
def encrypt(msg, key) do
process(msg, key, fn(m, k) -> 64 + mod(m + k - 128) end)
end
def decrypt(msg, key) do
process(msg, key, fn(m, k) -> 64 + mod(m - k) end)
end
defp process(msg, key, routine) do
msg
|> prepare
|> Enum.map(fn(msg_p) -> combine(prepare(key), msg_p, routine) end)
|> List.to_string
end
defp prepare(input) do
input
|> String.upcase
|> String.replace(~r/[^A-Z]/, "")
|> String.to_charlist
|> Enum.with_index
end
defp combine(key_with_index, {m, m_index}, routine) do
{k, _} = Enum.find(key_with_index, fn({_, k_index}) -> m_index == k_index end)
routine.(m, k)
end
defp mod(char) when char > 26, do: char-26
defp mod(char) when char < 1, do: char+26
defp mod(char), do: char
end
And if someone wants to try the example from the quiz:
msg = "Code in Ruby, live longer!"
key = "DWJXHYRFDGTMSHPUURXJ"
SolitaireCipher.encrypt(msg, key)
|> SolitaireCipher.decrypt(key)
@digitalcraftsman: if it works as expected (decrypted message is not same as original) then it’s ok
I’m not expert of speed optimisations and cryptography, so if there is something to suggest then I see only indention and documentation + type validation.
Please use 2 spaces for indention (at least when sharing code in forum - simple replace) - I think that comparing this my code looks better
Example:
defmodule SolitaireCipher do
@moduledoc """
Solitare Cipher
( ... )
Usage:
iex> msg = "Code in Ruby, live longer!"
"Code in Ruby, live longer!"
iex> key = "DWJXHYRFDGTMSHPUURXJ"
"DWJXHYRFDGTMSHPUURXJ"
iex> msg |> SolitaireCipher.encrypt(key) |> SolitaireCipher.decrypt(key)
"CODEINRUBYLIVELONGER"
"""
@spec encrypt(String.t, String.t) :: String.t
@doc """
Encrypting message.
This function requires two parameters:
`msg` - message to encrypt
`key` - key for encryption and decryption process
"""
def encrypt(msg, key) when is_bitstring(msg) and is_bitstring(key) do
# ...
end
# and similarly for decrypt method
# ...
end
Well, the message that the types in is sanitized before the encryption starts. This process removes everything that isn’t a letter of the latin alphabet and uppercases the remaining letters. Hence you actually encrypt “CODEINRUBYLIVELONGER” according to the exercise.
This was just a fun exercise so that I’ve a reason to get more familiar with the standard library. The cryptographic aspect can be omitted. I was more talking about reducing operations on the strings and char lists.
Please use 2 spaces for indention (at least when sharing code in forum - simple replace) - I think that comparing this my code looks better
I’ll fix the indentation in the code example above. Regarding documentation I’ll look into this as well. Currently, I’m half way through Elixir in Action and there still a ton of stuff left to learn.