Illustrate music beats

You know—they look like this:

The goal is to draw a music beats illustration like the following:

=     =      =
=  =  =      =          =
== = ==   =  ==     = ====
== ====  == ===   = = =======
======== == ====  = ========= =
=================================

The rules are:

• The width of the illustration is 33 symbols, but if you need—any trailing spaces exceeding this width are allowed.
• Each column is made of equals signs (=).
• Each column has a random height (the height of the next column shouldn’t depend in any way on the height of the previous column), varying from 1 to 6. It’s also fine if it’s at least possible to get some input with no strict math probability (i.e. some inputs could appear more rarely than others).
• A column can’t float above the bottom and have gaps in it.
• Since every column has the minimal height of 1, the last row can’t have any gaps either—it always consists of 33 equals signs.
• Since it’s possible to have no columns with the height of 6 (it’s all random after all): in this case you don’t need to have a top line made of spaces. Applies to any edge cases of this nature: if suddenly your code provided no columns with the height greater than 1, you don’t need to have additional lines made of spaces above the bottom line.
• You don’t take any input.
• @Lynn Oh, originally it did specify, but I accidentally removed it from the post. – nicael Jul 10 '16 at 18:59
• (Nitpicking) That looks to me like a spectrogram at a given instant, rather than a representation of any beats – Luis Mendo Jul 10 '16 at 19:00
• Are columns allowed to be separated by spaces? (i.e., bottom row would be = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =) – LegionMammal978 Jul 10 '16 at 22:12
• Is it OK to have extra lines above the output? – John Dvorak Jul 11 '16 at 5:46
• "the height of the next column shouldn’t depend in any way on the height of the previous column" -- most languages' built-in random number generators are seeded. For this reason a function like Math.random() is directly calculable from its previous call if the parameters of the linear congruential generator are known, which means you'd have to modify most built-in random functionality in order to meet this criteria. I suggest that this is better-worded. – Patrick Roberts Jul 13 '16 at 7:00

Pyth, 13 bytes

And I outgolfed Jelly.

j_.tm*hO6\=33

Try it online!

j_.tm*hO6\=33
m      33  for 33 times:
O6          yield a random number in [0,1,2,3,4,5].
*   \=        repeat "=" that number of times.
.t           transpose, filling with whitespace
_             reverse
j              join by newlines.
• Why doesn't this work here? – Insane Jul 11 '16 at 20:03
• @Insane Pyth is quite outdated on TIO. – Dennis Jul 12 '16 at 0:55
• @Dennis But I love TIO :'( – Insane Jul 12 '16 at 0:59

Dyalog APL, 14 bytes

⊖⍉↑'='⍴¨⍨?33⍴6

Explanation

33⍴6 33 repetitions of 6

? random integer in range [1,n] for each of the 33 6s

'='⍴¨⍨ equality symbol repeated each of those number of times

convert list of lists to table of rows

transpose rows into columns, columns into rows

flip upside down

Example runs

Input is indented six spaces:

⊖⍉↑'='⍴¨⍨?33⍴6
=          ==        =      ==
= =    =   ==      ====     ==
= = = ===  ==  === ==== =  ===  =
= = ===== ==== === ==== = ====  =
=== ============== ==== ====== ==
=================================
⊖⍉↑'='⍴¨⍨?33⍴6
=  =  =    =    =
=      =  =  ==  == == =  =
=== == ==  =  === =======  =
==== == ==  ====== ==========   =
==== ============= ========== = =
=================================
⊖⍉↑'='⍴¨⍨?33⍴6
=    =   =  =
=   =    =   = == =
=      = =   =    ==  = ==== ===
= = =  = =   =    ==  = ==== ====
=====  = == ==  ============ ====
=================================

Jelly, 14 bytes

6x33X€”=ẋz⁶Ṛj⁷

Try it here.

• Uh oh, that can't be right. Jelly must by definition be shorter than APL. – Adám Jul 10 '16 at 19:18
• It's not very efficient, but 6ṗ33X works as well. – Dennis Jul 11 '16 at 0:44

JavaScript (ES6), 116 bytes

(a=Array(33).fill.map(_=>[,,,,,,].fill .fill('=',Math.random()*6)))[0].map((x,i)=>a.map(x=>x[i]).join).join

Check it out in the animated snippet below:

F = () => (a=Array(33).fill.map(_=>[,,,,,,].fill .fill('=',Math.random()*6)))[0].map((x,i)=>a.map(x=>x[i]).join).join

