Question
7.20 Lab: Grade Processor Your task for this lab is to complete the implementation of a program that processes a file containing raw grade data,
7.20 Lab: Grade Processor
Your task for this lab is to complete the implementation of a program that processes a file containing raw grade data, and produces a report file.
Starter Code
The framework of the program has been given to you in the starter code, including useful constants, function prototypes, and the main()function.
The parts of the program that you need to complete have been marked with comments:
// TODO (n): ...
Input File Format
The input file will be formatted as follows:
- Lines beginning with a '#' character should be ignored
- All other lines will be student records consisting of colon-separated fields:
- student name
- student ID
- test scores
- The test scores field will contain a comma-separated list of 4 test results
For example, the beginning of such a file might look like this:
# Prof. Jones' Basket Weaving 101 class # Student:ID:Scores Fred Flintstone:q5563w:70,82,55,80 Barney Rubble:q5771x:65,62,0,71
Output File Format
The output file will be a neatly formatted report showing the student name, their four scores, the lowest score (dropped), the total score, average, and resulting grade letter.
For example, given the input above, the report would look like this:
Name Scores (Low) Total Average Grade ------------------------ ---------------- ----- ----- ------- ----- Fred Flintstone 70 82 55 80 ( 55) 232 77.33 C Barney Rubble 65 62 0 71 ( 0) 198 66.00 D
Note that various field widths have been defined as constants near the top of the source file. Be sure to use these named constants, rather than hard-coding "magic numbers" when you get to writing the code to output the formatted record.
Implementing the helper functions
The program is written in a modular way, using functions to "abstract" away details, so that the overall flow of the program is easy to understand. The main() function calls other functions to do the actual work.
Your job is to fill in the details by implementing many of these "helper" functions.
The Top-Level Functions
string getInputFilename()
The program starts by asking the user for the name of the input file. To do this it invokes the getInputFilename() function. This function should:
- Prompt the user to enter a filename.
- Validate that the filename has the form:
- "rawgrades-
.txt" - where
identifies the class to which it pertains. - ..for example, the above input file might be named "rawgrades-bw101.txt".
- "rawgrades-
- Continue prompting the user for a filename until a valid one is given.
- Return the validated filename.
Sample run:
Enter input filename (rawgrades-.txt): what Enter input filename (rawgrades- .txt): what.txt Enter input filename (rawgrades- .txt): rawgrades.txt Enter input filename (rawgrades- .txt): rawgrades-bw101.txt Processing rawgrades-bw101.txt ... Report written to grade-report-bw101.txt
string deriveOutputFilename()
This function takes an input filename as a parameter and should return the corresponding output filename.
bool openFiles()
This function opens the input and output files, associating the files with the provided input/output file streams.
If the input file fails to open, the following message should be output before the function returns false:
Failed to open for read:
If the output file fails to open, the following message should be output before the function returns false:
Failed to open for write:
The function should return true only if both files opened successfully. Returning false signals to the main program that some error occurred and that the run should be aborted.
void processGradeFile()
This function has been implemented for you. It writes the report header (invoking a function also written for you), then loops over the lines read in from the input file, invoking processLine(...) for each one.
Helper Functions
To break the problem down into manageable pieces, helper functions have been defined to solve small, specific tasks. These will need to be implemented correctly, and called from the appropriate places to complete the project.
You'll find them in the starter code, but as a quick summary:
// Returns true if `fname` of the form "rawgrades-.txt" bool validInputFilename(const string &fname) // Parses a record, placing the substrings into `name`, `id`, and `scores` void parseStudentRecord(const string &line, string &name, string &id, string &scores) // Parses a scores string, placing the integer values into s1..s4 void parseScores(const string &scores, int &s1, int &s2, int &s3, int &s4) // Returns the smaller of the two values int min(int a, int b) // Returns the smallest of all the values int min(int a, int b, int c, int d) // Returns a letter grade for the given score char gradeFromScore(double score) // Processes a line read from the raw-grades input file void processLine(ostream &out, const string &line) // Writes the report header to the given output file stream (ALREADY DONE) void writeReportHeader(ostream &out)
Given TXT: rawgrades-bw101.txt
# Prof. Jones' Basket Weaving 101 class # Student:ID:Scores Fred Flintstone:q5563w:70,82,55,80 Barney Rubble:q5771x:65,62,0,71 Yogi Bear:q1332b:89,92,100,95 Secret Squirrel:q9976d:75,77,83,81 (name thatn Chegg won't allow) Dastardly:d1101f:59,0,37,0
//name cannot be written is : D i c k
//remove the space to spell out full name
Given TXT:
# A long time ago, in a galaxy far, far away... Luke Skywalker:red-5:88,97,87,84 Leia Organa:d1102:94,100,88,83 Han Solo:pirate1:87,69,18,83 Threepio:C3P0:100,100,100,99 Artoo:R2D2:100,100,99,100 Darth Vader:x451:95,27,89,67 Ben Kenobi:obi-wan:98,93,96,97 Jar-Jar Binks:ep-1:37,50,3,0
Given Template:
// ----------------------------------------------------------------------- // grader.cpp // ----------------------------------------------------------------------- #include#include #include #include using namespace std; // ----------------------------------------------------------------------- // global constants const string INFILE_PREFIX = "rawgrades-"; const string OUTFILE_PREFIX = "grade-report-"; const string FILE_EXT = ".txt"; const size_t LEN_PREFIX = INFILE_PREFIX.length(); const size_t LEN_F_EXT = FILE_EXT.length(); const string HASH = "#"; const string COLON = ":"; const string SPACER = " "; const double A_GRADE = 90.0; const double B_GRADE = 80.0; const double C_GRADE = 70.0; const double D_GRADE = 60.0; // anything below D_GRADE is an 'F' // output field widths const int FW_NAME = 24; const int FW_SCORE = 4; const int FW_LOW = 3; const int FW_TOTAL = 5; const int FW_AVG = 7; const int FW_GRADE = 3; const int FW_SCORE_X4 = FW_SCORE * 4; // ----------------------------------------------------------------------- // function prototypes // top-level functions string getInputFilename(); string deriveOutputFilename(const string &inFname); bool openFiles(const string &inName, const string &outName, ifstream &fin, ofstream &fout); void processGradeFile(ifstream &fin, ofstream &fout); // helper functions // TODO (0): declare function prototypes for the helper functions // ----------------------------------------------------------------------- // program entry point int main() { // main() has been implemented for you; no need to change anything here ifstream fin; ofstream fout; string inFilename = getInputFilename(); string outFilename = deriveOutputFilename(inFilename); if (!openFiles(inFilename, outFilename, fin, fout)) { return EXIT_FAILURE; } cout << "Processing " << inFilename << " ..." << endl; processGradeFile(fin, fout); cout << "Report written to " << outFilename << endl; fin.close(); fout.close(); return EXIT_SUCCESS; } // ----------------------------------------------------------------------- // helper function definitions // Returns true if `fname` of the form "rawgrades- .txt" bool validInputFilename(const string &fname) { size_t nameLen = fname.length(); // TODO (1): implement validation on the given filename // currently this assumes that all names are valid // but this will fail the unit tests return true; } // Parses a record, placing the substrings into `name`, `id`, and `scores` void parseStudentRecord(const string &line, string &name, string &id, string &scores) { // TODO (2): carve up the input line into substrings // placing the results into the appropriate reference variables } // Parses a scores string, placing the integer values into s1..s4 void parseScores(const string &scores, int &s1, int &s2, int &s3, int &s4) { // TODO (3): parse the score string: "nn,nn,nn,nn" // HINT: consider using an input string stream (istringstream) } // Returns the smaller of the two values int min(int a, int b) { // TODO (4): return minimum value return 0; } // Returns the smallest of all the values int min(int a, int b, int c, int d) { // TODO (5): return minimum value // HINT: use min(int, int) return 0; } // Returns a letter grade for the given score char gradeFromScore(double score) { char grade = 'F'; // TODO (6): adjust grade based on score return grade; } // Processes a line read from the raw-grades input file void processLine(ostream &out, const string &line) { string studentName, studentId, scores; int score1, score2, score3, score4; int total, lowest; double average; char letterGrade; // TODO (7): ignore lines that start with `#` // TODO (8): process the raw record... // - extract name, id, scores // - compute total (but subtract the lowest score) // - compute the average (of 3 scores) // - assign the correct letter grade // TODO (9): write the formatted record to the report file } // Writes the report header to the given output stream void writeReportHeader(ostream &out) { // Lucky you! I've implemented this one for you. Don't change it! :) out << left; out << setw(FW_NAME) << "Name" << SPACER << setw(FW_SCORE_X4) << "Scores" << SPACER << "(" << setw(FW_LOW) << "Low" << ")" << SPACER << setw(FW_TOTAL) << "Total" << SPACER << setw(FW_AVG) << "Average" << SPACER << "Grade" << endl; out << setfill('-'); out << setw(FW_NAME) << "" << SPACER << setw(FW_SCORE_X4) << "" << SPACER << "-" << setw(FW_LOW) << "" << "-" << SPACER << setw(FW_TOTAL) << "" << SPACER << setw(FW_AVG) << "" << SPACER << "-----" << endl; out << setfill(' ') << fixed << setprecision(2); } // ----------------------------------------------------------------------- // top-level function definitions // Returns a validated input filename from the user string getInputFilename() { string fname; // TODO (10): Repeatedly prompt the user for a filename // until it matches the required form. return fname; } // Derives the output filename from the given input filename string deriveOutputFilename(const string &inFname) { // TODO (11): Generate the output file name return "FIXME-" + inFname; } // Returns true only if both files opened without error bool openFiles(const string &inName, const string &outName, ifstream &fin, ofstream &fout) { // TODO (12): open input and output files, associate with the given streams // HINT: // open input; if fails, write message and return false // open output; if fails, write message and return false // return true return false; } // Read input records, process, write formatted output records void processGradeFile(ifstream &fin, ofstream &fout) { // This function, too, has been implemented for you... nothing to do here string rawLine; writeReportHeader(fout); while (getline(fin, rawLine)) { processLine(fout, rawLine); } } // -----------------------------------------------------------------------
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started