13
\$\begingroup\$

Implement this key cipher

Goal

Use the algorithm (explained in the Algorithm section) to implement a certain cipher.

The program must read input from STDIN or the closest available equivalent, use the algorithm to generate the ciphertext and a key.

The ciphertext and the key will be written to STDOUT or the closest available equivalent. Any format is allowed, as long as it outputs the ciphertext and the key.

Algorithm

Convert the characters in the string into the respective ASCII values. For example:

Hello -> 72 101 108 108 111

Next, you will need to generate a key as long as the string with random numbers in the range of 0-9.

Hello -> 62841

Add the integers in the random number sequence to the ASCII values of the string. In the above examples, 72 would become 78, and 101 would become 104.

72 + 6 = 78, 101 + 2 = 103, 108 + 8 = 116, etc

Next, convert the new values back to characters. In the above examples, the text Hello has become Ngtpp.

Examples

(These are simply examples of what the output might look like. The output can and will vary.)

Hello World

Lfrlu)_supg
41606984343

This will be encoded
    
Zhjs$~koo gj$iuhofgj
60104723305544750226

Rules

  • You can assume that the input will only contain characters in the range a-z, A-Z, and spaces.
  • Submissions must be full programs or functions.
  • Submissions will be scored in bytes.
  • Standard loopholes are forbidden.
  • This is code-golf, so the shortest code wins.

(This is one of my first challenges, if there's something wrong with it, feel free to tell me how I could improve it.)

\$\endgroup\$
18
  • 5
    \$\begingroup\$ This challenge looks good to me, except for a couple of thoughts. 1. Is a function allowed instead of a full program? A related question is could the values be returned instead of printed? 2. You said preferably with the format (ciphertext)\n(key). "preferred features" and code golf don't mix very well. Your should make that mandatory or allow other output formats. 3. Does the key have to be printed without spaces? What about printing it in list format, e.g. [0, 5, 2, ...]? \$\endgroup\$
    – DJMcMayhem
    Commented Aug 19, 2016 at 13:48
  • \$\begingroup\$ Can the key have leading zeroes? \$\endgroup\$ Commented Aug 19, 2016 at 13:53
  • 1
    \$\begingroup\$ Nice first challenge but I'm not so sure on the strict IO formats. Usually functions are allowed and usually answers can read from one of the accepted IO methods. This includes outputting an array with the items \$\endgroup\$
    – Downgoat
    Commented Aug 19, 2016 at 15:54
  • 1
    \$\begingroup\$ Do the digits of the key have to be generated with an uniform distribution? \$\endgroup\$
    – Dennis
    Commented Aug 19, 2016 at 15:58
  • 1
    \$\begingroup\$ Uh ... 101 + 2 is 103, not 104. :-) \$\endgroup\$
    – YetiCGN
    Commented Aug 19, 2016 at 19:27

19 Answers 19

5
\$\begingroup\$

Jelly, 12 9 bytes

⁵ṁX€’Ṅ+OỌ

Try it online!

How it works

⁵ṁX€’Ṅ+OỌ  Main link. Argument: s (string)

⁵             Set the return value to 10.
 ṁ            Mold; create an array of 10's with the length of s.
  X€          Pseudo-randomly pick a integer between 1 and 10, for each 10.
    ’         Decrement, so the integers fall in the range [0, ..., 9].
     Ṅ        Print the key, as an array, followed by a linefeed.
      +O      Add the integers to the ordinals (code points) of s.
        Ọ     Unordinal; convert back to characters.
\$\endgroup\$
5
\$\begingroup\$

Python 3, 130 bytes

Thanks to @Rod for pointing out a bug

from random import*
def f(x):l=10**len(x);k=str(randint(0,l-1)+l)[1:];print(''.join(chr(ord(i)+int(j))for i,j in zip(x,k))+'\n'+k)

A function that takes input via argument as a string and prints to STDOUT.

How it works

from random import*  Import everything from the random module
def f(x):            Function with input string x
l=10**len(x)         Define l for later use as 10^length(x)
randint(0,l-1)+l     Generate a random integer in the range [0, l-1] and add l, giving a
                     number with l+1 digits...
k=str(...)[1:]       ...convert to a string and remove the first character, giving a key of
                     length l that can include leading zeroes, and store in k
