15
\$\begingroup\$

Generate a cipher given a number and string

Your task is simple. Given a string s and a number 0 <= n <= 9 as inputs, insert a pseudo-random printable ASCII character between each character of the string n times. Such that for each character of s there are n random characters between them. Spaces should be trimmed.

Input:

  • string s phrase to encrypt in the cipher
  • integer n in the range of 0 <= n <= 9

Example:

Input:

The treasure is here
2

Output:

T!0h32eF4t0irlkehma7ys#0u*&r*he!2iH^sB,h!@e0)r$he


This is so the shortest code wins! Good Luck and have fun!

\$\endgroup\$
19
  • 3
    \$\begingroup\$ random printable ASCII character You need to define what random means here. Shold all printable ASCII characters have the same probability? Should they be statistically independent? What flexibility do we have regarding this? \$\endgroup\$
    – Luis Mendo
    Nov 22, 2016 at 15:10
  • 3
    \$\begingroup\$ @jacksonecac I disagree. Just saying random is not enough. For example, if I only pick random characters with even ASCII codes, that's still random but that's probably not accepted (or ist it?) If each series of n characters consists of n copies of the same random character, they are still random, but they are not statistically independent. And so on \$\endgroup\$
    – Luis Mendo
    Nov 22, 2016 at 16:19
  • 5
    \$\begingroup\$ @jacksonecac "random" is a very broad term. Can I choose the characters with a normal distribution, so that characters around O are more likely than spaces or ~? If it has to be uniform, then you should say so explicitly. And if it doesn't have to be uniform, then you should at least state something like each character needs to have a non-zero probability. You've also stated in a previous comment that each character does have to have an independent distribution, so if this is important, it should be mentioned in the challenge. There is a very broad spectrum of randomness. \$\endgroup\$ Nov 22, 2016 at 16:19
  • 3
    \$\begingroup\$ This isn't really a cipher. It's steganographic, perhaps. \$\endgroup\$ Nov 22, 2016 at 18:21
  • 2
    \$\begingroup\$ That's not an appropriate response to @MartinEnder 's valid point. A solution would be to specify explicitly that the characters have to be uniform and statistically independent of each other and the comments will stop. An alternative (but more open to abuse) specification would be that skewed distributions or those where characters are dependent on one another are OK so long as all characters have nonzero possibility of occuring. In code golf specification is important for fairness. As you seem unwilling to address these valid comments on an otherwise good challenge, I`m voting to close. \$\endgroup\$ Nov 22, 2016 at 19:30

21 Answers 21

7
\$\begingroup\$

C#, 141 131 bytes

Pretty similar to @Geobit's Java answer, except longer currently :(

(I,n)=>{var R=new System.Random();var o="";int i,r;foreach(var c in I)if(c>32)for(i=r=0,o+=c;i++<n;){r=R.Next(33,127);o+=(char)r;}return o;};

Full lambda stuff:

Func<string, int, string> a = (I,n) =>
{
    var R=new System.Random();
    var o="";
    int i;
    foreach(var c in I)
        if(c>32)
            for(i=0,o+=c;i++<n;o+=(char)R.Next(33,127));
    return o;
};
\$\endgroup\$
2
  • \$\begingroup\$ why R=... You can just directly use new System.Random().Next(...) I think \$\endgroup\$ Nov 22, 2016 at 16:09
  • 2
    \$\begingroup\$ @RomanGräf msdn.microsoft.com/en-us/library/h343ddh9(v=vs.110).aspx C#'s Random class, without a seed, will use the System clock, so if you call in rapid succession (such as within the loop there), most of the values end up being identical, which wouldn't work in most cases :( Believe me, I always try and then remember that. \$\endgroup\$
    – Yodle
    Nov 22, 2016 at 16:12
7
\$\begingroup\$

05AB1E, 11 bytes

ð-vy²FžQ.RJ

Try it online!

Explanation

ð-           # remove spaces from input string
  v          # for each char in the string
   y         # push the char
    ²F       # input-2 number of times do:
      žQ.R   # push a random ascii character
          J  # join to string
\$\endgroup\$
8
  • \$\begingroup\$ close! trim the spaces! :) \$\endgroup\$ Nov 22, 2016 at 14:37
  • \$\begingroup\$ @jacksonecac: Missed that part sorry. Fixed now :) \$\endgroup\$
    – Emigna
    Nov 22, 2016 at 14:38
  • \$\begingroup\$ nice job! that works! \$\endgroup\$ Nov 22, 2016 at 14:39
  • 1
    \$\begingroup\$ @carusocomputing: That adds random characters after the last letter as well. Not just in between letters. \$\endgroup\$
    – Emigna
    Nov 22, 2016 at 15:08
  • 1
    \$\begingroup\$ @Emigna After a recent comment under the question this seems to be fine :) \$\endgroup\$ Nov 22, 2016 at 16:03
6
\$\begingroup\$

Java 7, 132 124 bytes

String f(int n,char[]a){String o="";int i;for(char b:a)if(b>32)for(i=0,o+=b;i++<n;o+=(char)(33+Math.random()*94));return o;}

Nothing fancy, just a double loop like you'd expect. Outer to loop the string, inner to fill in randoms:

String f(int n,char[]a){
    String o="";
    int i;
    for(char b:a)
        if(b>32)
            for(i=0,
                o+=b;
                    i++<n;
                        o+=(char)(33+Math.random()*94));
    return o;
}
\$\endgroup\$
4
  • \$\begingroup\$ No need for k: String f(int n,char[]a){String o="";for(char b:a)if(b>32){o+=b;for(int i=0;i++<n;o+=(char)(33+Math.random()*94));}return o;} (125 bytes) \$\endgroup\$ Nov 22, 2016 at 16:00
  • \$\begingroup\$ Oooh right. I was using it with a different method. Didn't think about taking it out when I went with the char cast. Thanks! \$\endgroup\$
    – Geobits
    Nov 22, 2016 at 16:01
  • \$\begingroup\$ My bad. I miscounted, my suggestion was also 124 bytes: I checked the column instead of the length ;) \$\endgroup\$ Nov 22, 2016 at 16:11
  • \$\begingroup\$ Yeah, I noticed that when comparing the two :) \$\endgroup\$
    – Geobits
    Nov 22, 2016 at 16:11
5
\$\begingroup\$

Pyke, 12 11 9 bytes

d-FQV~KHs

Try it here!

d-        -  remove spaces from input
  F       - for i in ^:
   QV     -  repeat (number) times:
     ~KH  -    random_from(printable)
        s -   sum(^)

Trailing random characters is fine according to OP.

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

Octave, 43 bytes

@(s,n)[s(s>32);33+94*rand(n,nnz(s>32))](:)'

This takes a string s and an integer n as input. A string in Octave is simply an array of characters. s>32 is a logical map with 1 for any non-space characers. The code appends a matrix with n rows and the same number of columns as s(s>32) has, containing floating point numbers between 33 and 126. It is implicitly rounded to integers and converted to ASCII-characters when it's concatenated with the string s. (:)' straightens this to a horizontal array of characters.

Test it here!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Implicit rounding! Nice \$\endgroup\$
    – Luis Mendo
    Nov 22, 2016 at 15:14
4
\$\begingroup\$

Python 2, 123 122 118 114 98 Bytes

Man, I wish random wasn't so expensive (and that we didn't have to filter for spaces). Now we have big savings from being allowed to have cipher characters at the end :) Anyways, here ya go:

from random import*
f=lambda s,n:s and(' '<s[0])*eval('s[0]'+'+chr(randint(32,126))'*n)+f(s[1:],n)
\$\endgroup\$
4
\$\begingroup\$

JavaScript (Firefox 30+), 96 bytes

(s,n)=>s.replace(/. */g,x=>x[0]+String.fromCharCode(...[for(_ of Array(n))Math.random()*95+32]))

Pure ES6 is two bytes longer:

(s,n)=>s.replace(/. */g,x=>x[0]+String.fromCharCode(...[...Array(n)].map(_=>Math.random()*95+32)))

Here's a really cool approach which is sadly 26 bytes longer:

(s,n)=>String.raw({raw:s.split` `.join``},...[for(_ of s)String.fromCharCode(...[for(_ of Array(n))Math.random()*95+32])])
\$\endgroup\$
3
  • \$\begingroup\$ Strictly speaking /. *(?=.)/ doesn't work for strings beginning or ending in spaces, not that anyone cares. (You're even allowed trailing random characters now.) \$\endgroup\$
    – Neil
    Nov 23, 2016 at 1:38
  • \$\begingroup\$ @Neil Trailing random chars are allowed? I guess I can just remove the (?=.) which takes care of spaces at the end of strings. \$\endgroup\$ Nov 23, 2016 at 1:55
  • \$\begingroup\$ The spec is not so clear, but I think you shold avoid inserting blank spaces, so 94+33 instead of 95+32 \$\endgroup\$
    – edc65
    Nov 23, 2016 at 9:31
3
\$\begingroup\$

R, 97 bytes

Unnamed function taking inputs x (string) and n.

function(x,n,l=nchar(x))for(i in 1:l)cat(substr(x,i,i),if(i<l)intToUtf8(sample(32:126,n)),sep="")

Try it on R-fiddle

\$\endgroup\$
3
\$\begingroup\$

CJam, 21 18 bytes

lS-(ol~f{{95mrSc+\}*}

Try it online!

Prints n random trailing characters.

Explanation

lS-        e# Read line and remove spaces.
l~         e# Read and evaluate another line.
f{         e# For each character (passing in N)...
  {        e#   Do this N times...
    95mr   e#     Push random integer in [0, 95).
    Sc+    e#     Add to space character, giving a random printable ASCII character.
  }*
}
           e# All characters remaining on the stack are printed implicitly
           e# at the end of the program.
\$\endgroup\$
3
\$\begingroup\$

Bash, 124 bytes

Pure bash + coreutils, no control flow structures, no sub-languages, no "eval"

Golfed

E() { N=${1// /};paste <(fold -1<<<$N) <(tr -cd "\\40-\\176"<\/dev\/urandom|head -c$(($2*${#N}-$2))|fold -$2)|tr -d '\t\n';}

Test

>E "The treasure is here" 2
TkZhf(e&Rt@FrS,edha+-sJTuh.rX@eVKi+3s<7hftey8r*/e
\$\endgroup\$
3
\$\begingroup\$

Q/KDB+, 39 36 34 Bytes

raze{""sv(raze x;`char$40+n?87)}prior s
(,/)({""sv((,/)x;`char$40+n?87)}':)s

(,/)({""sv((,/)x;10h$40+n?87)}':)s

Variables in use:

s:"The treasure is here"
n:2

This uses the prior adverb, which applies the function to it's left between each item to the right and its predecessor. (Essentially, applies function to the left between each character on the right.)

Generate n random numbers between 40 and 126 then convert them to a character equivilent: (q seems to only have characters for these)

`char$40+n?87

//Possible characters.
()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~

Example output:

TVghrveVp Rpti+r0sea3a9nsIjuRXrAReJ; +di=ys`{ ikhKTe4trTZesz

EDIT:
Saved 3 bytes by converting q's raze into (,/) using the k notation and similarly changed prior to `: Thanks to @slackwear for the update, shaved 2 bytes :)

\$\endgroup\$
1
  • 1
    \$\begingroup\$ can save a couple of bytes by casting with 10h$ \$\endgroup\$
    – skeevey
    Nov 22, 2016 at 18:52
2
\$\begingroup\$

Java 8, 114 bytes

Golfed

(n,s)->s.chars().forEach((c)->{if(c>32)for(int i=0;i<=n;)System.out.print((char)(++i==1?c:33+Math.random()*94));})

Lambda that accepts an Integer and a String. Inspired by the Java 7 answer, double loop using some Java 8 Stream syntax (String.chars) to save a few bytes.

Input

3, "Hello world!"

Output

HfKIedb3l<-Ul%}vod"Bw\"|oa`%rH-}l/-{dMS;!B#X
\$\endgroup\$
2
\$\begingroup\$

Scala, 95 94 Bytes

def c(s:String,i:Int)=s.filter(_>32).mkString(scala.util.Random.alphanumeric.take(i).mkString)

Nothing overly fancy, besides the use of mkString on a String. It treats the string as a list of characters, and allows me to insert a separator between them. My separator is the appropriate number of randomly generated alphanumeric characters.

\$\endgroup\$
3
  • \$\begingroup\$ Not quite answers the question. The nature of Random.alphanumeric will cause each chunk to be the same, so it's a lame cipher... See this example: scala> c("Hello", 1) res0: String = Hbeblblbo \$\endgroup\$
    – Jacob
    Nov 23, 2016 at 11:08
  • \$\begingroup\$ BTW, you can remove the filter. Invoking mkString on a String will treat it as a character collection. \$\endgroup\$
    – Jacob
    Nov 23, 2016 at 11:10
  • \$\begingroup\$ @Jacob the filter is the most efficient way I could think of to remove spaces. I left the random as is since it seemed sufficient, but if I have time I'll add in a separate function for proper random text. \$\endgroup\$
    – Ethan
    Nov 29, 2016 at 17:34
2
\$\begingroup\$

><> (Fish), 107 106 103 bytes

<v}:{r&" "
1xv+
2<v+
v}<
<~v!?=&:&:
6.>ol2-?!;a
:{{:}l1-[rv
v2<
<1x|!}:}-1<v!?:{{:o-+
^3<v ~}}r]~<
.40<

