# Make it rain characters

Inspired by this chat mini-challenge.

Given a string as input (ASCII printable characters only), output the string with the letters "raining" down. Each letter must be a random number of lines downward (random between 0 and the length of the string, each having non-zero probability), and only one character per column. All possible outputs must again have a non-zero probability of occurring.

That's maybe a little confusing, so here's an example (taken from that CMC):

Hello World

d
H
o
llo

l
W
e
r


Note how the H is one space down, the d is zero down, and the llo all happen to line up. The r is the farthest down, at 9, but is still less than the string length away from the top. This is just one example, there are dozens of other possibilities for input Hello World.

Other examples could be:

test

t
e
s
t

PP&CG

& G
P

P  C


• Input and output can be given by any convenient method.
• The input is guaranteed non-empty (i.e., you'll never receive "" as input).
• You can print it to STDOUT or return it as a function result.
• Either a full program or a function are acceptable.
• Any amount of extraneous whitespace is acceptable, so long as the characters line up appropriately (e.g., feel free to pad as a rectangle).
• Standard loopholes are forbidden.
• This is so all usual golfing rules apply, and the shortest code (in bytes) wins.
• Thought this was going to involve animation when I read the title. Have we had an animated version of this? – Shaggy Apr 12 at 22:22
• @Shaggy Not that I've seen or been able to find. – AdmBorkBork Apr 13 at 0:52
• "Any amount of extraneous whitespace is acceptable" - does that include a leading line of whitespace? – Jonathan Allan Apr 13 at 19:52
• I know we have had one based on the Matrix code, but good luck finding it with those 2 keywords! Do you mind if I Sandbox the idea? – Shaggy Apr 13 at 19:57
• What is the maximum input size answers need to implement? I'm seeing many people use random functions that use "pseudo-random" in the backendground, and certain input words are larger than the size of the seed used in those generators, and they will fail the " All possible outputs must again have a non-zero probability of occurring." constraint you have specified – Ferrybig Apr 13 at 20:33

# R, 104 bytes

function(s){m=matrix(" ",l<-nchar(s),l)
m[cbind(1:l,sample(l,l,T))]=el(strsplit(s,""))
write(m,1,l,,"")}


Try it online!

Input as a string; writes to stdout.

• You can save a byte by using scan(,'') and nesting a bunch of calls but honestly I vastly prefer the function approach, this other one is hideous for minimal gain. Might spark some ideas, though. Try it online! – CriminallyVulgar Apr 12 at 14:32
• I think sample(l,,T) suffices instead of sample(l,l,T) (-1 byte). – Robin Ryder Apr 12 at 15:24

# JavaScript (ES6), 72 bytes

Takes input as a list of characters. Returns a matrix of characters.

a=>a.map((_,y)=>a.map((c,x)=>Math.random()<.5|!a[y+1]?(a[x]=' ',c):' '))


Try it online!

• I think you could save one byte by not negating the ternary expression. – orthoplex Apr 12 at 14:12
• @orthoplex That wouldn't work because (0|'A') === (0|undefined) and the remaining letters would not be guaranteed anymore to appear on the last row. (So, basically, it's just like |!a[y+1] was removed altogether.) – Arnauld Apr 12 at 14:15
• Google says that Math.random() returns a number in [0, 1), so couldn't Math.random()<.5 become Math.random()>0? – nedla2004 Apr 13 at 2:30
• @nedla2004 In theory, yes. In practice, I think it's very likely that the implementation(s) of the PRNG can't possibly return exactly $0$ (let alone close enough $0$'s so that all configurations actually have a chance to occur). Because we define a language by its implementation, I personally think it's therefore invalid. – Arnauld Apr 13 at 10:34
• For what platform did you make your javascript for? Since the challenge has a uniqueness requirement, and does not specify a max input, this really matters, as most platforms are using a math.random() implementation that has an internal state, and thus cannot generate unique output. – Ferrybig Apr 13 at 23:31

# Pyth - 9 bytes

Outputs list of lines.

.tm+*;OlQ

m      (Q implicit)     Map over input
+    (d implicit)      Concatenate to loop var
*                     String repeat
;                    This refers to the var replaced by loop var, which is d=" "
O                    Random number less than
lQ                  Length of input


# J, 30 19 bytes

|:@,.]{.~"+_2-#?@##


Try it online!

• 0|:]{.~"+_1-#?# for 15 bytes – Galen Ivanov Apr 13 at 9:12
• @GalenIvanov I love this idea but since the dyad deal takes without repetition, the range of outputs won't span the full range of possibilities. eg, it won't be possible for 2 letters to have randomly dropped to the same height. – Jonah Apr 14 at 16:52
• @Conor, You can do 0|:]{.~"+_2-#?@## for 17 bytes without changing the behavior of your answer. – Jonah Apr 14 at 17:08
• @Jonah Yes, right. I realized that and had another 17-byte solution. – Galen Ivanov Apr 14 at 18:09

# Japt, 8 bytes

-1 byte from @Shaggy

y_iUÊö ç


y_iUÊö ç        Full Program. Implicit input U
y_              transpose and map each row in U (Call it X)
i             Insert at the beginning of X:
ç        " " repeated ↓ many times
UÊö          random integer in [0, length of U]
implicit transpose back and output


Try it online!

• 8 bytes – Shaggy Apr 12 at 14:33
• lol @Shaggy I got the same answer a while ago, i was just adding an explanation. Thanks anyway c: – Luis felipe De jesus Munoz Apr 12 at 14:44

# APL (Dyalog Unicode), 16 bytesSBCS

Anonymous tacit prefix function

⍉∘↑⊢↑¨⍨∘-∘?≢⍴1+≢


≢ length of string

1+ one added to that

≢⍴ "length" copies of that

∘? random integers in range 1…those, and then…

∘- negate, and then…

⊢↑¨⍨ take than many elements from each character, padding on the left with spaces

∘↑ mix list of strings into matrix, padding with spaces on the right

⍉ transpose

Try it online!

# Japt, 8 bytes

yÈùUÊö Ä


Try it

yÈùUÊö Ä     :Implicit input of string U
y            :Transpose
È           :Pass each column through the following function and transpose back
ù          :  Left pad with spaces to length
UÊ        :    Length of U
ö       :    Random number in the range [0,UÊ)
Ä     :    Plus 1


# Jelly, 10 bytes

³LŻX⁶x;)z⁶


