31
\$\begingroup\$

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.
\$\endgroup\$
8
  • 2
    \$\begingroup\$ Thought this was going to involve animation when I read the title. Have we had an animated version of this? \$\endgroup\$
    – Shaggy
    Commented Apr 12, 2019 at 22:22
  • \$\begingroup\$ @Shaggy Not that I've seen or been able to find. \$\endgroup\$ Commented Apr 13, 2019 at 0:52
  • \$\begingroup\$ "Any amount of extraneous whitespace is acceptable" - does that include a leading line of whitespace? \$\endgroup\$ Commented Apr 13, 2019 at 19:52
  • \$\begingroup\$ 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? \$\endgroup\$
    – Shaggy
    Commented Apr 13, 2019 at 19:57
  • \$\begingroup\$ 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 \$\endgroup\$
    – Ferrybig
    Commented Apr 13, 2019 at 20:33

23 Answers 23

5
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ 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! \$\endgroup\$ Commented Apr 12, 2019 at 14:32
  • \$\begingroup\$ I think sample(l,,T) suffices instead of sample(l,l,T) (-1 byte). \$\endgroup\$ Commented Apr 12, 2019 at 15:24
4
\$\begingroup\$

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!

\$\endgroup\$
7
  • \$\begingroup\$ I think you could save one byte by not negating the ternary expression. \$\endgroup\$
    – orthoplex
    Commented Apr 12, 2019 at 14:12
  • 2
    \$\begingroup\$ @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.) \$\endgroup\$
    – Arnauld
    Commented Apr 12, 2019 at 14:15
  • \$\begingroup\$ Google says that Math.random() returns a number in [0, 1), so couldn't Math.random()<.5 become Math.random()>0? \$\endgroup\$
    – nedla2004
    Commented Apr 13, 2019 at 2:30
  • \$\begingroup\$ @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. \$\endgroup\$
    – Arnauld
    Commented Apr 13, 2019 at 10:34
  • \$\begingroup\$ 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. \$\endgroup\$
    – Ferrybig
    Commented Apr 13, 2019 at 23:31
4
\$\begingroup\$

Pyth - 9 bytes

Outputs list of lines.

.tm+*;OlQ

 .t                       Transpose, padding with spaces
  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

Try it online.

\$\endgroup\$
4
\$\begingroup\$

J, 30 19 bytes

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

Try it online!

\$\endgroup\$
5
  • 1
    \$\begingroup\$ 0|:]{.~"+_1-#?# for 15 bytes \$\endgroup\$ Commented Apr 13, 2019 at 9:12
  • \$\begingroup\$ @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. \$\endgroup\$
    – Jonah
    Commented Apr 14, 2019 at 16:52
  • \$\begingroup\$ @Conor, You can do 0|:]{.~"+_2-#?@## for 17 bytes without changing the behavior of your answer. \$\endgroup\$
    – Jonah
    Commented Apr 14, 2019 at 17:08
  • 1
    \$\begingroup\$ @Jonah Yes, right. I realized that and had another 17-byte solution. \$\endgroup\$ Commented Apr 14, 2019 at 18:09
  • \$\begingroup\$ 0|:]({.~_2-?)"0# for 16 bytes \$\endgroup\$
    – Jonah
    Commented Jan 31, 2020 at 4:52
4
\$\begingroup\$

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!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ 8 bytes \$\endgroup\$
    – Shaggy
    Commented Apr 12, 2019 at 14:33
  • \$\begingroup\$ lol @Shaggy I got the same answer a while ago, i was just adding an explanation. Thanks anyway c: \$\endgroup\$ Commented Apr 12, 2019 at 14:44
3
\$\begingroup\$

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!

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

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!

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

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
\$\endgroup\$
2
\$\begingroup\$

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
\$\endgroup\$
3
  • \$\begingroup\$ We can output a leading line of spaces, so 9 bytes (although I feel like there may be an 8...) \$\endgroup\$ Commented Apr 16, 2019 at 21:14
  • \$\begingroup\$ @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? \$\endgroup\$ Commented Apr 16, 2019 at 21:18
  • \$\begingroup\$ 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 \$\endgroup\$ Commented Apr 16, 2019 at 21:39
2
\$\begingroup\$

Ruby, 59 57 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.

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

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!

\$\endgroup\$
5
  • \$\begingroup\$ 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 \$\endgroup\$
    – ASCII-only
    Commented Apr 12, 2019 at 23:41
  • \$\begingroup\$ @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! \$\endgroup\$
    – 640KB
    Commented Apr 12, 2019 at 23:54
  • \$\begingroup\$ 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 \$\endgroup\$
    – Ferrybig
    Commented Apr 13, 2019 at 20:33
  • \$\begingroup\$ @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? \$\endgroup\$
    – 640KB
    Commented Apr 13, 2019 at 23:08
  • \$\begingroup\$ 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 \$\endgroup\$
    – Ferrybig
    Commented Apr 13, 2019 at 23:26
1
\$\begingroup\$

Charcoal, 10 9 bytes

↑Eθ◧ι⊕‽Lθ

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

  θ         Input string
 E          Map over characters
        θ   Input string
       L    Length
      ‽     Random value
     ⊕      Incremented
    ι       Current character
   ◧        Padded to length
↑           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.

\$\endgroup\$
1
  • \$\begingroup\$ wonder if printing up instead would work? \$\endgroup\$
    – ASCII-only
    Commented Apr 12, 2019 at 23:40
1
\$\begingroup\$

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
     ú  #  Pad the current character with that many leading spaces
}ζ      # 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)
\$\endgroup\$
1
  • \$\begingroup\$ Was thinking along the lines of gD¸s∍ÝδΩ but it's longer... and ooo... this doesn't even work in the new 05AB1E ;). \$\endgroup\$ Commented Apr 18, 2019 at 14:53