Try it online!

It isn't super random, but it is random. Just place the string and integer on the stack (Example: "Hello world!", 5).

Input: "Hello world!", 5
Output: H^\^]^eceeedldcdeclgfffhowhhfggojkkkkrdccedl]]\]\d

Full Explanation

This is a slightly older version of the code, until I update the explanation. It's mostly the same, just maybe a bit easier to read:

< v}:{r&" "
+1xv
+2<v
   }
:&:<~ v!?=&
?!;a6.>ol2-
:{{:}l1-[rv
v2<
<1x|!}:}-1<v!?:{{:o+*
^3<v ~}}r]~<
.43<

We'll pretend the string parameter is s and the integer parameter is i.

< v}:{r&" "

The < tells the fish to immediately move left, which wraps around to " ", which adds a space characted to the stack. Then the fish travels over &, which adds the space to the register. r reverses the stack and {:} shifts the stack to the left (putting i on the end of the stack), copies the value on the end of the stack, then shifts it to the right. v tells the fish to begin moving downwards.

+1xv
+2<v
   }

x tells the fish to move in a random direction, ultimately resulting in the fish going right and continuing downwards, or pass over 1+ or 2+ beforehand. These add 1 or 2 respectively to the number on the end of the stack. If the fish travels upwards, it hits v again and travels back down. } shifts the stack to the right, then having i at position 1 on the stack and this new variable at position 0 (we'll call it m).

:&:<~ v!?=&

This section is a function, let's call it whitespaceTrimmer. It begins where the < is. It simply strips spaces that're on the end of the stack (so the beginning of the string) until it runs into a non-space character.

So immediately the fish swims into a < and must travel to the left. It then runs into :&:& which copies the value on the end of the stack, places the space from the register onto the end of the stack, copies it, then places it back onto the register.

Then the fish hits =?!v ~, or more specifically, =, which pops the last two values (the two we just created) off of the stack, compares them, places a 1 on the end of the stack if they're equal, and a 0 on the end of the stack if they're different. The ? pops the new value off the end of the stack, if it is 0 it doesn't execute the next instruction, which in this case is !, it instead executes v, which orders the fish to move downwards (exiting the function).

If it is 1 however, then it has found a space, so it executes the ! which is a trampoline, and that causes the fish to skip the next instruction, which is a v, so the fish continues. In front of the fish, it sees ~ which tells it to pop the last value off the stack (confirmed to be a space), then the fish continues, and runs the function again.

?!;a6.>ol2-

The fish is immediately told to swim right by a >, then output the last character on the stack by o (which, the first time this is run, is the first character of s). It gets the length of the stack from l, places a 2 on the end of the stack, then - causes 2 to be subtracted from l. It hits ?!; which, remembering what ? does, causes the fish to skip the ! if the stack is empty, and land on ;, which ends the program.

Following if there are still characters on the stack, we execute ! which causes the fish to bounce over the ; and execute a6., which stores a (AKA 10), and 6 on the end of the stack, which are x, y coordinates for ., which pops them off the end of the stack, then teleports the fish to 10, 6, and execute the instruction to the right of that postion (as the fish is swimming right).

This is less complicated than it sounds when you realise y position 6 is the line below this one. x position 10 is then v, and to the right of that is , which is a no-op. This causes the fish to continue swimming right and actually begin execution at the beginning of the line...

:{{:}l1-[rv
v2<
<1x|!}:}-1<v!?:{{:o+*
^3<v ~}}r]~<
.43<

