pi: add an app to simulate pi via monte carlo

This commit is contained in:
Brian S. Stephan 2015-05-21 21:41:42 -05:00
parent e647fc9b4d
commit 7046b53f20
7 changed files with 142 additions and 0 deletions

View File

@ -39,6 +39,7 @@ INSTALLED_APPS = (
'ircbot',
'karma',
'markov',
'pi',
'races',
'seen',
)

0
dr_botzo/pi/__init__.py Normal file
View File

8
dr_botzo/pi/admin.py Normal file
View File

@ -0,0 +1,8 @@
"""Manage pi models in the admin interface."""
from django.contrib import admin
from pi.models import PiLog
admin.site.register(PiLog)

42
dr_botzo/pi/ircplugin.py Normal file
View File

@ -0,0 +1,42 @@
# coding: utf-8
from __future__ import unicode_literals
import logging
from ircbot.lib import Plugin
from pi.models import PiLog
log = logging.getLogger('pi.ircplugin')
class Pi(Plugin):
"""Use the Monte Carlo method to simulate pi."""
def start(self):
"""Set up the handlers."""
self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!pi$',
self.handle_pi, -20)
super(Pi, self).start()
def stop(self):
"""Tear down handlers."""
self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_pi)
super(Pi, self).stop()
def handle_pi(self, connection, event, match):
"""Handle the pi command by generating another value and presenting it."""
newest, x, y, hit = PiLog.objects.simulate()
msg = ("({0:.10f}, {1:.10f}) is {2}within the unit circle. π is {5:.10f}. (i:{3:d} p:{4:d})"
"".format(x, y, "" if hit else "not ", newest.count_inside, newest.count_total, newest.value()))
return self.bot.reply(event, msg)
plugin = Pi

View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='PiLog',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('count_inside', models.PositiveIntegerField()),
('count_total', models.PositiveIntegerField()),
('created', models.DateTimeField(auto_now_add=True)),
],
),
]

View File

69
dr_botzo/pi/models.py Normal file
View File

@ -0,0 +1,69 @@
"""Karma logging models."""
from __future__ import unicode_literals
import logging
import math
import pytz
import random
from django.conf import settings
from django.db import models
log = logging.getLogger('pi.models')
class PiLogManager(models.Manager):
"""Assemble some queries against PiLog."""
def simulate(self):
"""Add one more entry to the log, and return it."""
try:
latest = self.latest()
except PiLog.DoesNotExist:
latest = PiLog(count_inside=0, count_total=0)
latest.save()
inside = latest.count_inside
total = latest.count_total
x = random.random()
y = random.random()
hit = True if math.hypot(x,y) < 1 else False
if hit:
newest = PiLog(count_inside=inside+1, count_total=total+1)
else:
newest = PiLog(count_inside=inside, count_total=total+1)
newest.save()
return newest, x, y, hit
class PiLog(models.Model):
"""Track pi as it is estimated over time."""
count_inside = models.PositiveIntegerField()
count_total = models.PositiveIntegerField()
created = models.DateTimeField(auto_now_add=True)
objects = PiLogManager()
class Meta:
get_latest_by = 'created'
def __unicode__(self):
"""String representation."""
tz = pytz.timezone(settings.TIME_ZONE)
return "({0:d}/{1:d}) @ {2:s}".format(self.count_inside, self.count_total,
self.created.astimezone(tz).strftime('%Y-%m-%d %H:%M:%S %Z'))
def value(self):
"""Return this log entry's value of pi."""
return 4.0 * int(self.count_inside) / int(self.count_total)