var interval;
G = () => output.innerHTML = F().split('\n').map((r, i) => <span id="row-${6-i}">${r}</span>).join('\n');
A = () => {
clearInterval(interval);
if (auto.checked) {
speed.disabled = false;
interval = setInterval(G, speed.value);
} else {
speed.disabled = true;
}
}
S = () => {
if (stylized.checked) {
} else {
output.classList.remove('stylized');
}
}

generate.onclick = G;
auto.onchange = speed.onchange = A;
stylized.onchange = S;

G();
A();
S();
#output {
background: #000;
color: #9fff8a;
overflow: hidden;
line-height: 1;
}

#output.stylized {
line-height: 0.25;
font-size: 2em;
margin: 0.5em 0 0 0;
}

.stylized #row-1 { color: #9fff8a; }
.stylized #row-2 { color: #c5ff8a; }
.stylized #row-3 { color: #e0ff8a; }
.stylized #row-4 { color: #ffe88a; }
.stylized #row-5 { color: #ffc28a; }
.stylized #row-6 { color: #ff8a8a; }
<button id="generate">Generate</button>
<label>Auto: <input id="auto" type="checkbox" checked/></label>
<label>Speed: <select id="speed">
<option value="25">25</option>
<option value="50">50</option>
<option value="100" selected>100</option>
<option value="200">200</option>
<option value="400">400</option>
<option value="600">600</option>
<option value="800">800</option>
<option value="1000">1000</option>
</select></label>
<label>Stylized: <input id="stylized" type="checkbox" checked/></label>
<pre id="output"></pre>

• Wow, that's really cool! – nicael Jul 11 '16 at 18:19

C, 87 bytes

f(x,y){for(y=6;y--;){srand(time(0));for(x=33;x--;)putchar("= "[rand()%6<y]);puts("");}}

Call as f();. This answer relies on the fact that six consecutive calls to time(0) return the same result (in seconds). This is virtually always true, but probably worth mentioning.

• You put x and y to avoid to declare them as int. Since there is no input, is this allowed? If yes, it is a nice idea! – aloisdg Jul 11 '16 at 0:54
• Just tried you code. You can run it with f(); Thats nice! I didnt know that C can do that. – aloisdg Jul 11 '16 at 0:59
• I really like you code. I port it to C# for a result of 117 bytes.I am not sure about posting it because it is literally your code. – aloisdg Jul 11 '16 at 10:34
• Feel free to post it, as long as you credit me. :) – Lynn Jul 11 '16 at 11:48

Cheddar, 68 65 bytes (non-competing)

->(1:33).map(->IO.sprintf("%6s","="*Math.rand(1,7))).turn().vfuse

O_O Cheddar is actually doing good! Uses sprintf and turn to do a bulk of the work. vfuse is vertical-fuse meaning it joins the array but vertically. This is very golfy but also rather fast. Version is prerelease v1.0.0-beta.10, which post-dates the challenge.

Explanation

->           // Anonymous function
(1:33)     // Range 1-33 inclusive
.map(->    // Loop through the above range
IO.sprintf("%6s",       // sprintf from C/C++
"="*Math.rand(1,7)    // Repeat = a random time from [1,7)
)
).turn().vfuse     // Turn it 90deg, and fuse it vertically

Some example runs:

05AB1E, 22 bytes

No auto joining, no automatic filling while transposing, osabie is doomed on this one. Code:

33F6ð×6L.R'=×ðñ})ø€J¶ý

Uses the CP-1252 encoding. Try it online!.

Python 2, 95 bytes

from random import*
x=map(randrange,[6]*33)
for y in range(6):print''.join('= '[z>y]for z in x)

Python 3, 115 bytes

Python never even had a chance...

from random import*
for k in zip(*[[' ']*(6-len(j))+j for j in[randint(1,6)*['=']for i in[0]*33]]):print(*k,sep='')

How it works

from random import*    Import everything in the random module
randint(1,6)*['=']     Create a list containing a random number in [1,6] of '='...
...for i in[0]*33      ...33 times...
[...]                  ...and store in a list X
for j in...            For all lists j in X...
[' ']*(6-len(j))+j     ...create a list containing j padded with the correct number of
spaces to give a height of 6...
[...]                  ...and store in a list Y

Y now contains a list for each output line, but transposed.

for k in zip(*...):...  For all lists k in the transpose of Y...
print(*k,sep='')        Print all elements in k with no separating space

Try it on Ideone

MATL, 201918 17 bytes

1 byte saved thanks to @Luis

C#, 200 117 bytes

