><> (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.
Can the printable ASCII character be the same? – MayorMonty – 2016-11-22T14:34:20.950
@MayorMonty sure just randomize it for obscurity – jacksonecac – 2016-11-22T14:38:04.347
1Do each individual character need to be random or can there be a set of
n
unique random ascii characters between the letters (no duplicate random characters between the letters)? – Emigna – 2016-11-22T14:40:07.530each individual character needs to be random – jacksonecac – 2016-11-22T14:46:30.507
3random 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? – Luis Mendo – 2016-11-22T15:10:31.933
Are
n
trailing cipher characters after the last character in the string acceptable? – Yodle – 2016-11-22T15:59:25.5331@Yodle Yes that is acceptable – jacksonecac – 2016-11-22T16:01:26.193
@LuisMendo thanks for the comment, I don't think that level of granularity is necessary. I think random is pretty well understood within the computing community. – jacksonecac – 2016-11-22T16:02:40.367
3@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 ofn
copies of the same random character, they are still random, but they are not statistically independent. And so on – Luis Mendo – 2016-11-22T16:19:05.2835@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. – Martin Ender – 2016-11-22T16:19:06.5273This isn't really a cipher. It's steganographic, perhaps. – Greg Martin – 2016-11-22T18:21:15.503
@MartinEnder "made, done, happening, or chosen without method or conscious decision." – jacksonecac – 2016-11-22T18:55:54.243
2That'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. – Level River St – 2016-11-22T19:30:39.293
@LevelRiverSt if you are such a stickler on rules, then recognize that I am not going to define more parameters for answering this question after there are 11 answers already, which would not be fair to them. thanks. – jacksonecac – 2016-11-22T19:33:24.677
The issue with not defining what distribution the samples should approximately follow is that it we need to make assumptions on what is allowed and it therefore it becomes ambigous if a solution is valid. We could for example replace
String.fromCharCode(...[...Array(n)].map(_=>Math.random()*95+32))
with[...Array(n)].map(_=>'TX'[+(Math.random()>.5)]).join('')
and lazily outgolf the current ES6 submission by 9 bytes. According to the spec it should count because it is a random character. However, it seems unfair, doesn't it? So should that count? See where this is going? – Lmis – 2016-11-23T07:52:33.370I posted an attempt at a standard definition over on meta (http://meta.codegolf.stackexchange.com/a/10663/56071) to avoid ambiguities in the future. It is consistent with the answers I can read that have been posted so far, FWIW.
– Lmis – 2016-11-23T08:38:31.963@Lmis that would be a fine solution in my book. There were no strict guidelines on this to allow any number of solutions. I don't see what that would be cheating. – jacksonecac – 2016-11-23T12:27:13.843
@GregMartin I guess it can be seen as a variant of the Scytale cipher (with just one line used and the rest filled randomly), or a Grille cipher (with a quite regular grille).
– Paŭlo Ebermann – 2016-11-23T21:10:59.407I guess I wouldn't really call those ciphers either; but I take your point about the historical usage of the word :) – Greg Martin – 2016-11-23T22:42:32.000