1
\$\begingroup\$

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
\$\endgroup\$
1
\$\begingroup\$

Perl 5 -F, 50 49 bytes

-1 by @DomHastings

map$;[rand@F][$i++]=$_,@F;say map$_||' ',@$_ for@

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Nice, actually works! :P You can save a couple of bytes with map$_||$",@$_ too! \$\endgroup\$ Commented Apr 18, 2019 at 7:51
1
\$\begingroup\$

PowerShell, 108 102 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.

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

C (gcc), 131 125 bytes

-6 bytes thanks to ceilingcat

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

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ @ceilingcat Cheers! \$\endgroup\$
    – gastropner
    Commented Jan 27, 2020 at 20:39
1
\$\begingroup\$

AWK, 120 118 bytes

{while(i++<NF)r[i]=int(rand()*NF)+1;for(;l++<NF;j=k=0){while(k++<NF)if(r[k]==l){printf"%*c",k-j,$k;j=k}print FS}}

Try it online!

I've included the 5 bytes in the score for the necessary -F '' switch, but I had to use the BEGIN{FS=""} directive for the TIO link since it doesn't process the command-line switch properly.

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

SmileBASIC 3, 62 bytes

LINPUT T$L=LEN(T$)CLS
FOR I=0TO L-1LOCATE,RND(L+1)?T$[I];
NEXT
\$\endgroup\$
0
\$\begingroup\$

Red, 84 bytes

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

Try it online!

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

Python - 92 bytes

import random
lambda s:map(None,*[(random.randrange(len(s))*' '+c).ljust(len(s))for c in s])
\$\endgroup\$
4
  • \$\begingroup\$ You have to include the import random \$\endgroup\$
    – MilkyWay90
    Commented Apr 12, 2019 at 22:20
  • \$\begingroup\$ @MilkyWay90 d'oh \$\endgroup\$
    – Maltysen
    Commented Apr 13, 2019 at 11:23
  • 1
    \$\begingroup\$ You can save 1 byte by using from random import* instead. \$\endgroup\$
    – orthoplex
    Commented Apr 13, 2019 at 11:44
  • \$\begingroup\$ I think map(None,... doesn't work in Python 3, so you should specify Python 2 in your title. \$\endgroup\$
    – orthoplex
    Commented Apr 13, 2019 at 11:50
0
\$\begingroup\$

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!

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

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.

Try it online!

\$\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.