for i,j in zip(x,k)  For each character pair i,j in x and k:
chr(ord(i)+int(j))    Find the UTF-8 code-point (same as ASCII for the ASCII characters),
                      add the relevant key digit and convert back to character
''.join(...)         Concatenate the characters of the ciphertext
print(...+'\n'+k)    Add newline and key, then print to STDOUT

Try it on Ideone

\$\endgroup\$
2
  • \$\begingroup\$ your key generator do not generates keys starting with 0. increasing the boundaries by a factor of 10 and removing the 1st digit should fix: m=10**len(x);k=str(randint(m,m*10))[1:]; and you even save a byte in the process c: \$\endgroup\$
    – Rod
    Commented Aug 19, 2016 at 14:45
  • \$\begingroup\$ @Rod Thanks for pointing out the bug. That won't save any bytes, however, since randint is inclusive, meaning that you would need to do m*10-1. I've just thought of a way to fix it for the same byte count. \$\endgroup\$ Commented Aug 19, 2016 at 17:09
3
\$\begingroup\$

Pyth - 16 bytes

Waiting for decision by OP on the output formats.

sCM+VCMQKmOTQjkK

Test Suite.

\$\endgroup\$
1
  • \$\begingroup\$ I decided on the format. \$\endgroup\$
    – m654
    Commented Aug 19, 2016 at 14:02
3
\$\begingroup\$

Actually, 17 bytes

