9
\$\begingroup\$

Because I forgot to celebrate Pi Day (14.3), let's celebrate with \$\pi\$, \$e\$ (Euler's number) and music!

Challenge

No, we don't have time to eat a pi-pizza, let's make a program.
What you need is \$500\$ digits of \$\pi\$, and \$10\$ digits of \$e\$.

The input is an integer \$n\$ between \$0\$ and \$499\$ inclusive.

Then you should loop through the first \$n\$ digits of \$\pi\$:

If the digit is:

  • \$0\$ then the note is C
  • \$1\$ then the note is D
  • \$2\$ then the note is E
  • \$3\$ then the note is F
  • \$4\$ then the note is G
  • \$5\$ then the note is A
  • \$6\$ then the note is B
  • \$7\$ then the note is C'
  • \$8\$ then the note is D'
  • \$9\$ then the note is E'

Next, for each digit in \$\pi\$, take a digit from \$e\$ based on this mapping:

  • If the digit from \$\pi\$ is \$0\$, take the \$1\$st digit from \$e\$
  • If the digit from \$\pi\$ is \$1\$, take the \$2\$st digit from \$e\$
  • If the digit from \$\pi\$ is \$2\$, take the \$3\$st digit from \$e\$
  • etc.

You need only \$10\$ digits of \$e\$, because the digits in \$\pi\$ are between \$0\$ and \$9\$.

Finally, take the note and the digit from \$e\$. Return a tuple (or equivalent) containing:

  • the note
  • the \$e\$ digit divided by \$4\$ (representing the beat)

Test cases

In:10
Out:
('D', 0.25)
('G', 2.0)
('D', 0.25)
('A', 0.25)
("E'", 1.0)
('E', 2.0)
('B', 2.0)
('A', 0.25)
('F', 0.5)
('A', 0.25)
In:5
Out:
('D', 0.25)
('G', 2.0)
('D', 0.25)
('A', 0.25)
("E'", 1.0)

Help

Here are \$500\$ digits of \$\pi\$:

3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912

And \$10\$ digits of \$e\$:
2.7182818284

Note that '3.' and '2.' don't count in the digits of \$\pi\$ and \$e\$, and that we are using \$0\$ indexing (so the \$0\$th digit of \$\pi\$ is \$1\$ etc.).

Rules

  • This is so the shortest answer wins.
  • Optional; After every tuple or list output, there can be a trailing newline.

As one week is over, here is an ungolfed code in Python 2:

Python 2, 526 bytes

def music_maker(n):
 i=p=1;x=3*100**n
 while x:x=x*i/-~i/4;i+=2;p+=x/i
 pi_number=str(p)[:-1] #First 3 lines calculates Calculate Pi
 euler='7182818284'
 del x,i,p #You don't need those Variables any more. They were ment for calculating
 for i in range(n):
  current_pi = pi_number[i] #Current Pi
  current_e = euler[int(current_pi)] #Current e
  number_to_note = {0:"C", 1:"D",2:"E",3:"F",4:"G",5:"A",6:"B",7:"C'",8:"D'",9:"E'"} #Dict number to note
  print((number_to_note[int(current_pi)], int(current_e)/4)) #Prints result

Try it online!

\$\endgroup\$
19
  • 1
    \$\begingroup\$ Here's a dict:{0:"C", 1:"D",2:"E",3:"F",4:"G",5:"A",6:"B",7:"C'",8:"D'",9:"E'"} \$\endgroup\$
    – math scat
    Jul 9, 2020 at 10:42
  • 1
    \$\begingroup\$ Great, it looks ok now, so I've upvoted and deleted my comment. :) \$\endgroup\$ Jul 9, 2020 at 10:49
  • 2
    \$\begingroup\$ Need clarification: you say that this is to use 0 based indexing, so an input of 0 would result in 1 note output, but your examples use 1 based indexing (input of 10 yields 10 results), so which is it? \$\endgroup\$
    – Xcali
    Jul 9, 2020 at 22:04
  • 2
    \$\begingroup\$ Will we be able to hear what it looks like? \$\endgroup\$
    – Kaddath
    Jul 10, 2020 at 8:02
  • 6
    \$\begingroup\$ @Tanmay for code-golf it's not ogligatory to declare a winner, as there are multiple languages that obviously cannot compete in length (while still pretty interesting to golf), but if you want to accept one, usually it's recommended to wait at least a week. But don't forget to upvote any number of answers you think deserve it! \$\endgroup\$
    – Kaddath
    Jul 10, 2020 at 9:24