()=>{var s="";int x,y=6;for(;y-->0;){var r=new Random();for(x=33;x-->0;)s+="= "[r.Next(6)<y?1:0];s+='\n';}return s;};

I move to @Lynn algorithm and save 83 bytes!

C# lambda without input and where output is a string. Try it online.

Code:

()=>{
var s="";int x,y=6;
for(;y-->0;){
var r=new Random();
for(x=33;x-->0;)
s+="= "[r.Next(6)<y?1:0];
s+='\n';
}return s;
};

Being a purely functional language, Haskell was doomed from the start. I did it anyway and it turns out, that the necessary overhead is actually not that large.

import System.Random
import Data.List
f r n|r>n=' '|0<1='='
s=do
g<-newStdGen
mapM_ putStrLn$transpose$map(\n->map(f$mod n 6)[0..5])(take 33(randoms g)::[Int]) Usage: s Explanation: import System.Random to be able to use newStdGen and randoms import Data.List to be able to use transpose f r n|r>n=' '|0<1='=' defines a function that prints a space if its first argument is larger than the second and a = otherwise. It is called with map (f m) [0..5] on a given number m and the list [0,1,2,3,4,5]. (See below) s=do g<-newStdGen Creates a new standard random number generator (take 33(randoms g)::[Int]) takes 33 random integers. map(\n->map(f$mod n 6)[0..5])

Calculates m = n % 6 and maps (f m) to the list [0,1,2,3,4,5], which results in one of "======", " =====", ..., " =". These lines are mapped to the list of the 33 random integers resulting in a table. (A table in Haskell is a list of lists)

transpose$switches columns and rows of the table mapM_ putStrLn$

prints every line in the table

CJam, 19 bytes

{5mrS*6'=e]}33*]zN*

Try it online!

Explanation

{       e# 33 times...
5mr   e#   Push a random number in [0 1 2 3 4 5].
S*    e#   Create a string with that many spaces.
6'=e] e#   Pad to length 6 with =.
}33*
]       e# Wrap all 33 strings in a list.
z       e# Transpose that list.
N*      e# Join the lines with linefeeds.

Mathematica, 78 bytes

",""]&

Anonymous function. Takes no input and returns a string as output. The Unicode character is U+F3C7, representing \[Transpose].

R, 102 bytes

m=rep(" ",33);for(i in 1:6){n=ifelse(m=="=",m,sample(c(" ","="),33,T,c(6-i,i)));m=n;cat(n,"\n",sep="")}

Explanation

m=rep(" ",33) init an empty vector for the upcoming loop

n=ifelse(m=="=",m,sample(c(" ","="),33,T,c(6-i,i))) If there's an = in the row above, then make sure the spot below also has an =; otherwise randomly pick. Random picks are weighted to make sure that a) the bottom row is all = and b) you get a neat shape to the whole thing.

cat(n,"\n",sep="") output that row to the console with a newline at the end and no spaces between elements!

PHP, 9592 89 bytes

<?php for(;++$i<34;)for($j=6,$e=' ';$j--;)$a[$j].=$e=rand(0,$j)?$e:'=';echo join(" ",$a);

Pretty happy with this one actually. For a while I had a version that in theory could generate any input but in practise would generate only solid blocks of = but this is both shorter and equally distributed!
Generates 7 undefined something notices whenever you run it but that's fine.

edit: well I just learned that join is an alias of implode, so that's nice.

J, 18 bytes

|.|:'='#~"0>:?33#6

Very simple stuff. With a bugfix from miles!

• This picks random integers in the range [0, 6] whereas the OP wanted [1, 6]. You could do >:?33#6 to get random integers in the range [1, 6]. Also, a rank 0 copy would be shorter using '='#~"0. This results in |.|:'='#~"0>:?33#6 but unfortunately, the 2 byte savings end up being mitigated by the inclusion of the increment operator. – miles Jul 11 '16 at 10:47
• @miles Whoa, thanks! Very cool. – Conor O'Brien Jul 11 '16 at 17:52

Perl, 64 bytes

@f=$_="="x33;s/=/rand>.4?$&:$"/ge,@f=($_.$/,@f)while@f<6;print@f Usage perl -e '@f=$_="="x33;s/=/rand>.3?$&:$"/ge,@f=($_.$/,@f)while@f<6;print@f'
= =           =  ==      =    =
= =         ===  ==      =    =
= = =         ===  ==      =    =
= = =   = =   ===  ===   = =    =
= = == =====  === ====   ===  = =
=================================

Perl, 68 bytes

