CS302 -- Lab 3 - Golf Handicaps
In this lab, you will write a non-trivial application in which you will use STL maps and vectors.
In the game of golf, players can rank themselves with a handicap.
This is a number that basically tells you how good you are at the game.
The lower your handicap, the better you are.
The US Golf Association has a very lengthy description of how you
calculate a handicap. It may be found at
http://www.usga.org/handicap/,
if you're interested. I'm going to simplify it a bit. Here is how
you calculate a handicap for a golfer:
For example, suppose I have played 20 rounds of golf from the
white tees at Three
Ridges golf course, whose rating is 69.3 and whose slope is 119.
On ten of the rounds, I shot 88 and on the other ten, I shot 85.
Then I would compute my handicap as follows:
- For each round on which I shot an 88, the differential
is (88-69.3)*113/119 = 17.757.
- For each round on which
I shot an 85, the differential is (85-69.3)*113/119 =
14.908.
- This means that my best ten differentials are all 14.908, so
their average is obviously 14.908, and
my handicap is 0.96 * 14.908 = 14.31
Your Job
Your job is to write the program handicap. It should take two
command line arguments:
handicap score-file course-file
The score-file is a file that contains scores.
Each line of this file is in the following format:
Month Day Year Name Score Course
Month is a number between 1 and 12.
Day is a number between 1 and 31.
You do not have to error check for legal month/day combinations
(i.e. don't worry about 2/30).
Year is the year (i.e. 1999, 2000 -- no
Y2K bugs on this program). Name is a one-word name of
a golfer, and
Score is an integer score. Course is the name of
a course, and may contain any number of words separated by white
space. The scores can be in any order, and there can be any number
of golfers in the score file.
There are example score files in
/home/bvz/courses/302/labs/lab3:
- score1: An example score file with
exactly 20 scores, 10 of which are 88's and 10 of which are
85's, all played on the white tees at Three Ridges. As calculated
above, the handicap for this score file should be 14.31.
- score2: The same score file as score1,
but with a second golfer, Phil, added. Phil has 10 scores of
74 and 10 scores of 78.
- score3: The same score file as score2,
except that Phil and Jim both have 40 scores. The most recent 20
for each person is the same as in score2.
- bigscore: A big score file with 11 different
golfers who have a variety of scores.
- scorebad1: A bad score file: only 4
scores instead of >= 20.
- scorebad2: A bad score file: the
golf course does not exist.
- scorebad3: A bad score file: bad
month declarations.
- scorebad4: A bad score file: the
golfer's name is two words.
- scorebad5: A bad score file: a whole variety
of error conditions
The course-file is a file that contains golf courses plus
their ratings and slopes. This file has a looser structure
than the score file. It contains three kinds of lines:
- Course Lines: These start with the word ``Course'' and
then contain the name of the golf course. Again, the name is
words separated by white space.
- Rating/Slope Lines: These have the word
``Rating'' then the rating (which is a floating point number),
then the word ``Slope'' and then the slope (which you should
also treat as a floating point number). When you encounter
this line, it is the rating and slope for the course named
on the most recently encountered ``Course'' line.
- All Other Lines: All other lines should be ignored.
An example (good to use for testing) is in
courses. Look at the first four
lines:
Course Three Ridges -- White Tees
Rating 69.3 Slope 119
Par 72
|
This says that there is a course that's called ``Three Ridges -- White Tees''
with a rating of 69.3 and a slope of 119. You ignore the ``Par'' line, and
the blank line after the ``Par'' line.
In both files (scores and courses) you should create a string for
a course that is composed of each word separated by a space. For
example, the following course specifications should be equivalent:
Course Three Ridges -- White Tees
Course Three Ridges -- White Tees
Now, your program must read in both of these files, and exit if it
sees any errors. It should however error check all lines before
exiting.
If both files are ok, and all golfers have at least 20
scores, then it should compute the handicap for each golfer, and then
print out each golfer and his or her handicap ordered by handicap (lowest
first). Print out the handicap first (padded to 5 characters and two
decimal places), and then the golfer's name.
For example:
UNIX> handicap score1 courses
14.31 Jim
UNIX> handicap score2 courses
3.70 Phil
14.31 Jim
UNIX> handicap score3 courses
3.70 Phil
14.31 Jim
UNIX> handicap bigscore courses
2.58 Tiger
8.26 Phil
8.31 Sergio
9.63 David
9.77 Anika
10.12 Jose
18.12 Ernie
18.21 Colin
18.50 John
18.88 Se-Ri
39.55 Karrie
UNIX> handicap scorebad1 courses
Jim: Less than 20 scores (only 4)
UNIX> handicap scorebad2 courses
scorebad2 Line 1: Course `` Three Ridges -- Ebony Tees'' not found in course file
UNIX> handicap scorebad3 courses
scorebad3 Line 1: Bad Month
UNIX> handicap scorebad4 courses
scorebad4 Line 1: Bad Score
UNIX>
A working executable is available at
~bvz/cs302/lab3/handicap.
If you set the environment variable PRINTDIFFS to be "yes", then
the program will also print out each golfer's differential and date
number (defined in step 4 below) or each score. You can use this
to test yourself in case your computations do not seem to match those here:
(note, you do not have to implement this feature. It is just included
it so that you can help test your own code).
UNIX> setenv PRINTDIFFS yes
UNIX> handicap score1 courses
Jim
Dnum: 743660 Differential: 17.76
Dnum: 743661 Differential: 17.76
Dnum: 743691 Differential: 14.91
Dnum: 743693 Differential: 14.91
Dnum: 743722 Differential: 17.76
Dnum: 743725 Differential: 17.76
Dnum: 743753 Differential: 14.91
Dnum: 743757 Differential: 14.91
Dnum: 743784 Differential: 17.76
Dnum: 743789 Differential: 17.76
Dnum: 743815 Differential: 14.91
Dnum: 743821 Differential: 14.91
Dnum: 743846 Differential: 17.76
Dnum: 743853 Differential: 17.76
Dnum: 743877 Differential: 14.91
Dnum: 743885 Differential: 14.91
Dnum: 743908 Differential: 17.76
Dnum: 743939 Differential: 14.91
Dnum: 743970 Differential: 17.76
Dnum: 744001 Differential: 14.91
14.31 Jim
UNIX> setenv PRINTDIFFS no
UNIX> handicap score1 courses
14.31 Jim
UNIX>
Fields, printf, and converting strings to numbers
You may use a C++ version of the Fields library for this assignment and you may
use printf rather than cout if you wish. Of course you are free to use stream I/O
if you prefer. In order to use the Fields library in your program you will need
the following statement:
#include "Fields.h"
You will need to add a -I/home/bvz/courses/302/include flag to your
compilation command. You will also need to add /home/bvz/courses/302/objs/lib302.a
to your linker command. For example:
g++ -o handicap handicap.o /home/bvz/courses/302/objs/lib302.a
You can find documentation for the C++ Fields library
here. You can also find source code for the C++ Fields
libary that can be compiled on either a mac or windows machine at
/home/bvz/courses/302/src/macwin.
If you use the C++ Fields library then you will need to convert the strings it
creates to numbers. hints provides three ways to
do it.
What To Submit
You should submit the following files:
- handicap.h: Even though you are using only one .cpp file for this
assignment you should still place your classes in a .h
file. Doing so will give you good practice for future labs.
- handicap.cpp
- makefile
Remember, you submit labs using the special script discussed on the
TA web site.
Suggested steps for writing this program:
Below are outlined suggestions for how to go about
writing this program, which you should find helpful.
-
Write a basic program that tests for the right number of command line arguments, and print out the right error message if that was wrong. Get your makefile working.
-
Write a procedure called read_course_file() that takes the course file name and an STL map as an argument and fills the STL map with course classes, which you should define. This function tests for all varieties of errors in the course file. When it returns, the main() routine prints out all of the courses in alphabetical order. Test this a bit, especially checking the error handling code.
The error conditions you should detect are:
- Duplicate course names
- Duplicate rating/slopes for the same course
- Invalid numbers for the rating and/or slope
- Negative numbers for the rating and/or slope
- Wrong number of fields for a rating/slope line
- Wrong keywords for the rating/slope line--if field 0 is "rating"
then field 2 must be "slope"
- No rating/slope for a course
- Wrong number of fields for a course line
- A rating line precedes any of the courses in the file
The file coursesbad1 contains a file that
tests all of the error conditions.
-
Write a procedure called read_scores_file() that takes the score file name and the course STL map as input, and fills a STL vector with score classes, which you define. However, for this step, all the function does is read the score file and check for errors. These errors are: bad month/day/year/score, bad line (too few words), and course not found in the course file (which you do check by searching in the course map). Test this against all the input files listed above.
You can read about maps at http://www.cppreference.com, under C++ Maps.
-
Now, traverse the vector of scores, calculating the differential for each score, storing it as part of the score class. Test this by again traversing the vector of scores, this time printing out all of the differentials. This is what you get when you set PRINTDIFFS in the provided executable above.
-
Now, test to make sure that all the golfers had at least 20 scores, and print an error if that was not the case. Create a STL map of golfer classes, which store a golfer's name, vector of scores, and handicap. Then, traversing the vector of scores, for each score find the appropriate golfer in the golfer map and add the score to the golfer's vector of scores. If the golfer does not yet exist in the map, then create an object for that golfer and insert the golfer into the map.
Now, traverse your map of golfers, printing an error message if any golfer has less than 20 scores. Test this.
-
Now, for each golfer in your map, sort its vector of scores. To do this,
write a boolean function named compare_scores_by_date to compare two score
objects by date. The function should return true if the date of the first score
is strictly less than the date of the second score. If the two dates are equal you
should return false.
A trick for comparing two dates is to compute a date number for each date and then
compare the date numbers. You can compute a date number like this:
number = day + (month*31) + (year * 12 * 31)
Compute this, then print it out for each score and check to make sure that it is working.
To sort a STL vector, you need to use the STL generic sort() function and pass it
your compare_scores_by_date function.
You can read about it at http://www.cppreference.com, under C++ Algorithms.
-
Now, compute the handicap for each golfer. To do this, for each golfer in
the golfer vector, use the golfer's last 20 scores. Step 6 should have already
sorted each golfer's scores into ascending order by date so you should be able to
erase the inital scores until there are only twenty scores left in the vector.
Sort this updated vector by differential. You will need to write a new boolean function,
named compare_scores_by_differential, that takes two differentials as parameters and returns
true if the first differential is strictly less than the second differential.
Compute the average of the first ten differentials, multiply by 0.96, and store the result as
this golfer's handicap.
-
Finally, iterate through your golfer map and create a new golfer
vector with the golfers. Sort your golfer vector by handicap. This is simply a matter of
creating yet another boolean function, named compare_handicaps, that takes
two golfers and returns true if the first golfer's handicap is strictly less than
the second golfer's handicap. Print out the golfer vector in order.
-
More testing, commenting, etc.