2010-10-18 22:48:51 -05:00
"""
Pi - calculate pi over time via the monte carlo method . idea borrowed from #linode
Copyright ( C ) 2010 Brian S . Stephan
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : / / www . gnu . org / licenses / > .
"""
import math
import random
2010-10-27 18:02:26 -05:00
import sqlite3
2010-10-18 22:48:51 -05:00
from extlib import irclib
from Module import Module
class Pi ( Module ) :
"""
Use the Monte Carlo method to approximate pi . Each time this method is called ,
it calculates a random point inside a square on the xy plane . If that point also
falls within a circle bound within that square , it is added to the count of points
inside . Over time , 4 * count_inside / count approaches pi .
Idea from #linode on OFTC. Code from http://www.eveandersson.com/pi/monte-carlo-circle
"""
2010-10-27 18:02:26 -05:00
def db_init ( self ) :
"""
Initialize database tables .
"""
# init the database if pi table doesn't exist
version = self . db_module_registered ( self . __class__ . __name__ )
if version == None :
# create tables
db = self . get_db ( )
try :
db . execute ( '''
CREATE TABLE pi_log (
id INTEGER PRIMARY KEY AUTOINCREMENT ,
count_inside INTEGER NOT NULL ,
count_total INTEGER NOT NULL ,
time TEXT DEFAULT CURRENT_TIMESTAMP
)
''' )
db . execute ( '''
CREATE VIEW pi_latest_pi AS
SELECT count_inside , count_total
FROM pi_log
WHERE id = last_insert_rowid ( )
''' )
db . execute ( ' INSERT INTO drbotzo_modules VALUES (?,?) ' , ( self . __class__ . __name__ , 1 ) )
db . commit ( )
except sqlite3 . Error as e :
db . rollback ( )
print ( " sqlite error: " + str ( e ) )
raise
2010-10-18 22:48:51 -05:00
def do ( self , connection , event , nick , userhost , replypath , what , admin_unlocked ) :
if what == " pi " :
2010-10-27 18:02:26 -05:00
db = self . get_db ( )
2010-10-18 22:48:51 -05:00
try :
2010-10-27 18:02:26 -05:00
cur = db . cursor ( )
pi_data = cur . execute ( ' SELECT * FROM pi_latest_pi ' )
datum = pi_data . fetchone ( )
2010-10-18 22:48:51 -05:00
2010-10-27 18:02:26 -05:00
if datum == None :
count_inside = 0
count = 0
else :
# load values
count_inside = datum [ ' count_inside ' ]
count = datum [ ' count_total ' ]
2010-10-18 22:48:51 -05:00
x = random . random ( )
y = random . random ( )
inside = False
d = math . hypot ( x , y )
if d < 1 :
inside = True
count_inside + = 1
count + = 1
pi = 4.0 * count_inside / count
2010-10-27 18:02:26 -05:00
cur . execute ( ' INSERT INTO pi_log (count_inside, count_total) VALUES (?,?) ' , ( count_inside , count ) )
db . commit ( )
except sqlite3 . Error as e :
db . rollback ( )
return self . reply ( connection , replypath , " sqlite error: " + str ( e ) )
2010-10-18 22:48:51 -05:00
2010-10-27 18:02:26 -05:00
return self . reply ( connection , replypath , " ( {0:.10f} , {1:.10f} ) is {2} within the circle. pi is {5:.10f} ( {3:d} / {4:d} ). " . format ( x , y , " " if inside else " not " , count_inside , count , pi ) ) ;
2010-10-18 22:48:51 -05:00
# vi:tabstop=4:expandtab:autoindent
# kate: indent-mode python;indent-width 4;replace-tabs on;