Try it online!

      )    | For each input character
³L         | Length of original input
Ż        | 0..length
X       | Random number from that list
⁶x     | That number of spaces
;   | Concatenate to the character
z⁶ | Finally transpose with space as filler

• We can output a leading line of spaces, so 9 bytes (although I feel like there may be an 8...) – Jonathan Allan Apr 16 at 21:14
• @JonathanAllan wouldn’t that be equivalent to the range 0..(length - 1)? The question specifies between 0 and the string length. Or am I missing something? – Nick Kennedy Apr 16 at 21:18
• Oh yes, I forgot about the inclusive-ness - when I asked three days ago about leading whitespace I'm pretty sure I had a 9, and I think it wasnt what I suggested above... hmm – Jonathan Allan Apr 16 at 21:39

# Ruby, 5957 55 bytes

->a{a.map{|c|s=[' ']*z=a.size;s[rand z]=c;s}.transpose}


Try it online!

Inputs 1D, outputs 2D array of characters.

# PHP, 88 bytes

for($o='';$i<$l=strlen($argn);$o[$i+$l*rand(0,$l)]=$argn[$i++]);echo chunk_split($o,$l);


Try it online!

Or 94 bytes using PHP's cryptographic random integers function.

for($o='';$i<$l=strlen($argn);$o[$i+$l*random_int(0,$l)]=$argn[$i++]);echo chunk_split($o,$l);


Try it online!

Input from STDIN, output to STDOUT. Run as:

$echo Hello World|php -nF rain.php l W l e r d H o l o  -1 byte (empty string instead of space) and +1 byte (err on side of rules) thx to @ASCII-only! • wonder if this is allowed, since you don't include the <?php that the ?> closes. also seems like it's fine if $o is the empty string – ASCII-only Apr 12 at 23:41
• @ASCII-only, you're right, empty string will also work (with a little more complaining). I'm not sure the ruling on using closing and re-opening tags, I'll update it though to stay on the up and up. Thx! – 640KB Apr 12 at 23:54
• Note that the rules for this challenge say "All possible outputs must again have a non-zero probability of occurring", this is not possible with the PHP rand function, as you can have an input text that requires more random than the size of the internal seed rand uses, so technically your answer fails to satisfy this condition in all situations – Ferrybig Apr 13 at 20:33
• @Ferrybig I agree that the legacy PHP/libc rand is not useful for much, however all supported/production versions of PHP (7.1+) use Mersenne Twister RND (mt_rand) internally for a random number generation. Is your concern that this is not sufficiently random for this challenge? – 640KB Apr 13 at 23:08
• mt_rand also uses an pseudo random number system internally, and also has the limitations. Assuming that PHP is compiled with 64 bit numbers (and that the seed, used for rand or mt_rand accepts this full range) would generate unique outputs for words upto the length of 13 characters or shorter. Pretty limiting if you ask me – Ferrybig Apr 13 at 23:26

# Charcoal, 10 9 bytes

↑Ｅθ◧ι⊕‽Ｌθ


Try it online! Link is to verbose version of code. Edit: Saved 1 byte thanks to @ASCII-only. Explanation:

  θ         Input string
Ｅ          Map over characters
θ   Input string
Ｌ    Length
‽     Random value
⊕      Incremented
ι       Current character
↑           Print rotated


As ASCII-only points out, you can move the letters randomly up instead of down for the same effect (except that there might be extra white space at the bottom rather than the top). Printing an array of characters upwards is equivalent to printing a string normally, so the padding then just offsets each character vertically by a random amount.

• wonder if printing up instead would work? – ASCII-only Apr 12 at 23:40

# 05AB1E (legacy), 9 bytes

εIgÝΩú}ζ»


Input as a string or list of characters (either is fine).

Try it online.

Much slower 9-bytes alternative:

