- I remember January 2019. Do you remember January 2019? Oh, it was a simpler time. Something happened that month. A video came out on the Internet. This video was called, The
most unexpected answer, I'm looking it up, The
most unexpected answer to a counting puzzle. And this video was from one of
my favorite YouTube channels, 3Blue1Brown, where I learn a
lot of wonderful math stuff and I get a lot of inspiration
for stuff that I do. And what this video was about is it was about these two blocks. There was a small block, and a big block. And these blocks, they moved around, they bounced into each
other, they clacked. It was like, the most
beautiful clacking sound I've ever heard. And then they bounced into a wall, and after awhile, just
count up how many times they're bouncing into each other, and this weird thing
happens, this number appears, this number which is
the digits of pi appears based on how many times they're
clacking into each other, which is crazy. Now, if you want to know why that occurs, you should go and watch the
3Blue1Brown video series, and even towards the end
of that three part series, 3Blue1Brown makes a connection to optics, and there's so much beauty
and wonder in there. This is not a new concept, you can find some other resources. There's a wonderful paper from 2003, I'm looking up the title of it now, by G. Galperin called
Playing Pool With Pi, The Number Pi from a
Billiard Point of View. There's a Numberphile video, and I'll also link to some other resources where you can read about
this particular phenomenon and why it occurs in
this video subscription. But that's what not I do on this channel. What I do on this channel is I code stuff. So I am going to attempt
in this coding challenge to make my own version of 3Blue1Brown's collision clacking magic wonderful thing, and we're going to see like,
can I really make this happen, just in the browser and JavaScript, and can I actually write some
code that's accurate enough to get the digits of pi? And where does this all
break down, and what happens? So, let's code. (whistle blows) Now, to celebrate Pi Day, I'm going to do something
a little bit different. I'm going to just start with a
little bit of boilerplate code. I kind of use the same stuff
in so many of my examples, maybe I can save you five minutes here of retyping this part out. So what I'm starting
with is just a very basic object-oriented system. I have a class called Block, and each Block has an x and y, that's where it is in the canvas, and it has a width, it's a square, so the width and the height are the same. And then when I want to draw
it, I just draw it as an image, and I've loaded one of my
coding train characters. The square character
from the coding train. I also have in here a
little clack sound loaded that I may or may not use, and then, I have created just two blocks, block1 appears at 100 with a size of 20, block2 appears at 200 with a size of 150, and then I am showing both those blocks. Alright, so what do I need to do? What I want to first do is
give these blocks a velocity. So let me go into the Block
class and add a velocity, I'm going to call it v. And then I am also going to
write a function called update where I will say this.x += v. So the idea here is it has a velocity, and x changes by that velocity. Then, I'll go back to the sketch, and let me give them a velocity, like the block1 is going
to have a velocity of zero, and block2 will have a
velocity of negative one, and then I should be
able to say also here, I can just call update for both of them. Update, update. V is not defined, did I
really forget the this dot, already, so already in this challenge? I think that's what I did,
I totally forgot this dot. Oh, this dot this dot. So now what I need to do
is I need to figure out, how do I check if the two blocks have knocked into each other? Okay, the way that I would do that, let's write a function,
I like to do everything in the class when possible. I'm going to write a
function called collide, and I'm checking if I'm
colliding with another block, call it other. So I'm checking if this block is colliding with some
other arbitrary block. So how do I know? If this is block1 with an x and a width, and this is block2, with an x and a width, I know that they are not intersecting if the left side of block2 is greater than the right side of block1, or if it was on the other side, right? If the left side of block1 was greater than the right side of block2. Otherwise, they must be
intersecting each other. And I know this is a
really simple situation, I don't need to check y's and heights, because they're only moving along this one-dimensional horizontal space. By the way, the math is going
to be a key concept here, and where I'm getting to that, if you know, you're
like, why not the math? Talk about the math! So now I can say, I can look
and basically say, like, if this.x + w, that's the right-hand side, is greater than other.x, other.x, right? Oh no, is less than, right? Or, if this.x is greater than the other.x + other.w, and this has to be a this dot, alright? So now, I'm going to say, println, oh no, print, not collide, not collide, otherwise, print collide. Let's see if I got this right. So it's moving, it's moving, oh, I got to call this
function, that would be nice. So I'm going to say block1, 1.collide block2. So I'm adding that in, and it's moving, not collide, not collide,
not collide, not collide, not collide, not collide,
it's going to collide. It's colliding, it's
colliding, it's colliding! Eventually, it's going
to get to the other side, go to the other side,
get to the other side, not colliding anymore. Okay, my algorithm was correct. So, really if I want that, I want that to just return true or false. So what I'm going to do is, I'm actually going to say, I'm just going to, I could write return, write return false here, but
another way I could do this is just say return not,
not this expression. This is a test to see if those two blocks are colliding with each other. Oof, alright. If block1 collides with block2, now what I want to say is block1.bounce block2. Alright, I want them to
bounce off of each other. So certainly at some point
we're going to have to deal with the fact that there's a wall here. But right now I'm just
looking at these two, and what I want to do
is I want to calculate the new velocities from
perfectly elastic collision. So this has a velocity, this
presumably also has a velocity, maybe it's moving that
way, maybe it's that way, maybe it's at rest. And, in an elastic collision,
there's no friction, there's nothing else
here in this environment. They're not like squishy things, no momentum, no energy, nothing is lost. So I need the formula
for an elastic collision. Luckily, I have that open right over here, and then you can see this is a formula that's following both the
conversation of momentum and the conservation of kinetic energy. So with both of these
formulas from physics we can then get the new velocity, right? U here is the old velocity,
and v is the new velocity. So the new velocity is a function of, the both object's mass, and
their previous velocity. Let's first add the idea of mass. So I'm going to go in here, and I'm going to add the idea of mass. And first I'm just going to
say, hey, the mass is one, so let's not worry about mass right now. By the way, what happens
if the mass is one? Think about this. If they're equal mass. If they're both equal mass, and this one is stationary,
and this one's moving, and they clack, right? All of the momentum and
energy is transferred, this one stops, this one moves. But that's not what's going to happen when the masses of each are different, so that's when it's going to
get really interesting, okay. So now we want a function called bounce, and I'm also going to say other. And it would be really
nice if I could just have that formula right over
there for me to refer to. Alright, so I took a
screenshot of the formula, so I've got it over there to refer to, and I just need to implement it here in this bounce function. So, one is this, two is other. So I'm writing it, I'm
not referring to my blocks as block1 and block2, I'm referring it to within
the object as this and other. So what I want to do is say this.v, but I don't want to start messing with v, because the old value of
v is part of the formula. So let's do this, const.v. Actually, you know what? Let's do, let's do, sorry, let newV = this.m-other.m, divided by what? Let's make a variable called sum of M, which is this.m + other.m. So this is divided by sum of M, and then, times this.v, right? So that's this side, and then, I mean, I could do this in one line, but I'm running out of space here. So then += 2 * other.m, divided by sumM * other.v. So I think what might make sense here is the thing is I don't want to update this object's velocity. I guess I could do both of them. I'll just do both of
them in this function. I was thinking I could return it, and then 'cause it's the
same formula both ways, I'd rather not duplicate my code. Let's try it this way. I'm going to return newV. You can see how this is
the same formula twice, it's just written in reverse order for v2, but if I change the two there, and change all the twos to
ones, we'll get the same thing. So I should be able to say,
if I go back into sketch.js, and I say, I'm going to say
v1 = block1.bounce block2. I'm going to say v2 = block2.bounce b1, block, block1. And then I should say, I'm going
to update their velocities. This I don't know if I
love, but this will work. So let's see what we got here. C'mon, clickety clack,
go, bounce that thing! Look at that, they're the same mass. So, by the way, let's, it's like, moving, it's like a funeral dirge over here, the way that thing's moving. Let's give it a bit of a
faster velocity to start. And we can see, boom, that's
a perfect elastically, now, it doesn't look very realistic, because really what we're seeing here, is like, should look like this, right? That's what we want. If both of those objects
have the same exact mass, one's going to transfer
all of its energy momentum to the other one. Now what if they have different mass? So let's give this one a size of 20, and this one a size of 200, and actually, I'm also going to give them each individual masses. So this will have a mass of one, and this one's going
to have a mass of 100. So not perfect, and some
weird stuff is happening, because I'm introducing
another argument here. So now let's see what happens. Oh, there we go, that's what we want! Look at this, right? Now the formula's working
with different masses. Alright, we're doing well,
oh, we need a wall, right? We need for the little
block to hit the edge. So the wall is another
thing that doesn't exist in the real world. We're looking at a
perfectly elastic collision with a immovable, fixed static wall. In other words, a wall,
a block of infinite mass. So we're going to give this
wall as having infinite mass, but honestly, the easiest
way to do this is just, if it hits the wall, just
negate, reverse its velocity. That will simulate a
perfectly elastic collision with an object of infinite mass. So I'm going to write a
function like hitWall. If this.x is less than
zero, then this.v *= -1. And then I only need to, in this case, I only ever need to check block1. So now I'm going to check block1.hitWall, and let's go here, boom,
boom boom boom boom. Amazingly, that kind of
sort of did something. Now, are we getting the right numbers? This is the question. And also, I kind of
want to hear that clack. Don't you want to hear that clack? So let's add the clack. Oh, I just realized,
this way that I did that, I really should have this
also be if block hitWall, then do something like, block1, let's let these be
separate functions, reverse, because, I also, I'm going
to need to do counting, there's a bunch of things that
are going to need to happen so it's good for me to
actually do it this way. Return, I'm going to say reverse, and then, okay, so this looks right. Let me make sure this is the same thing. Whoops, ah, I hit refresh, sorry. Da-da-da-da-da-da-da! Alright, so that did something. Now, let's add the clack. I mean, we're really
here just for the clack. The clack in the 3Blue1Brown video is the most beautiful clack ever. So I think if I said clack.play,
let's see what happens. (block clacks)
Ooh! Oh, that's kind of good! I need to clack when it
hits the wall though, too. (block clacks) Oh, the clacking, oh! It's a little weird how I lack
the clacking so much, is it? I don't know, it's very satisfying. Alright, so now let's count,
I mean, in theory, we're done! (bell rings)
I have a feeling we're going to run into some big problems. But let's say, int. So I'm going to start
with a count of zero. I am going to create a dom
element, I'll call it countDiv, because I'm going to make
a countDiv = createDiv, with the count in it. Ah, ah, ah. And then, I am going to say, count, countDiv.html count, and we will increase the count every time something collides. Whoops, line six error. Oh no, int, what am I doing, int? Int, oh, I feel like I'm
in Processing, it's a lot. Let's make them the same mass. Oh, and I got to make this bigger. Yes, okay, and then,
let's number format this. So, okay.
(block clacks) Hey, that's kind of like pi, three! Now, I'm going to make,
okay, so here's the thing. The magic number here is 100. So, if the mass of one
of the objects is one, the mass of block1 is one, the mass of block2 should
be the mass of block1 times 100 to the power of something. So the one here, this doesn't matter, 'cause this is just one. The ratio, so I could do 100
to the first power, right? 100 to the zero power,
which would be their equal, 100 to one, which would be one. 100 to the second power,
which would make this 10,000, right, to the third power? You see where we're going here. So what I want to do is, that's how I'm going
to calculate the mass. So, I guess what I want to say is, if the digits are zero, then is then two, I'm going
to say const m2 equals power. 100, to the number of digits. (block clacks) So that's one digit. And so, and now, that's
zero digits really, because, I'm confused when I'm
talking about digits, right? What I mean by zero is the
number of digits after the dot. Pi is 3.1, okay? So, now let's have one
digit after the dot. (block clacks) 3.1, that's crazy! Alright, here we go, two digits. (block clacks) Uh. Wait, hold on a second. Actually, the way that this
would make the most sense is for, if I want to get two digits, I should be saying 100
to the power of one, which is digits minus one, and then this makes sense down here. This is my digits plus
one, and there we go, this is two digits, I
should get the number 31, okay, that's good. And then if I change this to one digit, I get the number three. And by the way, when do I
decide when to stop counting? So at a certain point, the second block, or I know which block is the first, which block is the second, is going to just go off
and running forever, and they're not going to have
another chance to ever collide. So I'm just doing that visually right now. But we could actually
put something in here to determine when it's finished. But you could see here, now even though they're both moving in
the direction that way, but the second, the larger
block is moving faster, so they're never going to collide again, and that's something I could create a conditional to test for. But, let's talk about
the real problem here. The real problem is Euler integration. The real problem is, the phony
baloney physics simulation that I'm doing here. I am taking a giant step in time forward each frame of animation. And so the block is like, moving, then it's covering, it's colliding, again, everything is wildly inaccurate. So there are a variety of techniques of making a simulation more accurate. This diagram over here is
illustrating this concept. So if the blue line is like the real thing that would happen in the real
world with continuous time, if I'm just making guesses every so often, with the red line, with
the Euler integration, just adding the velocity
with large time steps, you could see how the
thing gets out of place. And this, if you were
programming a simulation to try to get a rocket to land on some, moon, planet thing, you're
going to have a problem with Euler integration. So there are a variety of techniques that are different types
of integration techniques for physics engines, and then of course, 3Blue1Brown talks about
other ways to calculate the number of collisions that would happen based on thinking about the
space in a different way. But what I'm going to do here is just see, what if I just make
those time steps smaller? So in other words, if I
recreate that diagram like this, and this is, you know,
with large time steps, well, if I could get smaller time steps, I could stay closer to
what it really would be. So a way of doing that
might be the following: I am going to create a variable, I'm going to call it a timeSteps. And I'm going to put the digits at one, just so we know it's always going to work, and I'm going to say the
timeSteps, I'm going to just try, let's add 10 extra timeSteps. We can make this a constant. So there's always going to
be, every time through draw, I want to do this 10 times. So I'm going to say, for let i = 0, i less than the number of timeSteps, i++. And I'm just going to do
this, all of this 10 times. All of this, by that I mean, check the collisions, bounce
the blocks, play the sound. And let's comment out
the sound for a second. We'll have to think of a different
way of dealing with that. Update the blocks, I'm going
to show once they're drawn. So if I'm doing that 10 times, the other thing I can do here is I can divide the velocity
that I want to start with with the number of timeSteps. So it's actually, it's as
if I'm doing the same thing, but with a tinier, tinier velocity, and just do it multiple
times through draw, so our animation happens faster. Let's see if this allows us to do. Let's just check to make
sure this is still working. One, two, three, oh, I miss the clack. I really miss the clacking. Let's try two digits. One, two, three, four,
five, da, da, da, 31, alright, that's pretty good. Now let's try three digits. And let's see, we should get 314! C'mon, ah, ah, go back! Hit the wall again, hit the wall again, clack, 314, woo! Let's add the clack back in. What happens if I add the sound back in? (block clacks) Hah, that was tolerable. Alright, 314, okay. Let's try four digits. (block clacks) Uh oh, goodbye! So that didn't work, what
if I we have 100 timeSteps? (block clacks) Okay, okay, that was, hey, it worked out! Alright, we got to deal with the sound. Alright, so I think, basically, what we should do with the
sound is I'm just going to say, let clackSound, I'm just going to assume it's not clacking, and
then if it clacks once, if it hits anything, I will say clackSound = true. Like, only if it collides,
either with the wall, or the other block. And then, I'm guaranteeing
now that I can only, I will only play the sound
once every time through draw. So this should really help things. So let's try this now, 100
timeSteps, four digits. (block clacks) 3.141, we're doing really well here! Okay, now, five digits? How about 1,000 timeSteps? (block clacks) Looks pretty good! Six digits, 10,000 time steps? (block clacks) That's pi, right, oh, clack! Oh, 3.14159! Alright, save, I'm saving! Seven digits, 100,000? (block clacks) What, that seriously worked? That's pi, right? I got seven digits just
through this method? I really didn't think I
was going to get that high. Alright, let's try eight. Let's try, like, 500,000. (block clacks) What, is that, is there a six there in pi? I mean, could I really get one million? I'm surprised that it actually, like, will go to one million. Nine, but I don't think that
it can handle 10 million. 10 million timeSteps
each time through draw? Can I get away with, like, 5 million? (block clacks) What? 1.4, what's pi, 14159265? That's right, that's pi! Can I really do 10 million timeSteps? (block clacks)
I didn't think JavaScript, oh yeah, the other thing I should do here, is I should constrain
where it's being drawn. You can hear the frame rate
is getting really, really low, so I'm just going to give these
a variable called x constraint. I want to say block1 can't be
drawn any further than zero, and block2, if this size is 20, can't be drawn any further than 20, and where I'm drawing it, let me say constant x equals constrain, this.x between this.xConstraint, and I don't know, the width
of the window should be fine. And then I'm going to
draw it at xConstraint. This will just visually, I think, make it look more correct. Oh, when an x constraint is not defined, 'cause I probably forgot the this dot. (laughs) Yes, I forgot the this dot. Oh, oops, no, no, I want to
draw at the x that's constraint, I don't know what I'm doing here, put this here, and now let's watch. (block clacks)
It's counting. A lot of collisions. Alright, can we, can we get to 10 digits? Let's try, like 500 bazillion. It's just running really slow. There's too many timeSteps. But I think we probably
will get the right number. (cheerful mamba music) ♪ It's the Pi Song ♪ ♪ We're counting the
collisions on the Pi Song ♪ ♪ We're counting the
collisions on the Pi Song ♪ ♪ Pi Song, Pi Song, Pi Song ♪ (cheerful mamba music) I don't have the digits of pi memorized. Oh, hold on, ah!
(block clacks) Ah, we got 10 digits everybody, whoohoo! Only 500 million, no,
50 million timeSteps, I had to look at this very close up. 50 million timeSteps per time per draw, I mean, why not, right? Oh, let's go to, this goes
to 11, we have to go to 11. Let's just add another
zero, because why not. Loading, loading, okay. Alright, so this, I might
need to speed this up, but I'll at least play you a little song. (peaceful ukulele music) ♪ 3.14159 ♪ ♪ 2653589 ♪ ♪ 793238462 ♪ ♪ 2643 ♪ ♪ 832 ♪ ♪ 795 ♪ ♪ 884 ♪ ♪ 1971 ♪ ♪ 939 ♪ ♪ 375105 ♪ ♪ 1, woops, 8209 ♪ ♪ 7494 ♪ ♪ 45923 ♪ (block clacks)
Ah, whoa! Oh, yes, oh, it's moving, it's moving! Okay, three, one, four, one, five, nine, two, six, five, three. Okay, it's got to hit one more time. Go, catch up little guy! Catch up little square, little one! You can do it, give me a clack! You can do it, you can
do it, you can do it! Ah, yes! 31415926535, that's 11 digits of pi, in JavaScript, p5, in the p5 Web Editor, just by elastic collisions of two squares! Woo, what a coding challenge. (whistle blows)
Alright, thank you for watching this coding challenge. This actually did happen
during a live stream, every once in awhile I do live streams for YouTube members and patrons, and I just happened to be
doing this during one of those, but this was so sort of fun and weird that I will include a link
to that unlisted live stream if you want to take a look and see the long version of all of the time spent actually doing this coding challenge, and waiting and waiting and waiting. I also have made a
Processing version of this. I've made some other attempts, some of them rather comical. For example, I tried to say, could box 2D actually do a good job of figuring out the elastic
collisions more accurately? As you can see, that did not work. I also tried using big decimal. Now, in JavaScript, I'm
using floating point numbers, and a floating point
number just has 32 bits of memory to store, it's
really just about seven digits, I think, you could, in Processing, I could use a double,
which has 64 bits of memory to store the decimal number. But there are lots of implementations, BigDecimal being one in
Java for storing huge, huge, decimal numbers with
really high precision, and I believe there are some
JavaScript analogs to that. So, I will include links
to all of that stuff in the code that goes along with this. If you can come up with a
creative way of visualizing this, of optimizing it to make it run, you should definitely check
out 3Blue1Brown's video. I have a version where I
implemented the optics method, but I had to load the number pi in order to then calculate. So this is a question I'm
asking you, the audience. Is there a way to do, to count
the number of collisions, either without tiny tiny
timeSteps that take forever, or by having access to the
number pi in the first place? I would love to know your
answer or thoughts on that. Go to thecodingtrain.com. Link in the description
to this challenge page, and you can submit your
own version of it there. Thanks for watching, and I'll see you, uh, see you before next
year on Pi Day, hopefully. I mean, there's like
Tau Day, it's coming up! June is, Summer's right around the corner! June is bustin' out all over! Goodbye, see you later!
(whistle blows) (upbeat music) (peaceful ukulele music) ♪ 3.1415 ♪ ♪ 926535 ♪ ♪ 89793238 ♪ ♪ 46, it's Pi Day, Pi Day ♪ ♪ Got to calculate from Pi Day ♪ ♪ Everyone's looking
forward to the digits ♪ ♪ Digits, it's Pi Day, Pi Day ♪ ♪ Got to calculate on Pi Day ♪ ♪ Everyone's looking
forward to the digits ♪ ♪ The digits ♪ ♪ Partying, partying, yeah ♪ ♪ Partying, party, yeah ♪ ♪ Fun, fun, fun, fun, Pi Day ♪ (upbeat music)