;`X9J`M;(O¥♂cΣ@εj

Try it online!

Explanation:

;`X9J`M;(O¥♂cΣ@εj
;                  dupe input
 `X9J`M            for each character in input copy:
  X9J                discard the character, push a random integer in [0, 9]
       ;           duplicate the offset array
        (O         bring input to top of stack, ordinal array
          ¥♂c      pairwise addition with offset array, turn each ordinal into a character
             Σ     concatenate
              @εj  concatenate the copy of the offset array
\$\endgroup\$
2
\$\begingroup\$

CJam - 14 bytes

When I saw the ascii code math, I knew I had to write a CJam answer.

q_{;Amr}%_@.+p

Try it online here.

\$\endgroup\$
2
\$\begingroup\$

MATL, 13 bytes

"10r*]v!kGy+c

The output looks like this:

9 5 8 2 1
Qjtnp

Try it online!

Explanation:

"    ]          % For each character:
 10             % Push a 10 onto the stack
   r            % Push a random float in [O, 1)
    *           % Multiply. This essentially the same thing as pushing a number in [0, 10)
      v!k       % Join all of these together, and take the floor
         G      % Push the input again
          y     % Duplicate the array of random numbers
           +    % And add these together. Since MATL treats strings as an array of chars, we don't need to explicitly convert types
            c   % Display as string
\$\endgroup\$
9
  • \$\begingroup\$ I'm not sure if that's the right format... \$\endgroup\$
    – Leaky Nun
    Commented Aug 19, 2016 at 15:51
  • \$\begingroup\$ @Leaky Nun I changed the rules a little. \$\endgroup\$
    – m654
    Commented Aug 19, 2016 at 15:56
  • \$\begingroup\$ @m654 Where did you say there can be spaces between the values? \$\endgroup\$
    – Leaky Nun
    Commented Aug 19, 2016 at 15:57
  • \$\begingroup\$ @LeakyNun Originally there was a rule against them but I removed it. \$\endgroup\$
    – m654
    Commented Aug 19, 2016 at 15:59
  • 1
    \$\begingroup\$ Good idea to use the loop. It's actually shorter than the multiple-input version of r or Yr \$\endgroup\$
    – Luis Mendo
    Commented Aug 19, 2016 at 16:29
2
\$\begingroup\$

PowerShell v2+, 79 77 bytes

param($n)-join(($x=[char[]]$n|%{0..9|Random})|%{[char]($_+$n[$i++])});-join$x

Takes input $n, loops over every character and gets a Random element from 0..9 each iteration. Stores those numbers (as an array) into $x. Pipes that array into another loop. Each iteration, takes the current element $_, adds it to the positional char sliced out of $n (implicit char-to-int cast), then re-casts as [char]. Leaves that on the pipeline. That's encapsulated in parens and -joined together to form the word. That's left on the pipeline. Additionally, the number $x is also -joined together and left on the pipeline. Those are implicitly printed with a Write-Output at the end of execution, which results in them being printed with a newline by default.

Example

PS C:\Tools\Scripts\golfing> .\implement-this-key-cipher.ps1 'Hello World!'
Lhoot(Yt{mf"
433358259121
\$\endgroup\$
2
\$\begingroup\$

C#, 252 247 245 232 216 Bytes

The size is pretty bad compared to the other solutions but nevertheless...

using System;using System.Linq;class p{static void Main(){var c="";var i=Console.ReadLine();var r=new Random();for(int b=0;b++<i.Count();){int d=r.Next(10);Console.Write((char)(i[b]+d));c+=d;}Console.Write("\n"+c);}}

This is my second ever answer to a codegolf and I'm quite a beginner considering C# so I'd appreciate to hear how to get it shorter :)

Ungolfed:

using System;
using System.Linq;

class p
{
    static void Main()
    {
        var c = "";
        var i = Console.ReadLine();
        var r = new Random();
        for (int b = 0; b++ < i.Count();)
        {
            int d = r.Next(10);
            Console.Write((char)(i[b] + d));
            c += d;
        }
        Console.Write("\n" + c);
    }
}
  • Saved 5 Bytes thanks to @FryAmTheEggman
  • Saved 2 Bytes thanks to @theLambGoat
  • Saved 7 Bytes by removing static from class p
  • Saved 24 Bytes thanks to @milk
\$\endgroup\$
6
  • 1
    \$\begingroup\$ The trick is not to compare with other languages ;) I'm not particularly well versed in C# golf, but can you do b++<i.Count() and leave the third clause empty? Also, I don't think you need a trailing newline, so the last call to WriteLine could be Write instead. \$\endgroup\$ Commented Aug 19, 2016 at 17:01
  • \$\begingroup\$ I'm also not well versed in C# but I think you can move the =r.Next(10) up to the declaration of d and save on a set of parenthesis in the write. Or does the random not return an int so you can't do that? \$\endgroup\$ Commented Aug 19, 2016 at 17:26
  • \$\begingroup\$ I think I can do that, let me check \$\endgroup\$ Commented Aug 19, 2016 at 18:00
  • \$\begingroup\$ You can replace types with var. ie- var c= instead of string c= to shave a few bytes. \$\endgroup\$
    – milk
    Commented Aug 19, 2016 at 19:55
  • \$\begingroup\$ Why not leave the result of Console.ReadLine() as string? i.Length is shorter than i.Count(), you won't need System.Linq. string has a char indexer. Also creating new Random objects in the loop is less bytes: new Random().Next(10). \$\endgroup\$
    – milk
    Commented Aug 19, 2016 at 20:01
2
\$\begingroup\$

CJam, 11 bytes

Nq{Amr_o+}/

Try it online!

How it works

N            Push a linefeed on the stack.
 q           Read all input from STDIN and push it on the stack.
  {      }/  For each character in the input:
   Amr       Pseudo-randomly pick an integer in [0 ... 9].
      _o     Print a copy.
        +    Add the integer to the character.
             (implicit) Print the linefeed, followed by the modified characters.
\$\endgroup\$
2
\$\begingroup\$

05AB1E, 18 17 bytes

vžh.RDyÇ+ç`?}J¶?,

Explanation

v           }      # for each char in input
 žh.RD             # push 2 copies of a random number in [0..9]
      yÇ+          # add 1 copy to the current chars ascii value
         ç`?       # convert to char, flatten and print
             J     # join stack (which contain the digits of the key)
              ¶?,  # print a newline followed by the key

Try it online

\$\endgroup\$
2
\$\begingroup\$

Python 3, 112 bytes

c is a function that returns the encrypted text and the key

from random import*
c=lambda t:map(''.join,zip(*[(chr(a+b),str(b))for a,b in((ord(i),randint(0,9))for i in t)]))

Here is a code that does the same thing and is a bit more readable

def encrypt(text):
    # keep the codes of the letters in the input and a random key
    # that will be used later to encrypt this letter
    letter_and_key = ((ord(letter),randint(0,9)) for letter in text)

    # encrypt the letter and keep the key used as a string
    output_and_key = [(chr(letter_code+key), str(key))
                      for letter_code, key in letter_and_key]

    # At this point the values are kept in the format:
    # [(firstletter, firstkey), (secondletter, secondkey), ...]

    # to reorder the list to be able to output in the format "text key"
    text, key = map(''.join, zip(*output_and_key))

    # same as print(*output_and_key)
    return text, key

Output:

>>> text, key = c('Hello World')
>>> print(text, key, sep='\n')
Liuot#`oylk
44935390707
\$\endgroup\$
1
  • \$\begingroup\$ Welcome to this site! \$\endgroup\$
    – DJMcMayhem
    Commented Aug 23, 2016 at 21:43
1
\$\begingroup\$

PHP, 63 86 82 bytes

Edit: forgot to print the key...

Thanks to Alex Howansky for saving me 4 bytes.

for(;$i<strlen($a=$argv[1]);$s.=$r)echo chr(ord($a[$i++])+$r=rand(0,9));echo"
$s";

Input is given through a command line argument. Takes each character in the string and adds a random int from 0-9 to its ASCII code, then converts the code back to ASCII. Every random number is appended to $s, which is printed at the end.

\$\endgroup\$
3
  • \$\begingroup\$ You need to print the key as well. \$\endgroup\$ Commented Aug 19, 2016 at 16:05
  • \$\begingroup\$ You can put the $s.=$r after the 2nd semi in the for loop, saving a byte because you can dump its trailing semi. Then your loop will only be one statement so you can cut out the wrapping braces, saving 2 more bytes. Then at the end, you can put the $s inside the quoted string saving the . operator for one more byte. :) \$\endgroup\$ Commented Aug 19, 2016 at 16:26
  • \$\begingroup\$ @AlexHowansky: That's very true. Thanks \$\endgroup\$ Commented Aug 19, 2016 at 16:31
1
\$\begingroup\$

J, 32 bytes

<@:e,:~[:<[:u:3&u:+e=.[:?[:$&10#

python equivalent:

from random import randint
def encrypt(message):
    rand_list = list(map(lambda x: randint(0, 9), range(len(message))))
    return (''.join(list(map(lambda x,y: chr(x+y), rand_list, map(ord, message)))), rand_list)
\$\endgroup\$
1
\$\begingroup\$

Perl, 34 bytes

Includes +1 for -p

#!/usr/bin/perl -p
s%.%$\.=$==rand 10;chr$=+ord$&%eg
\$\endgroup\$
0
\$\begingroup\$

Perl, 65 bytes

for(split'',$ARGV[0]){$;.=$a=int rand 9;$b.=chr$a+ord}say"$b\n$;"

Took me awhile to figure out how to get the input without a new line at the end. Takes it as a command line arg

\$\endgroup\$
3
  • \$\begingroup\$ Your solution has some problems. Input is not read form STDIN, $; does not start empty so it prints the old content and the rand can never generate 9. They are easy to fix and using STDIN will make your code shorter :-) \$\endgroup\$
    – Ton Hospel
    Commented Aug 23, 2016 at 14:19
  • \$\begingroup\$ @TonHospel Usually input requirements are loose and args are acceptable over STDIN and while taking input from STDIN is shorter, having to remove the newline from it makes it longer. And while rand does generate numbers < 9, Perl's int method rounds rather than floors so anything >=8.5 should end up as 9 \$\endgroup\$ Commented Aug 23, 2016 at 14:40
  • \$\begingroup\$ Input requirements usually are loose, but here it wasn't. Getting non newline from STDIN is easy: <>=~/./g. And no, int in perl truncates towards 0, it doesn't round. perl -wle 'print int 8.6' outputs 8 \$\endgroup\$
    – Ton Hospel
    Commented Aug 23, 2016 at 14:50
0
\$\begingroup\$

Python 2, 84 99 bytes

def f(x):y=`id(x)**len(x)`[1:len(x)+1];return''.join(map(chr,[ord(a)+int(b)for a,b in zip(x,y)])),y

Uses the id() value of the string to generate random numbers.

Try it

\$\endgroup\$
5
  • \$\begingroup\$ You have to output the key as well as the ciphertext. \$\endgroup\$ Commented Aug 19, 2016 at 19:33
  • \$\begingroup\$ @TheBikingViking don't know how I missed that. Thanks--fixed \$\endgroup\$ Commented Aug 19, 2016 at 19:47
  • \$\begingroup\$ I think that this also has the same problem as an earlier version of my Python answer; it never produces keys with leading zeroes. \$\endgroup\$ Commented Aug 19, 2016 at 20:13
  • \$\begingroup\$ @TheBikingViking Fixed again \$\endgroup\$ Commented Aug 19, 2016 at 20:25
  • \$\begingroup\$ change map(chr,[ord(a)+int(b)for a,b in zip(x,y)]) to map(lambda x,y:chr(ord(x)+int(y)),x,y)? that should save something \$\endgroup\$ Commented Aug 20, 2016 at 3:05
0
\$\begingroup\$

Senva, 74 bytes

Here is the shortest program I've made :

2'(`>0.>{@}0'{v}2-2'0,{@}1'{v}0'{+}{'}9%+{^}{1-}1'"{+}{~}>$10.~0'2+"0,-:>$

A little explanation ? (Note: BM means Back-Memory) :

// === Input and informations storing ===

2'  // Go to the 3rd cell (the two first will be used to store informations)
(   // Ask the user for a string (it will be stored as a suite of ASCII codes)
`   // Go the end of the string
>   // Make a new cell
0.  // Put a 0 to mark the end of the string
>   // Make a new cell, here will be stored the first random number
{@} // Store its adress in BM
0'  // Go to the 1st cell
{v} // Paste the adress, now the 1st cell contains the adress of the first random number
2-  // Subtract 2 because the string starts at adress 2 (the 3rd cell)
2'  // Go to the 3rd cell (where the string begins)

// === String encryption and displaying ===

0,  // While the current cell doesn't contain 0 (while we didn't reach the string's end)
  {@}  // Store the character's adress into the memory
  1'   // Go to the 2nd cell
  {v}  // Paste the value, now the 1st cell contains the adress of the current char
  0'   // Go to the 1st cell
  {+}  // Add the adress of the first random number to the current char adress
  {'}  // Go to this adrses
  9%+  // A random number between 0 and 10
  {^}  // Store this number in BM
  {1-} // Decrease BM (random number between 0 and 9)
  1'   // Go to the 1st cell
  "    // Go to the adress pointed by the cell (the adress of the current char)
  {+}  // Add it to the random number value
  {~}  // Display it as an ASCII character
  >    // Go to the next cell (the next character)
$   // End of the loop
10. // Set the new line's ASCII code into the current cell (which is now useless, so it can be overwritten)
~   // Display the new line
0'  // Go to the first cell
2+  // Add 2 to the adress, because we are not in the string loop : we cancel the 2 substraction
"   // Go to the pointed adress (the first random number's one)

// === Display the random numbers ===

0,  // While we didn't reach the end of the random numbers suite
    // That was why I stored numbers between 1 and 10, the first equal to 0 will be the end of the suite
  - // Decrease it (number between 0 and 9)
  : // Display the current random number as an integer
  > // Go to the next cell (the next number)
$ // End of the loop

That appears bigger now, true :p ? Maybe it's possible to optimize this code, but for the moment that's the shortest I've found.

\$\endgroup\$
0
\$\begingroup\$

C#, 174 bytes

using static System.Console;class b{static void Main(){var c=new System.Random();var d="\n";foreach(var e in ReadLine()){var f=c.Next(10);Write((char)(e+f));d+=f;}Write(d);}}

Ungolfed:

using static System.Console;

class b
{
    static void Main()
    {
        var c = new System.Random();
        var d = "\n";

        foreach (var e in ReadLine())
        {
            var f = c.Next(10);
            Write((char)(e + f));
            d += f;
        }

        Write(d);
    }
}

Pretty straightforward, really.

\$\endgroup\$
0
\$\begingroup\$

Perl 6: 55 or 70 bytes

As an anonymous function that takes a string parameter, and returns a list of two strings (54 characters, 55 bytes):

{my @n=^9 .roll(.ords);(.ords Z+@n)».chr.join,@n.join}

As a program that reads from STDIN and writes to STDOUT (69 characters, 70 bytes):

my @a=get.ords;my @n=^9 .roll(@a);say (@a Z+@n)».chr.join;say @n.join
\$\endgroup\$

Your Answer

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

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