gDÝsãΩúζ»


Input as a list of characters.

Try it online.

Both use the legacy version of 05AB1E, since the new version requires an explicit €S before the ζ..

Explanation:

ε       # Map each character in the (implicit) input to:
Ig     #  Take the length of the input
Ý    #  Create a list in the range [0, input-length]
Ω   #  Pop and push a random integer from this list
}ζ      # After the map: zip/transpose; swapping rows/columns (with space as default filler)
»     # Then join all strings by newlines (and it output implicitly as result)

g          # Get the length of the (implicit) input-list
D         # Duplicate this length
Ý        # Create a list in the range [0, input-length]
sã      # Take the cartesian product of this list that many times
Ω     # Pop and push a random list from this list of lists of integers
ú    # Pad the characters in the (implicit) input-list with that many spaces
ζ   # Zip/transpose; swapping rows/columns (with space as default filler)
»  # Then join all strings by newlines (and it output implicitly as result)

• Was thinking along the lines of gD¸s∍ÝδΩ but it's longer... and ooo... this doesn't even work in the new 05AB1E ;). – Magic Octopus Urn Apr 18 at 14:53

# C (gcc), 131 bytes

f(char*s){int l=strlen(s),R[l],i=l,j;for(srand(time(0));i--;)R[i]=rand()%l;for(;++i<l*l;printf("\n%c"+!!j,i/l^R[j]?32:s[j]))j=i%l;}


Try it online!

• Suggest R[j=i%l]?32:s[j])); instead of R[j]?32:s[j]))j=i%l; – ceilingcat May 5 at 15:49

# Julia, 69 bytes

f(s)=(n=length(s);z=fill(' ',n,n);for i=1:n z[rand(1:n),i]=s[i]end;z)


This defines a function f that accepts a String or Vector{Char} and returns a Matrix{Char}.

Ungolfed:

function f(s)
n = length(s)
z = fill(' ', n, n)  # an n×n matrix of spaces
for i = 1:n
# set a random entry in the ith column to the ith character in s
z[rand(1:n),i] = s[i]
end
z
end


Example:

julia> f("test")
4×4 Array{Char,2}:
't'  ' '  ' '  ' '
' '  ' '  ' '  ' '
' '  'e'  ' '  't'
' '  ' '  's'  ' '


This could surely be better; my golfing skills are pretty rusty.

Try it online!

# Perl 5-F, 50 49 bytes

-1 by @DomHastings

map$;[rand@F][$i++]=$_,@F;say map$_||' ',@$_ for@  Try it online! • Nice, actually works! :P You can save a couple of bytes with map$_||$",@$_ too! – Dom Hastings Apr 18 at 7:51

# PowerShell, 108102 98 bytes

-4 bytes thanks to mazzy

$a=1..($z=($y=$args|% t*y).count)|%{random $z} 1..$z|%{-join($y|%{"$_"[$a[$i++%$z]-eq+$r]});$r++}  Try it online! Basically iterates 1..length of the string twice, once to get random line locations for each character, and a second time to actually build each line using those indices. Figuring out how to do it in one sweep is where the big byte savings are. • – mazzy Jul 17 at 10:07 # SmileBASIC 3, 62 bytes LINPUT T$L=LEN(T$)CLS FOR I=0TO L-1LOCATE,RND(L+1)?T$[I];
NEXT


# Red, 84 bytes

func[s][foreach n random collect[repeat n length? s[keep n]][print pad/left s/:n n]]


Try it online!

# Python - 92 bytes

import random
lambda s:map(None,*[(random.randrange(len(s))*' '+c).ljust(len(s))for c in s])

• You have to include the import random – MilkyWay90 Apr 12 at 22:20
• @MilkyWay90 d'oh – Maltysen Apr 13 at 11:23
• You can save 1 byte by using from random import* instead. – orthoplex Apr 13 at 11:44
• I think map(None,... doesn't work in Python 3, so you should specify Python 2 in your title. – orthoplex Apr 13 at 11:50

# K (oK), 20 bytes

Solution:

+c$(-1-c?c:#x)$++x:


Try it online!

Explanation:

+c$(-1-c?c:#x)$++x: / the solution
x: / store input as x
+   / flip (enlist)
+    / flip again (break into chars)
$/ pad (each) character ( ) / do this together #x / length of x c: / save as c -c? / choose (?) c times from c -1 / subtract from -1 c$                 / pad to length of x
+                   / flip


# Python 3, 140 131 bytes

from random import*
def f(s):
e=range(len(s))
p=[choice(e)for t in s]
for r in e:print(''.join((r-p[i]and' 'or s[i]for i in e)))


Try it online!

# Python 3, 208 bytes

import random as r;x=input();R=range(len(x));c=[r.choice(R) for i in R];y=[' '*c[i]+x[i]+' '*(len(x)-c[i]) for i in R];R=range(len(y));print('\n'.join([''.join(r) for r in [[y[i][j] for i in R] for j in R]]))


Creates a list of random choices, then makes a list of columns with blank space everywhere except at the index specified by each random choice. The columns are transposed into rows and printed out with newlines between them.