Illustrate music beats

24

3

You know—they look like this:

source

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.

nicael

Posted 2016-07-10T18:19:39.937

Reputation: 4 585

@Lynn Oh, originally it did specify, but I accidentally removed it from the post. – nicael – 2016-07-10T18:59:53.313

11(Nitpicking) That looks to me like a spectrogram at a given instant, rather than a representation of any beats – Luis Mendo – 2016-07-10T19:00:52.173

@Luis Oh, that could be. But I love music and this is my first association :)) – nicael – 2016-07-10T19:15:11.907

Is ================================= allowed as an output, or do we need to put newlines before it? – Leaky Nun – 2016-07-10T19:52:11.217

@Leaky Nice example, edited. – nicael – 2016-07-10T20:01:54.020

Plot twist: you need to output a fixed (maybe a number given as the input) number of total = signs. – user6245072 – 2016-07-10T20:30:16.887

2Are columns allowed to be separated by spaces? (i.e., bottom row would be = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =) – LegionMammal978 – 2016-07-10T22:12:27.137

2Is it OK to have extra lines above the output? – John Dvorak – 2016-07-11T05:46:16.623

@LegionMa Nope. – nicael – 2016-07-11T12:40:21.663

@Jan You could, not required though. – nicael – 2016-07-11T12:41:16.803

1"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 – 2016-07-13T07:00:13.863

@Patrick I mean, you shouldn't specifically implement the dependance. – nicael – 2016-07-13T08:25:01.990

Answers

12

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].
      h            add one.
     *   \=        repeat "=" that number of times.
  .t           transpose, filling with whitespace
 _             reverse
j              join by newlines.

Leaky Nun

Posted 2016-07-10T18:19:39.937

Reputation: 45 011

Why doesn't this work here?

– Insane – 2016-07-11T20:03:06.990

@Insane Pyth is quite outdated on TIO. – Dennis – 2016-07-12T00:55:35.057

@Dennis But I love TIO :'( – Insane – 2016-07-12T00:59:20.763

13

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
             =    =   =  =       
         =   =    =   = == =     
=      = =   =    ==  = ==== === 
= = =  = =   =    ==  = ==== ====
=====  = == ==  ============ ====
=================================

Adám

Posted 2016-07-10T18:19:39.937

Reputation: 37 779

9

Jelly, 14 bytes

6x33X€”=ẋz⁶Ṛj⁷

Try it here.

Lynn

Posted 2016-07-10T18:19:39.937

Reputation: 55 648

11Uh oh, that can't be right. Jelly must by definition be shorter than APL. – Adám – 2016-07-10T19:18:19.470

It's not very efficient, but 6ṗ33X works as well. – Dennis – 2016-07-11T00:44:39.673

9

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`
`

Snippet preview

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) {
    output.classList.add('stylized');
  } 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;
  padding: 1em;
  line-height: 1;
}

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

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

George Reith

Posted 2016-07-10T18:19:39.937

Reputation: 2 424

1Wow, that's really cool! – nicael – 2016-07-11T18:19:37.900

8

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.

Lynn

Posted 2016-07-10T18:19:39.937

Reputation: 55 648

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 moving to codidact.com – 2016-07-11T00:54:50.527

2Just tried you code. You can run it with f(); Thats nice! I didnt know that C can do that. – aloisdg moving to codidact.com – 2016-07-11T00:59:40.630

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 moving to codidact.com – 2016-07-11T10:34:47.683

1Feel free to post it, as long as you credit me. :) – Lynn – 2016-07-11T11:48:15.327

8

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:

enter image description here

Downgoat

Posted 2016-07-10T18:19:39.937

Reputation: 27 116

5

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!.

Adnan

Posted 2016-07-10T18:19:39.937

Reputation: 41 965

5

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)

Lynn

Posted 2016-07-10T18:19:39.937

Reputation: 55 648

4

MATL, 20 19 18 17 bytes

1 byte saved thanks to @Luis

33l2$r6*6:>!~61*c

Try it Online

Suever

Posted 2016-07-10T18:19:39.937

Reputation: 10 257

4

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

TheBikingViking

Posted 2016-07-10T18:19:39.937

Reputation: 3 674

3

SpecaBAS - 76 bytes

1 FOR x=1 TO 33: r=1+INT(RND*6): FOR y=7-r TO 6: ?AT y,x;"=": NEXT y: NEXT x

Prints an equal sign at the relevant screen coordinate.

enter image description here

with a spot of colour and a GOTO loop it becomes

enter image description here

Brian

Posted 2016-07-10T18:19:39.937

Reputation: 1 209

2

K4, 18 bytes

Essentially a port of the APL solution (unsurprisingly).

+-6$(33?1+!6)#'"="

Aaron Davies

Posted 2016-07-10T18:19:39.937

Reputation: 881

2

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;
};

aloisdg moving to codidact.com

Posted 2016-07-10T18:19:39.937

Reputation: 1 767

2

Haskell, 164 Bytes

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

AplusKminus

Posted 2016-07-10T18:19:39.937

Reputation: 171

1

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.

Martin Ender

Posted 2016-07-10T18:19:39.937

Reputation: 184 808

1

Mathematica, 78 bytes

StringRiffle[(PadLeft[Array["="&,#+1],6," "]&/@5~RandomInteger~33),"
",""]&

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

LegionMammal978

Posted 2016-07-10T18:19:39.937

Reputation: 15 731

1

J, 18 bytes

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

Very simple stuff. With a bugfix from miles!

Conor O'Brien

Posted 2016-07-10T18:19:39.937

Reputation: 36 228

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 – 2016-07-11T10:47:42.267

@miles Whoa, thanks! Very cool. – Conor O'Brien – 2016-07-11T17:52:24.383

1

PHP, 95 92 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.

user55641

Posted 2016-07-10T18:19:39.937

Reputation: 171

1

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!

Barbarossa

Posted 2016-07-10T18:19:39.937

Reputation: 21

1

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

Dom Hastings

Posted 2016-07-10T18:19:39.937

Reputation: 16 415

1

Ruby, 102 99 84 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

Leibrug

Posted 2016-07-10T18:19:39.937

Reputation: 121

0

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();
           = =  =   =    = =     
=   =    = = =  =  == =  = =  =  
= = =  = === ====  ====  = = === 
= = =  = === ==========  ======= 
= === ===========================
=================================

charredgrass

Posted 2016-07-10T18:19:39.937

Reputation: 935

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 moving to codidact.com – 2016-07-11T10:39:44.003

if (n<=m+1){r[m]+="="}else may be if(n<=m+1)r[m]+="=" else – aloisdg moving to codidact.com – 2016-07-11T10:41:26.683

I had to make my own PRNG, and my Forth program isn't much longer. :P – mbomb007 – 2016-07-12T20:49:11.060

0

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

mbomb007

Posted 2016-07-10T18:19:39.937

Reputation: 21 944

0

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.

Davis

Posted 2016-07-10T18:19:39.937

Reputation: 131