8 Answers 8

10
\$\begingroup\$

JavaScript (Node.js),  150 ... 134  133 bytes

Saved 3 bytes thanks to @KevinCruijssen

Expects a BigInt as input and prints the music to STDOUT. This also works for \$n>500\$.

n=>{for(k=p=1n,x=3n*100n**n;x;p+=x/k)x=x*k++/k++/4n;for(;x<n;)console.log('CDEFGABCDE'[d=(p+'')[x++]]+" '"[d/7|0]+'7182818284'[d]/4)}

Try it online!

How?

Part 1: compute \$n\$ digits of \$\pi\$

This is based on the following formula:

$$\pi-3=\sum_{n=1}^{\infty}\frac{3}{4^n}\left(\prod_{k=1}^{n}\frac{2k-1}{2k}\right)\times\frac{1}{2n+1}$$

Instead of using floats -- whose precision is obviously far too limited -- we use a Big Integer \$x\$ initialized to \$3\$ times a large enough power of \$10\$ and process integer divisions until we have \$x=0\$.

For 500 digits, we could just use \$x=3\cdot10^{503}\$. We instead start with \$x=3\cdot100^n\$, which is more than enough to get \$n\$ correct digits and easier to golf.

for(                    // loop:
  k = p = 1n,           //   start with k = p = 1
  x = 3n * 100n ** n;   //   start with x = 3 * 100 ** n
  x;                    //   stop when x = 0
  p += x / k            //   add x / k to p after each iteration
)                       //
  x =                   //   update x to:
    x * k++ / k++ / 4n  //     x * k / (k + 1) / 4 (and increment k twice)

Part 2: convert to music notes

for(; x < n;)           // repeat as many times as requested:
  console.log(          //   print:
    'CDEFGABCDE'[       //     string of notes
      d = (p + '')[x++] //     d = x-th digit of pi, extracted from p
    ] +                 //
    " '"[d / 7 | 0] +   //     append a quote if d is greater than or equal to 7,
                        //     or a space otherwise
    '7182818284'[d]     //     get the d-th digit of e (using Math.E would be longer)
    / 4                 //     and divide it by 4 for the beat
  )                     //   end of console.log()
\$\endgroup\$
1
  • 1
    \$\begingroup\$ -3 bytes by removing k=0 and reusing x in the second part, since it's already 0 after the loop in the first part: 134 bytes. \$\endgroup\$ Jul 9, 2020 at 14:58
5
\$\begingroup\$

05AB1E, 33 30 bytes

LεAuS7£ÀÀD3£''««žsyè©èžt¦®è4/‚

Outputs as a list of pairs in the ["string-note", beat-decimal] format.

Try it online.

Explanation:

L                # Push a list in the range [1, (implicit) input]
 ε               # Map each integer to:
  Au             #  Push the uppercase alphabet
    S            #  Convert it to a list of characters
     7£          #  Only leave the first 7: ["A","B","C","D","E","F","G"]
       ÀÀ        #  Rotate it twice towards the left: ["C","D","E","F","G","A","B"]
         D       #  Duplicate it
          3£     #  Only leave the first 3 character of this copy: ["C","D","E"]
            ''«  #  Append a "'" to each: ["C'","D'","E'"]
               « #  Merge the two lists together:
                 #   ["C","D","E","F","G","A","B","C'","D'","E'"]
  žs             #  Push an infinite list of pi-digits: [3,1,4,1,5,...]
    yè           #  Index the current integer into it (0-based, so leading 3 is skipped)
      ©          #  Store it in variable `®` (without popping)
       è         #  Index this pi-digit into the notes string-list
  žt             #  Push an infinite list of e-digits: [2,7,1,8,2,...]
    ¦            #  Remove the leading 2
     ®           #  Push the pi-digit from variable `®`
      è          #  Index it into the infinite list of decimal e-digits
       4/        #  Divide it by 4
  ‚              #  Pair the pi-note and e-digit/4 together
                 # (after which the resulting list of pairs is output implicitly)