So this is the function that adds the random text in between the characters. It's a bit of a mouthful, but that's just because I tried to make it a little bit extra random. Let's call this genRandomChars.

The :{{:}l1-[rv is actually the setup for the function, and less-so part of the actual function itself. The fish first swims over :{{ which copies the value on the end of the stack, then shifts it to the left twice. If you recall that i was at postion 1 on the stack, then you'd know i is now on the end of the stack.

The fish then swims over :} which copies i, and shifts the stack to the right, placing i both at the beginning and end of the stack. l1-[ has the fish place the length on the end of the stack, subtract 1 from it, then [ creates a new stack, moving l-1 (stack length minus 1) values to the new stack (so just leaving i on the old stack). Then the fish simply hits rv which reverses the stack again (I think creating a new stack reverses it for some reason), and orders the fish to swim downwards once more, truely beginning the function at the < below.

So currently the end of the stack has m and our temporary i, which we'll call ti. Immediately the fish swims over 1-}, which subtracts 1 from ti and moves it to the beginning of the stack. Then :} which simply copies m and moves it to the beginning of the stack (putting ti at stack position 1).

This is when we hit this little thing:

v2<
<1x|!
^3<

This is actually dead simple. The ! causes the fish to skip | and execute x. Remembering what x does, we remember this makes the fish move in any 4 directions. | is simply a mirror, and causes the fish to swim back to x. So basically, the fish will place 1, 2, or 3 onto the end of the stack, and continue moving left, wrapping around.

The fish then executes *+o which causes the last two values on the stack to be popped off, multiplied together, and the result push back on, then the same thing with addition, then the final value is popped off the stack and outputted with o. Our stack is now relatively normal again containing just [m, ti, s].

:}}: causes the value on the end of the stack (basically s position 0) ot be copied, then the stack is shifted to the right twice (placing ti on the front again), then ti is copied. ?!v should be pretty easy to understand by now. Basically if ti is 0 then we exit the function with v, otherwise we execute ! and skip v (doing another loop).

If ti is 0 and we are done outputting slightly random characters, then we execute v and see:

   v ~}}r]~<
