Today's lab looks at decisions from Chapter 8.

Archery Scoring

Read the following program:

# Archery Program for Lab 9
# Lehman College, CUNY, Fall 2012

from graphics import *

def main():
    w = GraphWin("Target Practice",400,400)
    w.setCoords(-200,-200,200,200)

    origin = Point(0,0)

    for radius in range(10,0,-1):
        c = Circle(origin, 20*radius)
        c.draw(w)

    w.getMouse()
    w.close()

main()
What does it do? Try running it to see if you are right (remember for graphics programs to run you will need the graphics.py file in the same directory).

We will use decision statements to make it a bit more colorful and look like an archery target. Since targets alternate the colors between rings, we will do the same. For even numbered rings (that is, where i%2 == 0), we will color the rings red. And for odd numbers, we will color the rings yellow. Note that we are coloring the whole circle each time and then coloring over the inside of it when we color the next smallest circle:


The new part of this program is:
    for radius in range(10,0,-1):
        c = Circle(origin, 20*radius)
        if radius % 2 == 0:
            c.setFill("red")
        else:
            c.setFill("yellow")
        c.draw(w)

Next, we will turn the program into a game, scoring where the user clicked on the target. Lets start by scoring bullseyes (or when the user clicks on the center). We will give the user 10 points for clicking within the center ring. Since we are going to use distance over and over again, we will write a separate function to calculate it:

def dist(p1,p2):
    dist = sqrt((p1.getX()-p2.getX())**2 + (p1.getY() - p2.getY())**2)
    return dist

After drawing the target, we will put up a message to give the user directions:

    t = Text(Point(0,-225), "Click on the target")
    t.setSize(20)
    t.draw(w)
Remember that Text graphics objects are just strings that show up in the graphics window. Since the default font is really small, we have changed its size to 20 points before drawing the text to the window.

Our next step is to use the point the user clicked to figure out if they scored a bulleye or not. Since our inner ring has radius 20, the click is a bulleye if it is within 20 of the origin:

    p = w.getMouse()
    d = dist(origin, p)
    
    #This line prints to the IDLE shell window, so, we can debug the program:
    print("You clicked on (", p.getX(), ",", p.getY(),") with distance: ", d)

    if d < 20:
        t.setText("Bullseye!")
    else:
        t.setText("Missed!")

Putting all the pieces together, we have:

# Archery Program for Lab 8
# Lehman College, CUNY, Fall 2012

from graphics import *
from math import *

def dist(p1,p2):
    dist = sqrt((p1.getX()-p2.getX())**2 + (p1.getY() - p2.getY())**2)
    return dist

def main():
    w = GraphWin("Target Practice",500,500)
    w.setCoords(-250,-250,250,250)

    #make a point for the origin since we'll use it over and over again:
    origin = Point(0,0)

    #draw the target:
    for radius in range(10,0,-1):
        c = Circle(origin, 20*radius)
        if radius % 2 == 0:
            c.setFill("red")
        else:
            c.setFill("yellow")
        c.draw(w)

    #score the users click:
    t = Text(Point(0,-225), "Click on the target")
    t.setSize(20)
    t.draw(w)
    p = w.getMouse()
    d = dist(origin, p)

    #This line prints to the IDLE shell window, so, we can debug the program:
    print("You clicked on (", p.getX(), ",", p.getY(),") with distance: ", d)

    if d < 20:
        t.setText("Bullseye!")
    else:
        t.setText("Missed!")
    
    #keep the window up until the user clicks
    w.getMouse()
    w.close()

main()
Try running it several times, clicking both on the center and elsewhere. What messages do you see?

Lets make the program a bit more sophisticated and have it give a score of 10 for a bulleye, 1 point for hitting anywhere else in the target, and 0 for a total miss of the target. To do this, we only need to change the scoring section of the program. Our first part will stay the same, but we need to distinguish between what happens when they hit the rest of the target or miss altogether. To do that, we will use the if-elif-else construct. This allows us to have 3 different choices:

The if-elif-else will take care of some of these conditions for us automatically. Here's the idea in pseudocode:
	if distance < 20:
		put up the message that they have a bullseye
	elif distance < 200:	#We don't need to say distance > 20, since the only way 
		#we will make it here is if that's so.  We only need the new condition =
		put up the message that they hit the target
	else:	#No conditions needed, this is what happens if all other conditions fail
		put up the message that they missed

Here's the program with the additional decision for scoring:

# Archery Program for Lab 8
# Lehman College, CUNY, Fall 2012

from graphics import *
from math import *

def dist(p1,p2):
    dist = sqrt((p1.getX()-p2.getX())**2 + (p1.getY() - p2.getY())**2)
    return dist

def main():
    w = GraphWin("Target Practice",500,500)
    w.setCoords(-250,-250,250,250)

    #make a point for the origin since we'll use it over and over again:
    origin = Point(0,0)

    #draw the target:
    for radius in range(10,0,-1):
        c = Circle(origin, 20*radius)
        if radius % 2 == 0:
            c.setFill("red")
        else:
            c.setFill("yellow")
        c.draw(w)

    #score the users click:
    t = Text(Point(0,-225), "Click on the target")
    t.setSize(20)
    t.draw(w)
    p = w.getMouse()
    d = dist(origin, p)

    #This line prints to the IDLE shell window, so, we can debug the program:
    print("You clicked on (", p.getX(), ",", p.getY(),") with distance: ", d)

    if d < 20:
        t.setText("Bullseye! 10 points")
    elif d < 200:
        t.setText("Hit the target! 1 point")
    else:
        t.setText("Missed! 0 points")
    
    #keep the window up until the user clicks
    w.getMouse()
    w.close()

main()
Run your program multiple times until you see all three messages.

If you finish early, you may work on the programming problems.