$29
All 3 components (Cloud9 workspace, Moodle Coderunner attempts, and zip file) must be completed and submitted by Saturday, March 23, at 6 pm for your homework to receive points.
Project 2 requires you to have an interview grading with your TA, completed by Monday, April 15 (Tax Day).
1. Objectives
• Define classes and create objects
• Array operations: initialization, search
• Create arrays of an object type
• Use filestream objects to read data from text files
2. Submission Requirements
All three steps must be fully completed by the submission deadline for your homework to be graded.
1. Create Project2 directory on your Cloud 9 workspace: Your recitation TA will review your code by going to your Cloud9 workspace. TAs will check the last version that was saved before the submission deadline.
◦ Create a directory called Project2 and place all your file(s) for this assignment in this directory.
◦ Make sure to save the final version of your code (File > Save). Verify that this version displays correctly by going to File > File Version History.
◦ The file(s) should have all of your functions, test cases for the functions in main() function(s), and adhere to the style guide. Please read the submission file instructions under Week 4. You must include a test case for each one of your member functions for your classes.
2. Submit to the Moodle Coderunner: Head over to Moodle to the link Project 2 Coderunner. You will find one programming quiz question for each problem in the assignment. Submit your solution for the first problem and press the Check button. You will see a report on how your solution passed the tests, and the resulting score for the first problem. You can modify your code and re-submit (press Check again) as many times as you need to, up until the assignment due date. Continue with the rest of the problems.
3. Submit a .zip file to Moodle: After you have completed all 9 questions from the Moodle assignment, zip all 15 files you compiled in Cloud9, and submit the zip file through the Project 2 (File Submission)link on Moodle.
3. Rubric
Aside from the points received from the Project 2 Coderunner quiz problems, your TA will look at your solution files (zipped together) as submitted through the Project 2 (File Submission)link on Moodle and assign points for the following:
Style and Comments (5 points):
• The style guideis posted on Moodle under Week 6.
• Your code should be well-commented. Please review the standard for well-commented code, presented in more detail in previous homework write-ups.
• Please also include a comment at the top of your solution with the following format:
◦ CS1300 Spring 2019
◦ Author: my name
◦ Recitation: 123 – Favorite TA
◦ Cloud9 Workspace Editor Link: https://ide.c9.io/…
◦ Project 2 - Problem # ...
Global variables (use will result in a 5 point deduction):
• Later in the semester, we will learn about global variables and the joys and dangerous therein. To keep things simple, straightforward, and easy to debug and test, you may not use global variables in this homework.
Algorithm (5 points):
• Before each function that you define, you should include a comment that describes the inputs and outputs of your function and what algorithms you are using inside the function. Please review the standard for including your algorithm for each function, presented in more detail in previous homework write-ups.
Test Cases:
• Test cases for Project 2 are not a part of the grade. However, we expect for you to write your own test cases or use examples in this write-up to test (and debug) your code. In the Coderunner, you are allowed to use up to 30 times to click “check” button without penalty. After 30 checks, points will be deducted.
Please make sure that your submission files follow the the submission file instructions under Week 6.
4. Problem Set
*All the examples and values used in examples are arbitrary and randomly generated.*
In Project 2, you will be creating a Libraryclass to handle the operation of your Book and Userclasses from Homework 7. This new class will streamline the use of your previously-created classes, and will introduce the ability to recommend books based on the similarity between two users.
Specifications
• Create a new class Library. Define the class in a header file and implement it in a separate cpp file.
• The Bookand Userclasses from Homework 7 will be part of Project 2 as well. There may be some small modifications of your member functions and class definitions to fit the new Library class.
• In a driver routine called project2.cpp, the main() function will create an instance of Library object and a menu as specified below.
• Students should have seven files (Book.h, Book.cpp, User.h, User.cpp,
Library.h, Library.cpp, project2.cpp)
• The name of each member function should be exactly as specified. If you modify the function names, then your solution will not pass the autograder.
• There are two questions in Coderunner: 1) Library class 2) driver function
4.1. Library Class
(150 points in Coderunner)
Problem 0 - LibraryClass
Create Library.h and Library.cpp , and implement a class Library, with separate interface and implementation, comprised of the following attributes:
Data members (private):
int: sizeBook
The capacity of the booksarray (50). Constant
int: sizeUser
The capacity of the usersarray (100). Constant
Book array: books
An array of Bookobjects
User array: users
An array of Userobjects
int: numBooks
Number of books in the database (library)
int: numUsers
Number of users in the database (library)
Member functions (public):
Default constructor
Sets both numBooksand numUsers to value 0.
getSizeBook()
Returns sizeBookas an integer
getSizeUser()
Returns sizeUseras an integer
getNumBooks()
Returns numBooksas an integer
getNumUsers()
Returns numUsersas an integer
readBooks(string)
Takes a string (the name of the file to be read) and
populates the booksarray. Returns the total
number of books in booksarray as an integer
printAllBooks()
Prints all books stored in booksarray.
readRatings(string)
Takes a string (the name of the file to be read) and
populates the usersarray. Returns the total
number of users in usersarray as an integer
getRating(string, string)
Takes two strings (username and book title) and
returns that user’s rating for the specified book.
getCountReadBooks(string)
Takes a string (username) and returns the number
of books read by that user as an integer.
viewRatings(string)
Takes a string (username) and prints all the books
a user has provided ratings for.
calcAvgRating(string)
Takes a string (the title of a book) and returns the
average rating of the specified book as a double
addUser(string)
Takes a string (username) and returns an integer1
if the user is successfully added, 0 if the username
already exists in the users array and -2 if the users
array is already full.
checkOutBook(string,
Takes two strings and an integer for username, title
string, int)
of book, and a new rating, respectively (in this
order). Returns an integer 1 if the rating is
successfully updated, -4 if the rating value is not
valid and -3 if the rating value is valid, but the user
or title does not exist in the database.
getRecommendations(string)
Takes a string username and prints the first 5 book
recommendations from the most similar (other)
user.
It is advisable to write your own test cases for each class. Test your class in Cloud9 before submitting to the autograder, because the CodeRunner autograder has a submission limit of 30 attempts, after which there will be a small deduction of points.
Note that the following is broken up into problems to make it a bit more digestible, and for us to break up which parts are worth which points, but there are only 2 Coderunner problems on Moodle for testing your implementations.
Problem 1 - the member function readBooks
Update the readBooks function from Homework 7 to now be a member function for the Library class. The readBooks function populates an array of Book objects with the title and author data found in a file similar to the file books.txt that you’ve used in previous assignments. The array of Book objects is one of the data members of the Library class. This function should:
• Accept one input argument:
◦ string: the name of the file to be read
• Use ifstream and getline to read data from the file, making an instance of the Bookobject for each line, and placing it into the booksarray.
• Return the total number of books in the system, as an integer.
• If multiple txt files are read, then the booksarray should be populated with all of the books from all of the files (unless it reaches capacity, of course). For example, suppose readBooksreads books1.txt, and then it reads books2.txt. After the second function call, readBooksreturns the total number of books read from bothfiles, and the booksarray stores all books from both books1.txtand books2.txt.
• The function should return the following values depending on cases:
◦ Return the total number of booksin the system, as an integer.
◦ When the file is not opened successfully, return -1.
◦ When numBooksis equal to the size, return -2.
◦ The priority of the return code -2 is higher than -1, i.e., in cases when numBooks is equal to the sizeBook and the file cannot be opened, the function should return -2.
◦ When numBooks is smaller than sizeBook, keep the existing elements in books, then read data from the file and add (append) the data to the array. Be sure to update the total number of books in the system. The number of books stored in the array cannot exceed the sizeBook of the books array.
• Empty lines should not be added to the arrays.
Important: Since your books array is private, we cannot directly check objects stored in the array form the main() , like you tested in Homework 7. Let’s make printAllBooks to check if your readBooks are working fully functionally… in the next problem!
Example 1:readBooksas a general case
fileName.txt
Author A,Book 1
Author B,Book 2
Function calls
// make
library object
Library
myLibrary
// call
readBooks
int rv = myLibrary.readBooks(“fileName.txt”);
// print values
cout <<
“rv = “ << rv << endl;
cout <<
“numBooks = “;
cout <<
myLibrary.getNumBooks() << endl;
// print books
myLibrary.printAllBooks();
Output
rv = 2
numBooks = 2
Here is a list of books
Book 1 by Author A
Book 2 by Author B
Example 2: Suppose we call the readBooks functions twice. In books array, all books from the first file and the second file should be stored in the books array, and the function returns the total number of the books stored in the booksarray.
book1.txt
Author A,Book 1
Author B,Book 2
book2.txt
Author C,Book 3
Author D,Book 4
Function calls
// make library object
Library myLibrary
// call readBooks and check return values
int rv1 = myLibrary.readBooks(“book1.txt”);
cout << “rv1 = “ << rv << endl;
int rv2 = myLibrary.readBooks(“book2.txt”);
cout << “rv2 = “ << rv << endl;
// check value of getNumBooks
cout << “numBooks = “;
cout << myLibrary.getNumBooks() << endl;
// print books
myLibrary.printAllBooks();
Output
rv1 = 2
rv2 = 4
numBooks = 4
Here is a list of books
Book 1
by Author A
Book 2
by Author B
Book 3
by Author C
Book 4
by Author D
Example 3:file does not exist.
Function call
// make
library object
Library
myLibrary
// call
readBooks and check return values
int rv1 = myLibrary.readBooks(“badFile.txt”);
cout << “rv1 = “ << rv << endl;
Output
rv1 = -1
Example 4: numBooks becomes equal to the sizeBook and the function returns the sizeBook.
book1.txt
Author A,Book 1
Author B,Book 2
Author C,Book 3
Function call
// make
library obj
Library
myLibrary
// multiple files
were read
// check value of
getNumBooks
cout <<
“numBooks
= “;
cout <<
myLibrary.getNumBooks() << endl;
// call
readBooks
and check return values
int rv1
= myLibrary.readBooks(“book1.txt”);
cout <<
“rv1 = “ << rv << endl;
// check value of getNumBooks
cout << “numBooks = “;
cout << myLibrary.getNumBooks() << endl;
// print books
myLibrary.printAllBooks();
Output
numBooks = 48
rv1 = 50
numBooks = 50
Here is a list of books
(48 other books....)
Book 1 by Author A
Book 2 by Author B
Example 5: numBooks is equal to the sizeBook means that the array is already full and it returns -2.
fileName.txt
Author A,Book 1
Author B,Book 2
Author C,Book 3
Function call
// make
library obj
Library
myLibrary
// multiple files
were read
// check value of
getNumBooks
cout <<
“numBooks
= “;
cout <<
myLibrary.getNumBooks() << endl;
// call
readBooks
and check return values
int rv1
= myLibrary.readBooks(“book1.txt”);
cout <<
“rv1 = “ << rv << endl;
// check value of
getNumBooks
cout <<
“numBooks
= “;
cout <<
myLibrary.getNumBooks() << endl;
Output
numBooks = 50
rv1 = -2
numBooks = 50
Problem 2 - the member function printAllBooks
The printAllBooks function from Homework 7 was very useful. We can use this function to test your readBooks function. So let’s do it again. Write a new printAllBooks function, which will be a member function of the Library class, and will be useful in displaying the contents of your library.
• This function should not take any arguments.
• This function does notreturn anything
● This function should print “Here is a list of books” and then each book in a new line using the following statement
cout << books[i].getTitle() << " by "; cout << books[i].getAuthor() << endl;
Note: In the test case, you can always assume that the number of books matches the number of elements in the booksarray.
Expected output (assuming you have read the data from books.txt)
Here is a list of books
The Hitchhiker's Guide To The Galaxy by Douglas Adams Watership Down by Richard Adams
The Five People You Meet in Heaven by Mitch Albom Speak by Laurie Halse Anderson ...
Problem 3 - the member function readRatings
Update the readRatings function from Homework 7 to now be a member function for the Library class. The readRatings function populates an array of User objects with the username and ratings data found in a file similar to the file ratings.txt that you’ve used in previous assignments. Each username is followed by a list of ratings of the user for each book in books.txt. The array of User objects is one of the data members of the Library class.
For example, suppose there are a total of 3 books. The ratings.txt file would be of the format:
ratings.txt
ritchie,3,3,3
stroustrup,0,4,5
gosling,2,2,3
rossum,5,5,5
...
This function should:
• Accept one input argument:
◦ string: the name of the file to be read
• Use ifstream and getline to read data from the file, making an instance of a Userobject for each line, and placing it in the users array.
• Hint: You can use the split() - function from Problem 3 in Homework 6, with comma (“,”) as the delimiter.
• You can use stoi to convert each rating value (a string, as read from the text file) into an integer value.
• If multiple txt files are read, then the usersarray should be populated with all of the user data from all of the files (unless it reaches capacity, of course). For example, suppose readRatingsreads ratings1.txt, and then it reads ratings2.txt. After the second function call, readRatingsreturns the total number of users read from bothfiles, and the usersarray stores all users from bothratings1.txtand ratings2.txt
• The function should return the following values depending on cases:
◦ Return the total number of users in the system, as an integer.
◦ If the file cannot be opened, return -1
◦ When numUsersis greater than or equal to the sizeUser, return -2
◦ The priority of the return code -2 is higher than -1, i.e., in cases when numUsers is equal to the sizeUser and the file cannot be opened, the function should return -2
◦ When numUsers is smaller than the sizeUser of users array, keep the existing elements in users array, then read data from file and add (append) the data to the arrays. Be sure to update the total number of users in the system. The number of users stored in the arrays cannot exceed the size of the users array.
• Empty lines should not be added to the arrays.
Important: Since your users array is private, we cannot directly check objects stored in the array from the main(), like you tested in Homework 7. Let’s make getRating (in the next problem!) to check if your readRatingsare working well.
Example 1: readRatingsas a general case
bookFile.txt
AuthorA,Book1
AuthorB,Book2
AuthorC,Book3
AuthorD,Book4
AuthorF,Book5
ratingFile.txt
Ninja,0,1,2,3,4
Myth,2,2,4,5,1
Sphyer,3,1,0,0,5
Daequan,0,0,0,0,2
Function call
// make
library obj
Library
lib;
// read
book file
lib.readBooks(“bookFile.txt”);
// call readRatings and check return values
int rv1
= lib.readRatings(“ratingFile.txt”);
cout <<
“rv1 = ”;
cout <<
rv1 << endl;
// check value of getNumUsers
cout <<
“numUsers = “;
cout <<
lib.getNumUsers() << endl;
// print user’s ratings
string name = “Ninja”
cout <<
lib.getRating(name, “book1”) << endl;
cout <<
lib.getRating(name, “book2”) << endl;
cout <<
lib.getRating(name, “book3”) << endl;
cout <<
lib.getRating(name, “book4”) << endl;
cout <<
lib.getRating(name, “book5”) << endl;
Output
rv1 = 4
numUsers = 4
0
1
2
3
4
Example 2: Suppose we call the readRatings functions twice. In users array, all users from the first file and the second file should be stored in the users array, and the function returns the total number of the users stored in the usersarray.
ratingFile.txt
Ninja,0,1,2,3,4
Myth,2,2,4,5,1
Sphyer,3,1,0,0,5
Daequan,0,0,0,0,2
ratingFile2.txt
alpha,0,1,2,3,4
Beta,1,2,3,4,0
gamma,3,4,0,1,2
delta,2,3,4,0,1
sigma,4,0,1,2,3
Function calls
// make library obj
Library lib
// call readRatings and check return values
int rv1 = lib.readRatings(“ratingFile.txt”);
cout << “rv1 = “ << rv << endl;
int rv2 = lib.readRatings(“ratingFile2.txt”);
cout << “rv2 = “ << rv << endl;
// check value of getNumBooks
cout << “numUsers = “;
cout << lib.getNumUsers() << endl;
Output
rv1 = 4
rv2 = 9
numUsers = 9
Example 3:file does not exist.
Function call
• make library obj Library myLibrary
// call readBooks and check return values
int rv1
= myLibrary.readRatings(“badFile.txt”);
cout <<
“rv1 = “ << rv << endl;
Output
rv1 = -1
Example 4:numUsersequals sizeBookmeans the array is already full.
ratingFile.txt
Ninja,0,1,2,3,4
Myth,2,2,4,5,1
Sphyer,3,1,0,0,5
Daequan,0,0,0,0,2
Function call
// make
library obj
Library
myLibrary
// multiple files were read
// check value of getNumUsers
cout <<
“numUsers = “;
cout <<
myLibrary.getNumUsers() << endl;
// call
readRatings and check return values
int rv1
=
myLibrary.readRatings(“ratingFile.txt”);
cout <<
“rv1 = “ << rv1 << endl;
// check value of getNumUsers
cout <<
“numUsers = “;
cout <<
myLibrary.getNumUsers() << endl;
// call
readRatings again
int rv2
=
myLibrary.readRatings(“ratingFile.txt”);
cout <<
“rv2 = “ << rv2 << endl;
Output
numUsers = 98
rv1 = 100
numUsers = 100
rv2 = -2
Problem 4 - the member function getRating
The member function getRating accepts the given a user’s name and a book’s title, and returns the rating that the user gave for that book.
• Your function MUST be named getRating.
• Your function should take 2 input arguments in the following order:
◦ string: username
◦ string: title of the book
• The username and book title search should be case insensitive. For example, “Ben, “ben” and “BEN” are one and the same user.
• If both the user name and the book title are found, then the function should return the user’s rating value for that book title.
• The function should return the following values depending on cases:
◦ Return the rating value if both user and title are found
◦ Return -3 if either the user or the title are not found
Set up for the examples below
bookFile.txt
Author1,Title1
Author2,Title2
Author3,Title3
ratingFile.txt
User1,1,4,2
User2,0,5,3
//Create a new Library
Library myLibrary;
//add books to Library
myLibrary.readBooks(“bookFile.txt”);
//add users to Library
myLibrary.readRatings(“ratingFile.txt”);
Example 1: Both the userName and bookTitle exists, and the value of rating is non-zero, returns the value of the given user’s rating for the given book
Function call
getRating("User1", "Title2");
Return value
4
Example 2:The userNamedoes not exist, it returns - 3
Function call
getRating("User4", "Title1");
Return value
-3
Example 3:The bookTitledoes not exist, it returns - 3
Function call
getRating("User1", "Title10");
Return value
-3
Example 4:The userNameand the bookTitledo not exist, returns -3
Function call
getRating("User12", "Title10");
Return value
-3
Problem 5 - the member function getCountReadBooks
The member function getCountReadBooks which determines how many books a particular user has read and reviewed. This function should:
• Accept one argument:
◦ string: username
• The username and book title search should be case insensitive. For example, “Ben, “ben” and “BEN” are one and the same user.
• The function should return the following values depending on cases:
◦ Return the number of books read/reviewed by the specified user if user is found
◦ Return -3 if the username is not found
Example 1: The library is initialized
bookFile.txt
Author1,Title1
Author2,Title2
Author3,Title3
ratingFile.txt
User1,1,4,2
User2,0,5,3
User3,0,0,0
Function calls
//Create a new Library
outputs
Library myLibrary;
//add books to Library myLibrary.readBooks(“bookFile.txt”);
//add users
myLibrary.readRatings(“ratingFile.txt”);
// viewRatings for User2
cout << myLibrary.getCountReadBooks(“User2”);
2
Example 2: The user does not exist
bookFile.txt
Author1,Title1
Author2,Title2
Author3,Title3
ratingFile.txt
User1,1,4,2
User2,0,5,3
User3,0,0,0
Function calls
//Create a new Library
Library myLibrary;
//add books to Library
myLibrary.readBooks(“bookFile.txt”);
//add users
myLibrary.readRatings(“ratingFile.txt”);
cout << myLibrary.getCountReadBooks(“User4”);
outputs
-3
Example 3: The user has not rated any book yet
bookFile.txt
Author1,Title1
Author2,Title2
Author3,Title3
ratingFile.txt
User1,1,4,2
User2,0,5,3
User3,0,0,0
Function calls
//Create a new Library
Library myLibrary;
//add books to Library
myLibrary.readBooks(“bookFile.txt”);
//add users
myLibrary.readRatings(“ratingFile.txt”);
// getCountReadBooks for User3
cout << myLibrary.getCountReadBooks(“User3”);
outputs
0
Problem 6 - the member function viewRatings
Create a new member function viewRatingsprints all the books a user has provided ratings for. Recall that a rating a book 0 means a user has not rated that book and hence shouldn’t be displayed. This function should:
• Accept one input argument:
◦ string: username
• Not return anything.
• If the user is not found in the database, print:
<username> does not exist.
• If the user is found in the database, but has not rated any books, print:
<username> has not rated any books yet.
• If the user exists in the database, and has rated at least one book, display the user’s ratings in the following format:
Expected output (assuming you have read the data onlyfrom books.txt,ratings.txt)
Here are the books that megan rated
Title : The Hitchhiker's Guide To The Galaxy
Rating : 5
-----
Title : The Five People You Meet in Heaven
Rating : 2
-----
(...)
Example 1: The library is initialized
bookFile.txt
Author1,Title1
Author2,Title2
Author3,Title3
ratingFile.txt
User1,1,4,2
User2,0,5,3
User3,0,0,0
Function calls
//Create a new Library
Library myLibrary;
//add books to Library
myLibrary.readBooks(“bookFile.txt”);
//add users
myLibrary.readRatings(“ratingFile.txt”);
myLibrary.viewRatings(“User2”);
outputs
Here are the books that User2 rated
Title : Title2
Rating : 5
-----
Title : Title3
Rating : 3
-----
Example 2: The user has not rated any book yet
bookFile.txt
Author1,Title1
Author2,Title2
Author3,Title3
ratingFile.txt
User1,1,4,2
User2,0,5,3
User3,0,0,0
Function calls
//Create a new
Library
Library myLibrary;
//add books to
Library
myLibrary.readBooks(“bookFile.txt”);
//add users
myLibrary.readRatings(“ratingFile.txt”);
myLibrary.viewRatings(“User3”);
outputs
User3 has not rated any books yet.
Example 3: The user does not exist
bookFile.txt
Author1,Title1
Author2,Title2
Author3,Title3
ratingFile.txt
User1,1,4,2
User2,0,5,3
User3,0,0,0
Function calls
//Create a new
Library
Library myLibrary;
//add books to
Library
myLibrary.readBooks(“bookFile.txt”);
//add users
myLibrary.readRatings(“ratingFile.txt”);
myLibrary.viewRatings(“User4”);
outputs
User4 does not
exist.
Problem 7 - the member function calcAvgRating
The member function calcAvgRating returns the average (mean) rating for a particular book. This function should:
• Accept one argument:
◦ string: book title
• The book title search should be case insensitive. For example, “Ben, “ben” and “BEN” are one and the same user.
• The average rating is calculated by the sum of non-zero rating values divided by the number of non-zero ratings.
• The function should return the following values depending on cases:
◦ Return the average rating of the specified book as a doubleif title is found
◦ Return -3 if title is not found
◦ Return 0 if the book has not been read by anyone. Poor book!
Note: Books that haven’t been read (have a rating value of 0) shouldn’t be counted in calculating the average.
Example 1: The library is initialized, and we can calculate an average ratings for the book.
bookFile.txt
Author1,Title1
Author2,Title2
Author3,Title3
ratingFile.txt
User1,1,4,2
User2,0,5,3
User3,0,0,0
Function calls
//Create a new Library
Library myLibrary;
//add books to Library
myLibrary.readBooks(“bookFile.txt”);
//add users
myLibrary.readRatings(“ratingFile.txt”);
// calcAvgRating for Title2
cout << myLibrary.calcAvgRating(“title2”);
outputs
4.5
The function returns 4.5 because User 1 rated 4 and User 2 rated 5, which means (4 + 5) / 2 = 4.5. Since User 3’s rating is 0, it is not included for the calculation.
Example 2: The title does not exist in the library. No user has read a particular title
bookFile.txt
Author1,Title1
Author2,Title2
Author3,Title3
ratingFile.txt
User1,0,4,2
User2,0,5,3
User3,0,0,0
Function calls
//Create a new Library
Library myLibrary;
//add books to Library
myLibrary.readBooks(“bookFile.txt”);
//add users
myLibrary.readRatings(“ratingFile.txt”);
// calcAvgRating for Title4
cout << myLibrary.calcAvgRating(“Title4”);
// calcAvgRating for Title1
cout << myLibrary.calcAvgRating(“Title1”);
outputs
-3
0
Problem 8 - the member function addUser
The member function addUseradds a new user to the database. This function should:
• Accept one argument:
◦ string: user name
• The user name is case insensitive (e.g. Ben. BEN, ben are all same as ben)
• Fill in the usernameand ratingsdata members for a Userobject, at the first unused position in the array of Userobjects.
• Be sure to update the total number of users in the system
• The function returns following one of the following integer values:
◦ Return 1 if the user is successfully added.
◦ Return 0 if the username already exists in the usersarray.
◦ Return -2 if the usersarray is already full.
Example 1: Successfully user is added to the usersarray.
ratingFile.txt
User1,1,4,2
User2,0,5,3
User3,0,0,0
Function calls
//Create a new Library
Library myLibrary;
myLibrary.readRatings(“ratingFile.txt”);
// checking the user count
cout << “numUsers = ” << myLibrary.getNumUsers()
<< endl;
//add users
cout << myLibrary.addUser(“User4”);
// checking the user count
cout << “numUsers = ” << myLibrary.getNumUsers()
<< endl;
outputs
numUsers = 3
1
numUsers = 4
Note that at this point, there are 4 users in the system, and User3 and User4 both have all 0 ratings associated with them.
Example 2: The username already exists in the users array (and is case-insensitive)
ratingFile.txt
User1,1,4,2
User2,0,5,3
User3,0,0,0
Function calls
//Create a new Library
Library myLibrary;
outputs
//add users
myLibrary.readRatings(“ratingFile.txt”);
//add users
cout << myLibrary.addUser(“user2”);
0
Example 3: The usersarray is full
Function calls
//Create a new Library
Library myLibrary;
//add books to Library
myLibrary.readBooks(“bookFile.txt”);
//add users
myLibrary.readRatings(“100UsersFile.txt”);
// check value of getNumBooks
cout << “numUsers = “;
cout << myLibrary.getNumUsers() << endl;
// add users
cout << myLibrary.addUser(“user4”);
outputs
numUsers = 100
-2
Problem 9 - the member function checkOutBook
The member function checkOutBookupdates the rating of the book for the user. This function should:
• Accept three arguments in this order
◦ string: username
◦ string: book title
◦ int: new rating
• Find the index of the user and the index for the book, then update the new rating if the new rating value is valid. The rating scheme follows the one provided in homework 6.
Rating
Meaning
0
Did not read
1
Hell No - hate it!!
2
Don’t like it.
3
Meh - neither hot nor cold
4
Liked it!
5
Mind Blown - Loved it!
• The username and book title search should be case insensitive. For example, “Ben, “ben” and “BEN” are one and the same user.
• The function returns the following integer value depending the cases (with the following order of precedence):
◦ Return 1 if the rating is successfully updated
◦ Return -4 if the rating value is not valid
◦ If the rating value is valid, but the user or title do not exist in the database, this function should return -3.
Set up for the examples below
bookFile.txt
Author1,Title1
Author2,Title2
Author3,Title3
ratingFile.txt
User1,1,4,2
User2,0,5,3
User3,0,0,0
Set up
//Create a new Library
Library myLib;
myLib.readBooks(“bookFile.txt”);
myLib.readRatings(“ratingFile.txt”);
Example 1: User successfully checks out a book and updates an existing rating.
Set up
int oldRating = myLib.getRating("User2", "Title1");
int rv = myLib.checkOutBook(“User2”, “Title1”, 2);
int newRating = myLib.getRating("User2", "Title1");
cout << “rv = “ << rv << endl;
cout << “oldRating = “ << oldRating << endl;
cout << “newRating = “ << newRating << endl;
outputs
rv = 1
oldRating = 0
newRating = 2
Example 2: The
rating value is invalid
Set up
int oldRating = myLib.getRating("User2", "Title1");
int rv = myLib.checkOutBook(“User2”, “Title1”, 10);
int newRating = myLib.getRating("User2", "Title1");
cout << “rv = “ << rv << endl;
cout << “oldRating = “ << oldRating << endl;
cout << “newRating = “ << newRating << endl;
outputs
rv = -4
oldRating = 0
newRating = 0
Since the rating value is invalid, User2’s Title1 rating should stay the same.
Example 3: title is not found
Function calls int rv = myLib.checkOutBook(“User2”, “noTitle”, 1);
cout << “rv = “ << rv << endl;
outputs
rv = -3
Example 4: user is not found
Function calls int rv = myLib.checkOutBook(“noUser”, “title1”, 2); cout << “rv = “ << rv << endl;
outputs
rv = -3
Problem 10 - the member function getRecommendations
The member function getRecommendationswill recommend book titles a user might enjoy, based on the book ratings of another user who likes similar books. This function should:
• Accept one input argument:
◦ string: username
• Not return anything.
• Find the user with the given username, and print some book recommendations to the screen. (Details on how to recommend books are given below.)
• The username search should be case insensitive. For example, “Ben, “ben” and “BEN” are one and the same user.
• If the user name is not found, it should print the following message :
<username> does not exist.
● Ifthere are no books to recommend for the user, print the following:
There are no recommendations for <username> at present.
• If there is at least one book to recommend for a certain user, print the following information for at most five books:
Here is the list of recommendations <book_title_1> by <author1> <book_title_2> by <author2>
…
…
<book_title_5> by <author5>
How to find books to recommend?
The recommendations for a given user will be based on the other user who is most similar to that user. To generate recommendations, for example, for a user named Ben:
1. Find the most similar user to Ben. Let’s say we found Claire to be most similar.
2. Recommend to Ben the first 5 books in the database Claire has rated with a rating of 3, 4 or 5, that Ben has not yet read (rating 0).
3. If there are fewer than 5 books to recommend, recommend as many as possible. Ben will be presented with between 0 and 5 recommendations.
In order to compare two users and calculate their similarity, we will be looking at the rating values for all the books for both users (regardless of whether a user has read a book or not), and calculating the difference in their ratings. Because our similarity metric is based on difference, more similar users will have smaller similarity values. Therefore, when Ben is compared to all other users in the database, the user whose similarity score with Ben is smallestwill be the most similar user (Claire).
Note 1: A new user, who has not rated any books, cannot be chosen as the most similar user. The getCountReadBooks function can be used to weed out the new users.
Note 2: In the event of a tie between two users for being the most similar to the user you are making recommendations for, make recommendations using the user with the lowerindex within the users array.
The similarity metric you should use is the sum of squared differences (SSD). The sum of squared differences is calculated by summing the squares of the differences between corresponding elements in two ratings arrays from two users. Follow the example below.
Let Arepresent ben's ratings, and Brepresent claire's ratings.
Ais ben's rating for book i, and Bis claire's rating for book i
i i
Example 1 : Calculating SSD
john′s ratings : [0, 1, 3, 5]
claire′s ratings : [3, 0, 5, 0]
SSD=(0−3)2 +(1−0)2+(3−5)2+ (5−0)2
SSD = (−3)2 + (1)2 + (−2)2 + (5)2
SSD=9+1+4+25=39
Example 2: Users with very different ratings will get a high SSD.
john′s ratings : [5, 1, 0, 0, 5]
david′s ratings : [1, 5, 0, 5, 1]
SSD=(5−1)2 +(1−5)2+(5−0)2+(5−1)2
SSD= 42 +42+52+42
SSD=16+16+25+16= 73
Example 3: Two users with very similar ratings will get a low SSD.
john′s ratings : [5, 0, 5, 3]
claire′s ratings : [5, 0, 4, 2]
SSD = (5 −5)2 + (5 − 4)2+ (3 − 2)2
SSD=02+12+ 12
SSD=0+1+1=2
For example (this example is different than the data in ratings.txt):
Let's say we're generating recommendations for John. Here are the books:
Douglas Adams,The Hitchhiker's Guide To The Galaxy Richard Adams,Watership Down
Mitch Albom,The Five People You Meet in Heaven Laurie Halse Anderson,Speak
Liz: [5, 1, 5, 3]
John: [5, 0, 3, 0]
David: [4, 1, 0, 5]
To generate recommendations for John:
1. find the most similar user
John has a SSD of 14 with Liz, and an SSD of 36 with David, so John is more similar to Liz. Thus, our book recommendations will be based on Liz’s ratings.
2. find 5 books Liz (the most similar user) has rated as a 3, 4, or 5 that John has not yet read (rating 0)
We look at Liz's ratings to find books that she has rated that John has not:
◦ Liz has rated The Hitchhiker's Guide To The Galaxy as 5, but John has already rated this book.
◦ Liz has rated Watership Down as 1. John hasn't read that book yet, but the rating value of 1 is lower than 3, so we do not add it to the list of recommendations.
◦ Liz has rated The Five People You Meet in Heaven as 5, but John has already rated this book.
◦ Liz has rated Speak as 3. John has not yet read that book, so we add it to the list of recommendations.
◦ There are no more books that Liz has rated, so we're done. Our final list of recommendations will be:
Speak by Laurie Halse Anderson
Set-up for the examples:
bookFile.txt
Author1,Title1
Author2,Title2
Author3,Title3
Author4,Title4
Author5,Title5
ratingFile.txt
User1,5,4,2,3,1
User2,5,5,3,2,0
User3,0,0,0,0,0
User4,0,0,0,0,0
User5,5,0,2,3,0
Set-up
//Create a new Library
Library myLib;
myLib.readBooks(“bookFile.txt”);
myLib.readRatings(“ratingFile.txt”);
Example 1: There are books to recommend
Function call
myLib.getRecommendations("User5");
outputs
Here are the list
of recommendations
Title2 by Author2
The best matched user for User5 is User1, with SSD = 17. Title2 is the only book to recommend because that is the only book User5 has not rated and User1 rated at least a 3.
Example 2: No books to recommend
Function call
myLib.getRecommendations("User2");
outputs
There are no recommendations for User2 at present
The best matched user for User2 is User1, with SSD = 4. The only book User2 has not read is Title5, but it cannot be recommended because User2 rated it as 1. Hence, no books to recommend.
Example 3: The most similar user has not rated any book. So need to find the second most similar user
Function call
myLib.getRecommendations("User4");
outputs
Here are the list of recommendations
Title1 by
Author1
Title4 by
Author4
The SSD score between User4 and User3 is 0. However, since the User3 has not rated any books, we need to find the other most similar user. The best matched user for User4 is User5, with SSD = 38. We will recommend Title1 and Title4.
4.2. Driver
(30 points in codeRunner)
Problem 11 - Driver function
Now, let’s modify our HW7.cpp from Homework 7 to use the Book class, User class, and Library class we have updated/created for Project 2. Make a copy of your old HW7.cpp
and rename it to project2.cpp, to modify for this problem so we can show off to our enemies how much cool stuff we’re doing!
Since we’ve added some other functionality to our driver routine, we will need to update some of the menu functionality. Download the Project2Template.cppto update your displayMenufunction, as well as some other print statements.
The zip file submission should have five files for this problem: Book.h, Book.cpp, User.h, User.cpp, Library.h, Library.cpp, and a driver called project2.cpp, with a main() function to test your menu interface. Note that the submitted project2.cpp file should not have the class definitions in it. They should be contained in their respective modules (Book.h+Book.cpp, User.h+User.cpp, Library.h+Library.cpp, ) and #include’ed in project2.cpp.
For Coderunner, however, paste your entire project2.cpp driver function with the class definitions. You need to submit the the entire program project2.cpp, including the Book, User, and Library classes, in the answer box of the Coderunner auto-grader on Moodle.
The menu will run on a loop, continually offering the user eleven options until they opt to quit. You need to fill in the code for each of the options. You should make use of the functions you wrote previously, call them, and process the values they return.
• Option 1: Initialize library
◦ Prompt the user for a file name.
◦ Pass the file name to your readBooksfunction.
◦ Print the total number of books in the database in the following format:
▪ Total books in the database: <numberOfBooks>
◦ If the function returned -1, then print the following message:
▪ No books saved to the database.
◦ If the function returned -2, print
▪ Database is already full. No books were added.
◦ When numBooksis equal to size of the array print the following message:
▪ Database is full. Some books may have not been added.
• Option 2: Initialize user catalog
◦ Prompt the user for a file name.
◦ Pass the file name to your readRatingsfunction
◦ Print the total number of users in the database in the following format:
▪ Total users in the database: <numUsers>
◦ If the function returned -1, then print the following message:
▪ No users saved to the database.
◦ If the function returned -2, print
▪ Database is already full. No users were added.
◦ When numUsersis equal to size of the array print the following message:
▪ Database is full. Some users may have not been added.
• Option 3: Display library
◦ If the database has not been initialized (i.e., arrays of books and users/ratings have not yet both been read in), then print
▪ Database has not been fully initialized.
◦ Otherwise, call your printAllBooksfunction.
• Option 4: Get a rating
◦ If the database has not been initialized, print
▪ Database has not been fully initialized.
◦ Otherwise:
▪ Prompt the user for a username.
▪ Prompt the user for a title
▪ Pass the username and the title to your getRatingfunction
◦ If the user exists in the system, print the result in the following format:
▪ <name> rated <title> with <rating>
◦ If the function returns 0, print the result in the following format:
▪ <name> has not rated <title>
◦ If the function returns -3, print the result in the following format:
▪ <name> or <title> does not exist.
• Option 5: Get number of books the user has rated
◦ If the database has not been initialized, print
▪ Database has not been fully initialized.
◦ Otherwise:
▪ Prompt the user for a username.
▪ Pass the username to your getCountReadBooksfunction
◦ If the user exists in the system and has rated some books:
▪ <name> rated <number> books.
◦ If the function returns 0, print the result in the following format:
▪ <name> has not rated any books.
◦ If the function returns -3, print the result in the following format:
▪ <name> does not exist.
• Option 6: View user’s ratings
◦ If the database has not been initialized, print
▪ Database has not been fully initialized.
◦ Otherwise:
▪ Prompt the user for a username.
▪ Pass the username to your viewRatingsfunction
• Option 7: Calculate the average rating for the book
◦ If the database has not been initialized, print
▪ Database has not been fully initialized.
◦ Otherwise:
▪ Prompt the user for a title.
▪ Pass the title to your calcAvgRatingfunction
◦ If the title exists in the system, display the average ratings in two decimal places:
▪ The average rating for <title> is <avg rating>
◦ If the function returns -3, print the result in the following format:
▪ <title> does not exist.
• Option 8: Add a user to the database.
◦ Prompt the user for a username.
◦ Pass the username to your addUserfunction
◦ If the user is successfully added (the function returns 1), the print
▪ Welcome to the library <username>
◦ If the username exists in the system (the function returns 0), print
▪ <username> already exists in the database.
◦ If the function returns -2, print the result in the following format:
▪ Database is already full. <username> was not added.
• Option 9: Check out the book
◦ If the database has not been initialized, print
▪ Database has not been fully initialized.
◦ Otherwise:
▪ Prompt the user for a username.
▪ Prompt the user for a title.
▪ Prompt the user for a new rating.
▪ Pass the username, title, and rating to your checkOutBook function
◦ If the user is successfully added (the function returns 1), the print
▪ We hope you enjoyed your book. The rating has been updated.
◦ If the function returns -4, print:
▪ <rating> is not valid.
◦ If the function returns -3, print:
▪ <name> or <title> does not exist.
• Option 10: get recommendations
◦ If the database has not been initialized, print
▪ Database has not been fully initialized.
◦ Otherwise:
▪ Prompt the user for a username.
▪ Pass the username to your getRecommendationsfunction
• Option 11: Quit
◦ Print “good bye!”before exiting
5. Project 2 checklist
Here is a checklist for submitting the assignment:
1. Complete the code Project 2 Coderunner
2. Submit one zip file to Project 2 (File Submission). The zip file should be named, <firstName>_<lastName>_project2.zip., and have following 7 files:
1. Book.h
2. Book.cpp
3. User.h
4. User.cpp
5. Library.h
6. Library.cpp
7. project2.cpp
3. Sign up to the interview grading slot on Moodle. Please make sure that you sign-up and complete an interview grading with your TA by Monday, April 15. The schedulers for interview grading will be available after the deadline of this project.
You are allowed to reschedule an interview grading session without any penalty once during the semester. If you miss a second time, you may reschedule but there will be a 25-point (out of 100) penalty, then 50 points for the third time.
6. Project2 point summary
Criteria
Pts
Coderunner
Interview grading
Style and Comments
Algorithms
Recitation attendance (Mar 19 or Mar 21)*
Not using Library class in the driver
Using global variables
Total
180
60
5
5
-50
-30
-5
250
* If your attendance is not recorded, you will lose points.
Make sure your attendance is recorded on Moodle before you leave recitation.