.43<

Nothing too fancy here. We remove ti from the stack via ~. Then ] is new, it pops all our values off the stack and places them on the old stack! Because of the reversal issue we reverse with r, then shift the stack right twice with }}~, shufting the stack to the right, giving us [m, i, s], the ~ is to remove the extra duplicated s[0] from earlier in the function as we'd need it if we were doing a loop (but we're not, we're exiting). v tells the fish to swim down and into >34. (inverted to show execution order), which tells the fish to simply swim left and into 3, 4 (because the . is a jump!). 3, 4 is actually just to the right of the beginning whitespaceTrimmer, which is perfect because we are travelling left.

Following all this logic we can follow the fish until the stack is ultimately empty and program exits just after whitespaceTrimmer is executed.

\$\endgroup\$
2
  • \$\begingroup\$ Hmm I didn't see that the character has to be printable. This will require slight modification which might make it less random and smaller. \$\endgroup\$ Nov 27, 2016 at 0:33
  • \$\begingroup\$ It doesn't really look a whole lot less random. I believe it should work in most cases, I haven't had it fail yet. It will work with any capital or lowercase letter for sure, and some symbols. I'm pretty sure this satisfies the requirements of the challenge. \$\endgroup\$ Nov 27, 2016 at 0:46
2
\$\begingroup\$

