In: Computer Science
Setup
The game that we will use for this simulation is "darts." We will randomly throw a number of darts at a specially configured dartboard. The set up for our board is shown below.
In the figure, you can see that we have a round ‘dart board’ mounted on a square piece of ‘wood’. The dartboard has a radius of one unit. The piece of wood is exactly two units square so that the round board fits perfectly inside the square.
But how will this help us to approximate pi? Consider the area of the circular dartboard. It has a radius of one so its area is pi. The area of the square piece of wood is 4 (2 x 2). The ratio of the area of the circle to the area of the square is pi/4. If we throw a whole bunch of darts and let them randomly land on the square piece of wood, some will also land on the dartboard. The number of darts that land on the dartboard, divided by the number that we throw total, will be close to the ratio described above (pi/4), minus random noise. If we then multiply by 4, we have an approximation of pi.
You will need to implement a function that sets up the dartboard as pictured above; however, we are going to do this by breaking our setup into further functions. You should implement the following functions as described:
drawSquare(myturtle, width, top_left_x, top_left_y)
to outline dartboard
drawLine(myturtle, x_start, y_start, x_end, y_end)
to draw a single axis
You will need to call this twice when you setup your dartboard, once for each axis
drawCircle(myturtle, radius)
to draw the circle
Note: Do not modify any of the code in main. You will implement the functions that main calls.
If you run your code as is, the dartboard will probably be very tiny. You will need to update the scale of your window. You can use the Screen method setworldcoordinates to make your graph re-scale according to the values you are graphing. Read the documentation and refer to your code for Lab 3 to determine the values you need to pass to it.
Your setUpDartboard() function should be almost entirely calls to the above functions.
You can write dummy functions or comment out the parts of the main() that you have not completed yet to test and debug your code as you go.
Throwing Darts
Now that we have our dartboard setup, we can throw darts. We will assume that we are good enough at throwing darts that we always hit the wood (inside the window). Sometimes the darts will hit the dartboard (circle) and sometimes they will miss.
In order to simulate throwing darts, we can use the random module’s random() function to generate two random floating point numbers between -1 and 1. The first will be the “x coordinate” of the dart and the second will be the “y coordinate”. Once we move to where the dart lands, we can use a Turtle function to draw a dot at that point (left as an exercise to the reader).
random.uniform() also accomplishes this in fewer steps. You should read the documentation on this function to learn how to use it.
The driver (main function) tests your code by "throwing" 10 darts at the dartboard. Make sure this part works before moving onto the next part (i.e. each call draws a dot onto the board).
Part B
A Game of Darts
Once you understand what you have to do, using the provided driver code as a guide, complete the program, run and debug it as necessary.
You must use the provided template. Your code must implement the functions used in main as well as the functions described in the head comments.
Notice that only functions are called in the main. There is no program logic. This should be the structure of all procedural programs.
The next part of your program requires you to create a function that plays a game of darts between two players. This function is called in the main, playDarts(). We will simplify the game of darts by saying that if the player lands inside the circle, she scores a point.
What we need to figure out is how many darts land in the circle. Since the circle is centered at (0,0) and it has a radius of 1, the question is simply a matter of checking to see whether the dart has landed within 1 unit of the center. Luckily, there is a turtle method called distance that will return the distance from the turtle to any other position. It only needs the x,y for the other position.
For example, darty.distance(12,5) would return the distance from darty’s current position to position (12,5).
Now we need to use this method in an if/else to ask whether darty is within 1 unit from the center. You must meet the following requirements in your program:
You should choose one color for darts that are within the circle, and a different color for darts outside of the circle.
This means you will need to update your throwDart function to change the color of the dart before you draw it, depending on where it lands
You must create a boolean function, isInCircle(myturtle), that returns True or False depending on if the turtle is within 1 unit away from the origin.
There should be 10 rounds where the players take turns throwing their own dart. If a player’s dart is within the circle, they score a point. You should keep track of both players’ scores, then print which player has won or if there was a tie.
Your playDarts function must:
Use a loop to play the rounds
Use accumulators to keep track of players' points
Use your existing throwDart() function
Part C
Making the Plot Better
Finally you will end your program by running a Monte Carlo simulation.
Counting Darts
We already know the total number of darts being thrown. The variable number_darts keeps this for us. Create an accumulator variable in your montePi function.
For example, inside_count, initialize it to zero, and then increment it if we find that the dart is in the circle.
Remember that the increment is a form of the accumulator pattern.
The Value of Pi
After the loop has completed and visualization has been drawn, we still need to actually compute pi and print it. Use the relationship given above to get the formula.
Run your program with larger values of num_darts to see if the approximation gets better.
To summarize:
The Virtual Dartboard has an area of 2 X 2 (i.e., it accommodates a unit circle)
Total area is 4
Since area of unit circle = pi * radius2 = pi (since radius squared = 1)
ratio of area of unit circle to area of board is pi/4
Theoretically, if you fill the entire board with darts, counting the number of darts that fall within the circle divided by the total number of darts thrown should give us the same ratio (i.e., 1/4 pi)
Therefore, multiplying this ratio by 4 should give us our approximation of pi
Main Code
def main():
# Get number of darts for simulation from user
# Note continuation character <\> so we don't go over 78
columns:
print("This is a program that simulates throwing darts at a
dartboard\n" \
"in order to approximate pi: The ratio of darts in a unit
circle\n"\
"to the total number of darts in a 2X2 square should be\n"\
"approximately equal to pi/4")
print("=========== Part A ===========")
#Create window, turtle, set up window as dartboard
window = turtle.Screen()
darty = turtle.Turtle()
darty.speed(0) # as fast as it will go!
setUpDartboard(window, darty)
# Loop for 10 darts to test your code
for i in range(10):
throwDart(darty)
print("\tPart A Complete...")
print("=========== Part B ===========")
darty.clear()
setUpDartboard(window, darty)
playDarts(darty)
print("\tPart B Complete...")
# Keep the window up until dismissed
print("=========== Part C ===========")
darty.clear()
setUpDartboard(window, darty)
# Includes the following code in order to update animation
periodically
# instead of for each throw (saves LOTS of time):
BATCH_OF_DARTS = 5000
window.tracer(BATCH_OF_DARTS)
# Conduct simulation and print result
number_darts = int(input("\nPlease input the number of darts to be
thrown in the simulation: "))
approx_pi = montePi(darty, number_darts)
print("\nThe estimation of pi using "+str(number_darts)+" virtual
darts is " + str(approx_pi))
print("\tPart C Complete...")
# Don't hide or mess with window while it's 'working'
window.exitonclick()
main()
Program:
Output:
Part A:
Part B:
Part C:
Summary: