Playing pool with Pi

I saw this topic on another forum and thought I’d try it with Codea. The subject is calculating the value of Pi by counting the number of collisions using 2 balls and a wall. What this program shows is a red ball moving towards a blue ball. I count the number of collisions that the blue ball has with the wall and the red ball. That count gives the value of Pi. Using M1 mass of 100 and M2 mass of 1, I can only get Pi to 1 decimal position. To get 2 positions, M1 has to be 1,000. 3 positions, M1 has to be 10,000, etc. The Codea Physics engine doesn’t work right if I use M1 mass with 1,000 or higher. That’s just too much of a mass difference between the 2 balls. This example for 1 digit is sufficient to show how this works. For more info, do a Google search on “Playing pool with Pi”.

displayMode(FULLSCREEN)

function setup()
    physics.continuous=true
    cnt=0
    pi=0
    nbr=2
    
    b1=physics.body(CIRCLE,20)
    b1.x=WIDTH
    b1.y=140
    b1.linearVelocity=vec2(-200,0)
    b1.friction=0
    b1.restitution=1
    b1.info="ball"
    b1.mass=10^nbr
    
    b2=physics.body(CIRCLE,20)
    b2.x=250
    b2.y=140  
    b2.friction=0
    b2.restitution=1
    b2.mass=1
    
    e1=physics.body(EDGE,vec2(0,120),vec2(WIDTH,120)) 
    e2=physics.body(EDGE,vec2(0,0),vec2(0,HEIGHT)) 
    e2.info="edge"
end

function draw()
    background(40, 40, 50)    
    noStroke()
    fill(255,0,0)
    ellipse(b1.x,b1.y,40)
    fill(0,0,255)
    ellipse(b2.x,b2.y,40)
    fill(255)

    strokeWidth(2)
    stroke(255)
    line(0,120,WIDTH,120)
    line(0,0,0,HEIGHT)
    text("Calculate pi using physics collisions.",WIDTH/2,HEIGHT-100)
    text('Do a Google search for "Playing pool with pi".',WIDTH/2,HEIGHT-140)
    text("Count = number of blue ball collisions with the wall or red ball.",WIDTH/2,HEIGHT-200)
    text("M1 = mass of red ball     100",WIDTH/2,HEIGHT-250)
    text("M2 = mass of blue ball    1",WIDTH/2,HEIGHT-280)
    text("Count = "..cnt,WIDTH/2,HEIGHT-350)
    text("pi = Count/sqrt(M1)",WIDTH/2,HEIGHT-390)
    text("pi = "..pi,WIDTH/2,HEIGHT-420)
end

function collide(c)
    if c.state==BEGAN then
        if c.bodyA.info=="edge" or c.bodyA.info=="ball" then
            cnt=cnt+1
            pi=cnt/10
        end
    end
end

Hah I just watched a video on this. So cool to see that it actually works in code.

Though I notice if I increase the order of magnitude to 3 it does not simulate correctly

@Simeon I guess the Codea Physics engine can’t handle a mass that high (1,000) with collisions. The speed of the blue ball is just to great.

Yeah I think it breaks it :slight_smile:

This is like the most inefficient way to compute Pi, but really fun that it works

@Simeon Here’s a mathematical version of the graphics. This code was originally written in TiBasic by redsmith in another forum that I visit. I tried the original code on my TI 84 Plus SE and it worked, but was extreamly slow even for a few digits. I rewrote the code to run on the iPad. Use the slider to select the number of digits then press calc. It takes about 20 seconds to calculate 8 digits on my iPad Air. Each additional digit results in an increase of 10x. So 9 digits will take around 200 seconds.

function setup()
    s=require("socket")
    parameter.integer("digits",1,14,1,function() C=0 en,st=0,0 end)
    parameter.action("calc",calc)
    calc()
end

function draw()
    background(0)
    text("Pi "..C/(10^(digits-1)),WIDTH/2,HEIGHT/2)
    text("Calc time  "..en-st,WIDTH/2,HEIGHT/2-100)
end

function calc()
    en,st=0,0
    output.clear()
    print("start")
    Z,C=0,0
    M1=1
    M2=100^(digits-1)
    V1,V2=0,-1
    cnt=0
    st=s.gettime()
    repeat
        cnt=cnt+1
        U=V1
        Y=V2       
        V1=(M1-M2)/(M1+M2)*U+2*M2/(M1+M2)*Y
        V2=2*M1/(M1+M2)*U+(M2-M1)/(M1+M2)*Y        
        if (V2-V1)<0 or V1<0 then
            C=C+1
        else
            Z=1
        end        
        V1=V1*-1        
        if (V2-V1)<0 or V1<0 then
            C=C+1
        else
            C=C+1
            Z=1
        end   
    until Z==1
    print("done")
    en=s.gettime()
end