# Monte Carlo method of computing pi
# with graphics showing the points on the unit circle
# and printing he results in the graphics window
# Toss darts at a dart board (2x2, centered at (0,0)
# The ratio of the darts in the unit circle to all darts is pi/4
#
# Matt Bishop, ECS 36A, Winter 2019
#
import random
import math
import turtle
# Generate a landing position for a dart tossed at
# a 2x2 square with center at (0,0)
# returns: (x, y) co-ordinates of toss
def gentoss():
x = 2*random.random() - 1
y = 2*random.random() - 1
return x, y
# for point x, y, if x^2 + y^2 <= 1, they are in the unit circle
# parameters: x, y: co-ordinates of point
# returns True if so, False if not
def inunitcircle(x, y):
return x ** 2 + y ** 2 <= 1
# function to read and vet user selection
# returns: n, the number of tosses
# NOTE: n must be positive; return -1 to quit
def getinput():
# loop until we get good input
while True:
try:
# get the input and check the type here
n = int(input("number of tosses (EOF to quit): "))
except EOFError: # user wants to quit, so help
n = -1
break
except: # user didn't enter a number
print("You have to enter a positive n or EOF")
continue
# got an integer
# now check the value we read/were given
if n > 0:
break
# this is bad, so say so
print("You have to enter a positive n or EOF")
# it's positive to continue, -1 to quit
return n
##### GRAHICS ROUTINES
#
#
# first, we need to scale everything to make it visible
# set this by trial and error
#
scale = 100
#
# make a window
# parameters: col is background color of window
# name is title to put on window
# returns: handle for window
# side effects: none
#
def makewindow(col, name):
win = turtle.Screen() # draw the window for the picture
win.bgcolor(col) # make the background color col
win.title(name) # put up a title
return win
#
# make a tutle
# parameters: col is color of turtle (pen for drawing)
# img is shape of turtle
# returns: handle for turtle
# side effects: animation is turned off and turtle is hidden
#
def maketurtle(col, img):
tur = turtle.Turtle() # create a turtle
tur.shape(img) # give it the identified shape
tur.color(col) # be sure this color contrasts with the background
tur.speed(0) # no animation -- turtle (drawing) just jumps
tur.hideturtle() # don't show turtle
return tur
#
# move turtle to a given point
# parameters: tur is handle of turtle to use
# x, y is new location of turtle
# returns: nothing
# side effects: none
#
def plotgoto(tur, x, y):
tur.goto(x * scale, y * scale)
#
# draw a line from first point to second point
# parameters: tur is handle of turtle to use
# x1, y1 is beginning point of line
# x2, y2 is ending point of line
# returns: nothing
# side effects: pen is raised to move turtle to line
# leaves pen in original state at end
#
def plotline(tur, x1, y1, x2, y2):
# get current pen state of turtle
penstatedown = tur.isdown()
# move the turtle to the starting point without drawing a line
tur.penup()
plotgoto(tur, x1, y1)
# now draw the line
tur.pendown()
plotgoto(tur, x2, y2)
# now restore original pen state
if (not penstatedown):
tur.penup()
#
# draw an x-axis and y-axis
# parameters: tur is handle of turtle to use
# xpos, xneg are the positive, negative end points of the x-axis
# ypos, yneg are the positive, negative end points of the y-axis
# returns: nothing
# side effects: none
#
def plotaxes(tur, xpos, ypos, xneg, yneg):
# draw the x axis
plotline(tur, xneg, 0, xpos, 0)
# draw the y axis
plotline(tur, 0, yneg, 0, ypos)
#
# draw a dot at a point
# parameters: tur is handle of turtle to use
# x, y are co-ordinates of the point
# returns: nothing
# side effects: turtle raises pen throughout this
# dot is 1 point in size
#
def plotpoint(tur, x, y):
# get current pen state of turtle
penstatedown = tur.isdown()
# move the turtle to the point without drawing a line
tur.penup()
plotgoto(tur, x, y)
# draw the dot
tur.dot(1)
# now restore original pen state
if (penstatedown):
tur.pendown()
#
# draw a unit circle, then surround it by a unit square
# parameters: tur is handle of turtle to use
# x, y are co-ordinates of the point
# returns: nothing
# side effects: turtle raises pen throughout this
# dot is 1 point in size
#
def drawunit(tur, circlecolor, squarecolor):
# get current color state of turtle
curcolor = tur.pencolor()
# first, draw the x, y axes (each 4 units, from -2 to 2)
plotaxes(tur, 1, 1, -1, -1)
# now draw a unit circle centered at (0, 0) in green
tur.goto(0, -scale)
tur.color(circlecolor)
tur.circle(1 * scale)
# now draw a square around the unit circle in red
tur.color(squarecolor)
plotline(tur, -1, -1, -1, 1)
plotline(tur, -1, 1, 1, 1)
plotline(tur, 1, 1, 1, -1)
plotline(tur, 1, -1, -1, -1)
# restore original color state
tur.color(curcolor)
##### END OF GRAPHICS ROUTINES
# main routine: pull it all together
def main():
# get number of tosses
n = getinput()
# valid number; be sure it's positive, or user is stopping
if n > 0:
# initialize random number generator
random.seed()
# set up the window and the turtle
wn = makewindow("white", "Plot of the Monte Carlo calculation of pi")
yertle = maketurtle("black", "classic")
# draw the figure
drawunit(yertle, "green", "red")
# number of darts in unit circle
# nothing thrown yet
h = 0
# now start throwing
for i in range(n):
# toss
x, y = gentoss()
# plot it
plotpoint(yertle, x, y)
# is it in the circle?
if inunitcircle(x, y):
h += 1
# done! see how well you did ...
yertle.penup()
yertle.goto(0, -1.25 * scale)
yertle.write(" number of throws: %6d\t\tapproximation to pi: %9.7f" % (n, 4.0 * h / n), False, "center", ("Monaco", 10, "normal"))
yertle.goto(0, -1.40 * scale)
yertle.write(" number of hits: %6d\t\t actual value of pi: %9.7f" % (h, math.pi), False, "center", ("Monaco", 10, "normal"))
yertle.goto(0, -1.55 * scale)
yertle.write(" ratio: %6.4f\t\t error: %9.7f" % (h/n, abs(4.0 * h / n - math.pi)), False, "center", ("Monaco", 10, "normal"))
# end it all
yertle.hideturtle()
wn.mainloop()
#
# they're off!
#
main()