Alternative version that relies on ANSI escape codes to move the cursor around, first dropping down 6 lines, then writing the original line (all the =s), moving up a line and printing the replaced string (s/=/rand>.4?$&:$"/ge) repeatedly until it makes no more substitutions. This can end up writing more than six lines, but it is eventually replaced with an empty line.

Note: \x1bs are actually the ASCII Esc character.

print"\x1bc\x1b[6B",$_="="x33;print"\x1b[1A\x1b[33D$_"while s/=/rand>.4?$&:$"/ge

Ruby, 1029984 83 bytes

s='
'*203;33.times{|j|a=(' '*rand(6)).ljust 6,'=';6.times{|i|s[i*34+j]=a[i]}};$><<s New and significantly shorter approach, where I start with string full of newlines. Older version... s='';204.times do|i|s+=->i{i%34==0?"\n":i>170?'=':s[i-34]=='='?'=':rand(2)==1?'=':' '}[i]end;puts s ...gave output with leading new line. My first submission in Ruby, using similar approach to @Barbarossa's one, but in single loop. What I liked in Ruby while working on this program: • .times loop • rand() which is pretty short • stacking ternary operators without parentheses I didn't like (mainly in terms of golfing): • mandatory$ for global variables not so mandatory in .times loop
• do and end keywords which can be replaced with single-line block
• 0 is not falsy

JavaScript, 179 bytes

Still working on golfing this a bit. I like this since it's straightforward.

n=>{a=Array(33).fill(0).map(n=>Math.floor(Math.random()*6)+1);r=Array(6).fill("");r.map((e,m)=>{a.map(n=>{if (n<=m+1){r[m]+="="}else r[m]+=" "})});return r.join('\n');}

Usage:

>q=n=>{a=Array(33).fill(0).map(n=>{return Math.floor(Math.random() * 6)+1});
r=Array(6).fill("");r.map((e,m)=>{a.map(n=>{if (n<=m+1){r[m]+="="}else r[m]+=" "})});return r.join('\n');}
>q();
= =  =   =    = =
=   =    = = =  =  == =  = =  =
= = =  = === ====  ====  = = ===
= = =  = === ==========  =======
= === ===========================
=================================
• You should be able to replace .map(n=>{return Math.floor(Math.random() * 6)+1}) with .map(n=>Math.floor(Math.random()*6)+1). Lambda are greats :) – aloisdg Jul 11 '16 at 10:39
• if (n<=m+1){r[m]+="="}else may be if(n<=m+1)r[m]+="=" else – aloisdg Jul 11 '16 at 10:41
• I had to make my own PRNG, and my Forth program isn't much longer. :P – mbomb007 Jul 12 '16 at 20:49

Forth, 190 bytes

I had to create my own PRNG, an xor-shift taken from here. The word f is the word you would call multiple times to see the output.

variable S utime S !
: L lshift xor ;
: R S @ dup 13 L dup 17 rshift xor dup 5 L dup S ! 6 mod ;
: f
33 0 DO R LOOP
1 -5 DO
33 0 DO
I PICK J + 0< 1+ IF ." =" ELSE SPACE THEN
LOOP CR
LOOP
; f

Try it online - Note that the system time is one of two values based on which server (or something) is running the code. Other than that, they don't change in the online IDE for some reason. So you'll only see two possible outputs. You can manually set the seed by changing utime to an integer.

Ungolfed

variable seed                   \ seed with time
utime seed !

: RNG                           \ xor-shift PRNG
seed @
dup 13 lshift xor
dup 17 rshift xor
dup 5 lshift xor
dup seed !
6 mod                           \ between 0 and 6, exclusive
;

: f 33 0 DO RNG LOOP            \ push 33 randoms
1 -5 DO                     \ for (J = -6; J <  0; J++)
33 0 DO                 \ for (I =  0; I < 33; I++)
I PICK J + 0< 1+ IF \ if  (stack[I] < J)
61 EMIT         \ print "="
ELSE
32 EMIT         \ print " "
THEN
LOOP
CR                      \ print "\n"
LOOP
; f

Ungolfed online

JavaScript, 165 Bytes

// function that fills a column with a specified number of = signs
m=l=>Array(6).fill.map((e,i)=>i<l?"=":" ");
// fill an array of 33 length with columns of random number of = signs
a=Array(33).fill.map(e=>m(Math.ceil(Math.random()*6)));
// transponse the rows and columns and print to console
a[0].map((c,i)=>a.map(r=>r[5-i])).map(r=>console.log(r.join))

The newlines are unnecessary but they make it easier to see what's going on. Not the most optimal solution, but it makes sense to me at least.