Perl 5, 81 bytes

($_,$n)=<>;chomp;y/ //d;$\=chop;print map{$_,map{chr 33+int rand 94}1..$n}split//

I hope the following helps you understand what the one-liner does:

($_, $n) = <STDIN>;  # Reads in the string into $_,
                     # and the number into $n, from standard input.
                     # (<STDIN> works slightly different from <>.)
chomp($_);           # Removes the newline from the string.
$_ =~ tr/ //d;       # `Tr/`ansliterates ASCII space characters
                     # into nothing, effectively `/d`eleting them.
$\ = chop($_);       # Chop()s off the last character out of $_ and
                     # appends it to the output when print()ing.
                     # (Perl always prints $\ after you call print().)
print( map {         # Each element of [List 1] will be mapped to:
    $_,              #   -- Itself, and
                     # (When mapping, each element is available as $_.)
    map {            # (`map` resembles `foreach` but returns a list.)
        chr(         #   -- A random ASCII character, in the range
          33 + int(rand(94)) ) # from 33 (!, hex 21) to 126 (~, hex 7E)
    } 1..$n          # ...$n times! (Over the range 1 to $n, actually.)
} split(//, $_) );   # [List 1] is $_, split() into characters.
\$\endgroup\$
1
\$\begingroup\$

Clojure, 126 123 118 122 117 bytes

(defn c[m n](apply str(remove #(=\space %)(mapcat #(apply str %(for [_(range n)](char(rand-nth(range 32 127)))))m))))

Maps over the message, inserts random characters in, then concatenates the result.

The instructions suggest that all spaces should be stripped from the result string. If only spaces from the original message are supposed to be stripped, I can change that.

Ungolfed:

(defn cipher [message n]
  (apply str
    (remove #(= \space %)
        (mapcat #(apply str %
                     (for [_ (range n)]
                       (char (rand-nth (range 32 127)))))
                message))))
\$\endgroup\$
1
\$\begingroup\$

Python 3, 127 Bytes

import random
a,b=input(),input()
print(''.join([x+''.join([chr(random.randint(33,126))for c in range(int(b))]) for x in a]))

Probably way longer than necessary, but this is mine golfed so far.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This adds random characters in front of the first character, and spaces are not trimmed. I think both of these things breaks the rules. \$\endgroup\$ Nov 23, 2016 at 7:21
1
\$\begingroup\$

PHP, 96 bytes

Takes String as argument 1 and Number as argument 2

for(;($s=str_replace(' ','',$argv[1]))[$j]>'';)echo$i++%($argv[2]+1)?chr(rand(33,127)):$s[$j++];

Try it online

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

Python 3, 133 Bytes

from random import *
c=int(input())
print(''.join([i+''.join([chr(randint(33,126))for i in range(c)])for i in input().strip(' ')])[:-c])
\$\endgroup\$
1
\$\begingroup\$

Node.js, 88 bytes

(s,n)=>s.replace(/./g,c=>c!=" "?c+crypto.randomBytes(n).toString`base64`.substr(0,n):"")

Example outputs:

f("The treasure is here", 2)
// THphdwekAtMArbSeU1aDTsZWuqnr2yek1iyUsKshqXewvrVCeTi

f("The treasure is here", 2)
// TYshlcep6t4Iru7e29aQ1sl/uvQrlzeSJihysDhhOLe1urpte1m

Try it online!

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

C, 102 100 bytes

-2 bytes for skipping continue.

i;f(char*s,int n){do{while(*s==32)++s;putchar(*s);i=n;while(i--)putchar(32+rand()%95);}while(*s++);}

Ungolfed:

i;
f(char*s,int n){
 do{
  while(*s==32)++s;
  putchar(*s);
  i=n;
  while(i--)
    putchar(32+rand()%95);
 }while(*s++);
}

Usage:

main(){
  char a[]="A   A A";
  f(a,3);
}
\$\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.