\$\endgroup\$
4
\$\begingroup\$

Wolfram Language (Mathematica), 97 bytes

Print[C[D,E,F,G,A,B,"C'","D'","E'"][[#]]|R[E,10,2+#][[1,-1]]/4]&/@#&@@R[Pi,10,#,-1]&
R=RealDigits

Try it online!

Prints notes as [key] | [duration], with one note per line.

Since Mathematica's number->string functions are so bulky (FromCharacterCode, anyone?), hardcoding the keys' names as symbols seems to be shorter.

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

Perl 5 -Mbignum=bpi, 86 84 bytes

say+(C..G,A..E)[$_],"'"x($_>6),$",((exp 1)=~/./g)[$_+3]/4for(substr bpi<>+1,2)=~/./g

Try it online!

How?

for               # loop over
  (substr         # a substring of
     bpi<>+1,     #   PI to the appropriate number of decimals
     2)           #   starting after the second character
  =~/./g          # split into characters

    say+              # output
      (C..G,A..E)[$_],  # the note letter
      "'"x($_>6),       # a ' if it is in the next octave higher
      $",               # a space
      ((exp 1)          # Euler's number
       =~/./g)           # split into characters
       [$_+3]            # skipping the first 3 (2.7)
       /4                # divided by 4 beats
\$\endgroup\$
3
\$\begingroup\$

Charcoal, 52 bytes

P×φψ¤≕Pi→→≔EKDN→Iιθ⎚Eθ⁺⁺⁺§…α⁷⁺²ι×'›ι⁶ ∕I§⪫74ײ1828ι⁴

Try it online! Link is to verbose version of code. Actually works up to n=998. Explanation:

P×φψ¤≕Pi

Charcoal apparently has a built-in for π, but unfortunately the only way I know how to use it is copied from the Charcoal answer to Bake a slice of Pi which involves using it as a flood fill. Here I just output 1,000 null characters which therefore gives me 998 decimals of π, well above the 499 required by the challenge.

→→≔EKDN→Iιθ

Now input the number of decimals required, read them from the canvas, and convert them to integers.

Clear the canvas ready for the actual output.

Eθ⁺⁺⁺

Map over the digits and concatenate...

§…α⁷⁺²ι

... the first 7 letters of the uppercase alphabet, cyclically indexed by 2 more than the digit...

×'›ι⁶

... an ' if the digit is greater than 6...

 

... a space...

∕I§⪫74ײ1828ι⁴

... and the appropriate digit divided by 4, taken from the string 7182818284, constructed by doubling the string 1828 and inserting it into the string 74.

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

Python 2, 173 164 162 156 150 149 143 141 bytes

def f(n):
 i=p=1;x=3*100**n
 while x:x=x*i/-~i/4;i+=2;p+=x/i
 while x<n:i=int(`p`[x]);print"CDEFGAB"[i%7]+"'"[i<8:],1907986849/9**i%9/4.;x+=1

Try it online.

Prints the pairs newline-delimited to STDOUT in the format string-note beat-decimal (space-delimited).

Port of @Arnauld's JavaScript answer, so make sure to upvote him!
-6 bytes thanks to @ovs, which opened up -6 more bytes by switching to Python 2
-1 byte thanks to @Arnauld
-2 bytes thanks to @Tanmay

\$\endgroup\$
8
  • 1
    \$\begingroup\$ You don't need the second colon in the slice without a step and 1907986849//9**d%9/4 is a little shorter than int('7182818284'[d])/4. \$\endgroup\$
    – ovs
    Jul 9, 2020 at 14:15
  • 1
    \$\begingroup\$ @ovs Thanks! Now that I don't use := as much anymore, it's also shorter in Python 2 with int(`p`[k]) and regular / instead of //. \$\endgroup\$ Jul 9, 2020 at 14:45
  • 1
    \$\begingroup\$ 159 bytes \$\endgroup\$
    – Noodle9
    Jul 9, 2020 at 17:02
  • 1
    \$\begingroup\$ @Tanmay Thanks for the -1 byte (and an additional -1 by removing the space between print"). :) But next time please leave a comment with the golfing suggestion instead of editing someone else's answer. \$\endgroup\$ Jul 9, 2020 at 18:45
  • 1
    \$\begingroup\$ Guess we were out of sync somehow - did it on my phone. :( \$\endgroup\$
    – Noodle9
    Jul 9, 2020 at 21:50
3
\$\begingroup\$

Vyxal, 29 bytes

ƛkAf7Ẏ2Ǔ:3Ẏ\'vJJn∆iin∆i›∆ė4/"

Try it Online! or Run both test cases!

Port of 05AB1E. If it can't output rationals instead of decimals, add øḋ before ". Then it will be as strings.

How?

ƛkAf7Ẏ2Ǔ:3Ẏ\'vJJn∆iin∆i›∆ė4/"
ƛ                              # For each item `n` in the (implicit) inclusive one range of the (implicit) input
 kA                            # Push the uppercase alphabet
   f                           # Convert to list of characters
    7Ẏ                         # Leave only the first seven letters: ["A","B","C","D","E","F","G"]
      2Ǔ                       # Rotate left twice: ["C","D","E","F","G","A","B"]
        :                      # Duplicate
         3Ẏ                    # Leave only the first three letters of the duplicate: ["C","D","E"]
           \'vJ                # Append a single quotation mark to each letter: ["C'","D'","E'"]
               J               # Join these two lists together: ["C","D","E","F","G","A","B","C'","D'","E'"]
                n∆i            # Get the `n`th (zero-indexed) digit of pi
                   i           # Index this into the list of notes
                    n∆i        # Get the `n`th pi digit again
                       ›       # Increment it
                        ∆ė     # Get the zero-indexed E digit from that
                          4/   # Divide by four
                            "  # Pair the pi-note and e-digit/4 together
\$\endgroup\$
1
\$\begingroup\$

perl -MMath::BigFloat -pl, 170 bytes

$n=$_;$p=new Math::BigFloat;$p->accuracy(500);$_=$p->bpi;s/..//;s!.!'('.substr(CDEFGABCDE,$&,1).("'"x($&>6)).', '.((substr 7182818284,$&,1)/4).")\n"!eg;/(.+\n){$n}/;$_=$&

Try it online!

How does this work?

$n = $_;

This gets the input (which is in $_ due to the -p switch; the -l switch removes the newline).

$p = new Math::BigFloat;
$p -> accuracy (500);
$_ = $p -> bpi;
s/..//;

This gets us the 500 required digits from \$\pi\$. First we create a Math::BigFloat object, give it an accuracy of 500 (so, 500 decimals behind the comma). We then query the object to get \$\pi\$, which we store in $_. And we then remove the first two characters, to set rid of the leading 3..

s !.!
  '(' .    substr (CDEFGABCDE, $&, 1) . ("'" x ($& > 6)) .
  ', ' . ((substr  7182818284, $&, 1) / 4) .
  ")\n"
  !eg

This does the majority of the work. We take each digit of \$\pi\$ and replace it with the result of the middle three lines of code above. During the replacement, the digit being replaced is in $&. We start with an opening paren, then we look up the note by using the current digit as in index into a string (substr (CDEFGABCDE, $&, 1). If the digit is greater than 6, we need to add a prime (("'" x ($& > 6))). We then add a comma. Then, to get the beat, we index into the digits of \$\epsilon\$, and divide by four (((substr 7182818284, $&, 1) / 4)). Finally, we add an closing paren and a newline.

/(.+\n){$n}/;
$_ = $&

This trims the resulting string to the desired length. We're grabbing n times a group of non-newline characters followed by a newline character, and store the result into $_, which gets printed due to the -p command line switch.

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