obviously this means all of the modules changed to accomodate. this is one of many steps to reduce the number of times we pass connections and servers and other such info around, when it's mostly unnecessary because modules have a reference to DrBotIRC
119 lines
4.5 KiB
Python
119 lines
4.5 KiB
Python
"""
|
|
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
|
|
import re
|
|
|
|
import MySQLdb as mdb
|
|
|
|
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
|
|
"""
|
|
|
|
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:
|
|
version = 1
|
|
cur = db.cursor(mdb.cursors.DictCursor)
|
|
cur.execute('''
|
|
CREATE TABLE pi_log (
|
|
id SERIAL,
|
|
count_inside INTEGER NOT NULL,
|
|
count_total INTEGER NOT NULL,
|
|
time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin
|
|
''')
|
|
cur.execute('''
|
|
CREATE VIEW pi_latest_pi AS
|
|
SELECT count_inside, count_total
|
|
FROM pi_log
|
|
ORDER BY id DESC
|
|
''')
|
|
db.commit()
|
|
self.db_register_module_version(self.__class__.__name__, version)
|
|
except mdb.Error as e:
|
|
db.rollback()
|
|
self.log.error("database error trying to create tables")
|
|
self.log.exception(e)
|
|
raise
|
|
finally: cur.close()
|
|
|
|
def do(self, connection, event, nick, userhost, what, admin_unlocked):
|
|
match = re.search('^!pi$', what)
|
|
if match:
|
|
db = self.get_db()
|
|
try:
|
|
cur = db.cursor(mdb.cursors.DictCursor)
|
|
cur.execute('SELECT * FROM pi_latest_pi')
|
|
datum = cur.fetchone()
|
|
|
|
if datum == None:
|
|
count_inside = 0
|
|
count = 0
|
|
else:
|
|
# load values
|
|
count_inside = datum['count_inside']
|
|
count = datum['count_total']
|
|
|
|
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
|
|
|
|
cur.execute('INSERT INTO pi_log (count_inside, count_total) VALUES (%s,%s)',
|
|
(count_inside, count))
|
|
db.commit()
|
|
except mdb.Error as e:
|
|
db.rollback()
|
|
self.log.error("database error doing pi stuff")
|
|
self.log.exception(e)
|
|
return self.irc.reply(event,
|
|
"database error while estimating pi: {0:s}".format(str(e)))
|
|
finally: cur.close()
|
|
|
|
return self.irc.reply(event,
|
|
"({0:.10f}, {1:.10f}) is {2}within the unit circle. "\
|
|
"pi is {5:.10f}. (i:{3:d} p:{4:d})".format(x, y,
|
|
"" if inside else "not ",
|
|
count_inside, count, pi))
|
|
|
|
# vi:tabstop=4:expandtab:autoindent
|
|
# kate: indent-mode python;indent-width 4;replace-tabs on;
|