As a way of making bowling leagues more fun for beginners, bowlers are often assigned a handicap so that beginning bowlers may compete more evenly with experienced bowlers. The handicap is calculated based on the bowler's average; the higher the average, the lower the handicap. For example, a bowler with an average of 100 may have a handicap of 80, and a bowler with an average of 150 may only have a handicap of 40. When the two bowlers compete against each other, their handicaps are added to their respective scores to determine the winner. The higher bowler still has an advantage (if they both bowl their averages exactly, the 150 + 40 = 190 will beat the 100 + 80 = 180) but the match is clearly much closer. If the 150 bowler bowls exactly 150, the 100 bowler need only bowl a 111 to win instead of a 151. You can assume that the scores entered are integers and that they are legal bowling scores, i.e., in the range [0..300].
handicap = (200 - average) * 80%Here the bowler's average (a floating-point number) is truncated to an integer, and the handicap is also truncated to an integer. (You can use the int() function to truncate a positive floating point number to an integer.) However, if the computation would result in a negative handicap, report the handicap as 0. Note that multiplying by 80% really means multiplying by 0.8.
To report a negative handicap as 0, one would naturally consider an if statement. But since we haven't introduced that concept you can do the following. Compute the handicap in, say, a variable handicap. Then do this:
handicap = max( 0, handicap )Think about why that works.
For example: if a bowler in the above league had a 147.8 average, you would calculate her handicap as follows:
average = 147 (147.8 truncated) handicap = (200 - average) * 80% = (200 - 147) * 80% = 53 * 80% = 42.4which is then truncated to 42.
On the other hand, an excellent bowler with an average of 225.5 would have handicap computed as follows:
average = 225 (225.5 truncated) handicap = (200 - average) * 80% = (200 - 225) * 80% = -25 * 80% = -20But we don't allow negative handicaps, so this is replaced by 0. Note that as soon as we see that the average is greater than or equal to 200, we can stop the computation and report 0.
The sample below shows three separate runs of the program. (Your code only has to handle one bowler, not three! But, of course, you can run your program as often as you like.) Format your output so that, if you were to use the same inputs, your output would match the following exactly. Notice that the handicap may be low, zero, but not negative. There should be one space after each colon (where something follows on the line) and a single blank line above and below the output in addition to the blank lines internal to the report. There are two spaces at the start of the average and handicap lines. Follow these examples and you'll be fine.
> python Handicap.py Enter bowler's name: Bernard Enter Game 1: 200 Enter Game 2: 184 Enter Game 3: 209 Handicap report for Bernard: Bernard's average is: 197 Bernard's handicap is: 2 It's time to Bowl! > python Handicap.py Enter bowler's name: Cindy Lou Enter Game 1: 50 Enter Game 2: 82 Enter Game 3: 75 Handicap report for Cindy Lou: Cindy Lou's average is: 69 Cindy Lou's handicap is: 104 It's time to Bowl! > python Handicap.py Enter bowler's name: Tom Daugherty Enter Game 1: 300 Enter Game 2: 295 Enter Game 3: 287 Handicap report for Tom Daugherty: Tom Daugherty's average is: 294 Tom Daugherty's handicap is: 0 It's time to Bowl! >The final example in slideset 3 shows how to use the name in the later output. Ideally, your program shouldn't crash regardless of what values are input. However, your program does not need to verify that the numbers input are legal bowling scores; we won't test your program for illegal inputs.
Be sure to test your program before you submit it. It should also contain a header with the following format:
# File: Handicap.py # Student: # UT EID: # Course Name: CS303E # # Date: # Description of Program:
If you submit multiple times to Canvas, it will rename your file name
to something like Handicap-1.py, Handicap-2.py, etc.
Don't worry about that; we'll grade the latest version.
>>> s = input("name: ") name: Susie Q. >>> s ' Susie Q. ' >>> s.strip() # creates a new string, doesn't change s 'Susie Q.' >>> n = input("value: ") value: 12 >>> n ' 12 ' >>> int(n) # creates an int, but doesn't change n 12 >>>
Keep an eye on efficiency: In general, this semester we won't care much about the efficiency of our code. But it's a very important issue in computing. For example, when checking whether the computed handicap is negative, we could stop as soon as we see that the average is greater than or equal to 200. Or we go on with the computation and check whether the final computed handicap is less than zero. This is an obvious place to use an if statement (which we'll introduce next week). But for now, just compute the handicap and take the max of the 0 and the handicap. A few extra steps of computation don't really make much difference (in this case); but it's a good idea to favor more efficient computations when possible.
There's an entire area of computing called asymptotic complexity that looks at the efficiency of algorithms. You characterize the complexity of an algorithm by the number of "computational steps" it takes to process a set of data. For example, if you're searching for the smallest element in a list, you only need to look through the elements once, keeping track of the smallest you've seen so far. This is called a linear or "order n" algorithm. If you double the size of the list, you double the time (on average).
Later in the semester, we'll look at some sorting algorithms: bubble sort and insertion sort. These are quadratic or "order n2" algorithms; for each new element you add you have to look through the entire list again. So sorting using these algorithms takes approximately n2 computation steps. That means that a list that is twice as long requires four times as many steps to sort. A list that is ten times as long requires one hundred times as many steps to sort. You can see why a linear algorithm would be much more efficient than a quadratic one.
Some algorithms are exponential or "order kn", for some k. An example is the famous traveling salesman problem: given a list of cities and the distances between them, find the shortest route a salesman would have to take to visit all of them exactly once and return to the starting point. It's believed that this can't be solved in less than 2n steps, where n is the number of cities. Think about how big that number is for 100 cities.
The following table shows why this all matters. The left column is the "order" of the algorithm, meaning the number of steps as a function of the size of the input set. We're supposing each computation takes a microsecond (one millionth of a second) and seeing how long it takes to compute the output as the size of the input set increase (across the top). Now imagine how each algorithm would perform for thousands or millions of elements.
n = 10 | n = 20 | n = 30 | n = 40 | n = 50 | n = 60 | |
---|---|---|---|---|---|---|
n | .00001 sec | .00002 sec | .00003 sec | .00004 sec | .00005 sec | .00006 sec |
n2 | .0001 sec | .0004 sec | .0009 sec | .0016 sec | .0025 sec | .0036 sec |
n3 | .001 sec | .008 sec | .027 sec | .064 sec | .125 sec | .216 sec |
n5 | .1 sec | 3.2 sec | 24.3 sec | 1.7 min | 5.2 min | 13.0 min |
2n | .001 sec | 1.0 sec | 17.9 min | 12.7 days | 35.7 yr | 366 cen |
3n | .059 sec | 58 min | 6.5 yr | 3855 cen | 2 * 108 cen | 1.3 * 1013 cen |
You can see why it's often important to pick the most efficient algorithm to solve a problem. Later in the semester, we'll look at a specific problem (finding the nth Fibonnaci number) for which there is an exponential solution, a linear solution, and even a constant time solution (the time to compute doesn't depend on n).