Users can enter codes via a web site, or they can register one or more cell phones with their account, and then they can text codes from a given phone number, which will register the points.
Rad is handling the business and marketing end of this endeavor, and Banjolina is doing all of the web programming. Your job is to write the server that maintains information about users, prizes and codes, and talks with Banjolina's web front-end. Since you haven't taken CS360 yet, your server won't do any real networking. Instead, it will communicate via files and standard input.
As with many of our labs, I give you a header file that defines a class, and you have to implement the methods. I have a driver program that you compile with your code, and that will be the final product.
Here's the header, in include/code_processor.hpp. Unlike the previous labs, there is no commenting here. I have explanations below.
#include <set> #include <map> #include <unordered_map> #include <unordered_set> #include <string> class User { public: std::string username; std::string realname; int points; std::set <std::string> phone_numbers; }; class Prize { public: std::string id; std::string description; int points; int quantity; }; class Code_Processor { public: bool New_Prize(const std::string &id, const std::string &description, int points, int quantity); bool New_User(const std::string &username, const std::string &realname, int starting_points); bool Delete_User(const std::string &username); bool Add_Phone(const std::string &username, const std::string &phone); bool Remove_Phone(const std::string &username, const std::string &phone); std::string Show_Phones(const std::string &username) const; int Enter_Code(const std::string &username, const std::string &code); int Text_Code(const std::string &phone, const std::string &code); bool Mark_Code_Used(const std::string &code); int Balance(const std::string &username) const; bool Redeem_Prize(const std::string &username, const std::string &prize); ~Code_Processor(); bool Write(const std::string &filename) const; void Double_Check_Internals() const; /* You don't write this */ protected: std::unordered_map <std::string, User *> Names; std::unordered_map <std::string, User *> Phones; std::unordered_set <std::string> Codes; std::unordered_map <std::string, Prize *> Prizes; }; |
While this looks like a mouthful, it's really not that bad. Users store the following data:
Prizes store the following data:
A Code_Processor keeps track of Users, Codes and Prizes. Users are stored in the unordered_map Names, which is keyed on their usernames. Phone numbers are stored in the unordered_map Phones, which is keyed on the phone numbers, and whose second field points to the user that has registered the cell phone.
There is an unordered_set Codes, which stores the codes that have been entered by all users. This unordered_set exists so that users can't enter a code more than once. Finally, there is a unordered_map Prizes, keyed on the id of each prize.
You'll note that both Names and Phones point to users. In other words, each user has just one User instance, and that is pointed to both in Names and in Phones. If the user has multiple phones, then there will be multiple entries in Phones that point to that user. Moreover, there are two data structures that hold phones -- Phones, which is keyed on the phone number, and the set phone_numbers which is part of the User's data.
Now, you are to write the following methods (I'm omitting the const declarations here, to keep the writeup uncluttered. Obviously, you can see the const declarations in the header):
(BTW, you can use the implementation of djb_hash that's in src/random_codes.cpp.)
Otherwise, the following commands are supported:
The format of Write() should be as a file that cp_tester can use as input to recreate the state of the Code_Processor. It should only consist of ADD_USER, PRIZE, ADD_PHONE and MARK_USED lines, and when cp_tester is run with the file as input, it should recreate the state of the Code_Processor.
I don't care about the order or format of the lines, as long as they create the proper Code_Processor when they are fed to cp_tester. My grading program will test your files by using them as input to my cp_tester and looking at the output of my Write() call.
UNIX> bin/cp_tester - CP_Tester> ADD_USER tigerwoods 0 Tiger Woods ADD_USER successful CP_Tester> ADD_USER the-donald 100 Donald Trump ADD_USER successful CP_Tester> PRIZE mp3 40 5000 Free MP3 download from Bapster PRIZE successful CP_Tester> PRIZE cancun 10000 1 All expense-paid vacation to Cancun PRIZE successful CP_Tester> WRITE cp1.txt WRITE successful CP_Tester> QUIT UNIX> cat cp1.txt PRIZE cancun 10000 1 All expense-paid vacation to Cancun PRIZE mp3 40 5000 Free MP3 download from Bapster ADD_USER the-donald 100 Donald Trump ADD_USER tigerwoods 0 Tiger Woods UNIX>I've added two prizes and two users, and then written the server's state to cp1.txt. You'll note that the order of cp1.txt is different from my input. That's fine -- if you use it as input to cp_tester, it will create the same server state. For example:
UNIX> bin/cp_tester cp1.txt - CP_Tester> BALANCE tigerwoods 0 Points CP_Tester> BALANCE the-donald 100 Points CP_Tester> WRITE cp2.txt WRITE successful CP_Tester> QUIT UNIX> cat cp2.txt PRIZE cancun 10000 1 All expense-paid vacation to Cancun PRIZE mp3 40 5000 Free MP3 download from Bapster ADD_USER the-donald 100 Donald Trump ADD_USER tigerwoods 0 Tiger Woods UNIX>When I called cp_tester, I gave it two command line arguments: cp1.txt and -. So, it first read commands from cp1.txt, which recreated the same state as when I created cp1.txt, and then it read from standard input. When I entered WRITE cp2.txt, it created cp2.txt, which is identical to cp1.txt, since they have the same state.
Suppose I call cp_tester with cp1.txt and cp2.txt on the command line. I should expect four error messages, since the users and prizes already exist when it tries to process cp2.txt:
UNIX> bin/cp_tester cp1.txt cp2.txt Prize cancun couldn't be added Prize mp3 couldn't be added ADD_USER the-donald unsuccessful ADD_USER tigerwoods unsuccessful UNIX>This is because cp_tester checks the return values of the New_Prize() and New_User() calls.
Let's add a few phone numbers and enter some codes. If you check the hashes using djbhash.cpp from the hashing lecture notes, you'll see that they are each divisible by 13 and not by 17, so they are each worth three points:
UNIX> /home/jplank/cs202/Notes/Hashing/bin/djbhash | awk '{ print $1%17, $1%13 }' Df18ly81CO1mo4 11 0 IDWNZJ20ENkAxP 2 0 h0yuKnVD6DvRUu 11 0 UNIX> bin/cp_tester cp1.txt - CP_Tester> ADD_PHONE tigerwoods 865-974-4400 ADD_PHONE successful CP_Tester> ADD_PHONE tigerwoods 1-800-Big-Putt ADD_PHONE successful CP_Tester> SHOW_PHONES tigerwoods 1-800-Big-Putt 865-974-4400 CP_Tester> ENTER_CODE tigerwoods Df18ly81CO1mo4 ENTER_CODE: Added 3 points to tigerwoods. CP_Tester> TEXT_CODE 865-974-4400 IDWNZJ20ENkAxP TEXT_CODE: Added 3 points. CP_Tester> TEXT_CODE 1-800-Big-Putt h0yuKnVD6DvRUu TEXT_CODE: Added 3 points. CP_Tester> BALANCE tigerwoods 9 Points CP_Tester> WRITE cp3.txt WRITE successful CP_Tester> QUIT UNIX>Each ENTER_CODE and TEXT_CODE call adds three points to tigerwoods' account, giving him 9 points in all. After the WRITE call, cp3.txt looks as follows:
PRIZE cancun 10000 1 All expense-paid vacation to Cancun PRIZE mp3 40 5000 Free MP3 download from Bapster ADD_USER the-donald 100 Donald Trump ADD_USER tigerwoods 9 Tiger Woods ADD_PHONE tigerwoods 1-800-Big-Putt ADD_PHONE tigerwoods 865-974-4400 MARK_USED Df18ly81CO1mo4 IDWNZJ20ENkAxP h0yuKnVD6DvRUu |
The phones have been registered to tigerwoods, his point total has been updated, and the codes have been marked as used. Although I put multiple codes on a MARK_USED line, you don't have to. Just remember the 20-word limit on a line.
And again, your output does not have to match mine -- it simply needs to create the same Code_Processor.
Let's take a look at an example where some prizes are redeemed:
UNIX> bin/cp_tester cp3.txt - CP_Tester> ADD_USER billgates 500000 Bill Gates ADD_USER successful CP_Tester> REDEEM tigerwoods mp3 REDEEM: either the user doesn't exist, or the prize doesn't exist, or the user can't afford the prize. CP_Tester> REDEEM the-donald mp3 REDEEM successful CP_Tester> REDEEM billgates cancun REDEEM successful CP_Tester> WRITE cp4.txt WRITE successful CP_Tester> QUIT UNIX> cat cp4.txt PRIZE mp3 40 4999 Free MP3 download from Bapster ADD_USER billgates 490000 Bill Gates ADD_USER the-donald 60 Donald Trump ADD_USER tigerwoods 9 Tiger Woods ADD_PHONE tigerwoods 1-800-Big-Putt ADD_PHONE tigerwoods 865-974-4400 MARK_USED Df18ly81CO1mo4 IDWNZJ20ENkAxP h0yuKnVD6DvRUu UNIX>Since tigerwoods only has 9 points, he can't even afford an MP3 from Bapster. the-donald has no such problem, and billgates can easily afford the Cancun vacation (like he needs it). The updated points for the users and the updated quantities for the prizes have been reflected in the file. Since the quantity of cancun went to zero, it has been removed from the system.
The first thing you should do is implement New_Prize(), and then implement the part of the Write() method that creates the file and stores the prizes. Test this by only making PRIZE and WRITE calls in cp_tester.
Then move onto the others. I implemented these in the following order:
UNIX> /home/jplank/cs202/Labs/Lab7/bin/cp_tester /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-*.txt
UNIX> bin/cp_tester /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-*.txt
UNIX> /home/jplank/cs202/Labs/Lab7/bin/cp_tester f1.txt
What that does is create the file your_dir/f1.txt with my program, but using your f1.txt as input. Now your_dir/f1.txt should match correct_dir/f1.txt exactly.
UNIX> ls /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-*.txt /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-A.txt /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-B.txt UNIXLet's look at the first -- as you can see, it adds prizes, users and phones, and it sets a bunch of codes as marked:
UNIX> cat /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-A.txt PRIZE cancun 10000 1 All Expense-Paid trip to Cancun PRIZE dogo 570 3 Club Dogo 12-Month Subscription PRIZE habitat 35 100 Donation to Habitat for Humanity PRIZE silver 1100 2 Two DMC Theatres Silver Experience movie tickets PRIZE spinner 750 4 Multi-Function Salad Spinner and Chopper ADD_USER ACamelb30 45158 Arianna Camelback ADD_PHONE ACamelb30 590-448-0257 ADD_PHONE ACamelb30 596-598-2816 ADD_PHONE ACamelb30 702-497-7232 ADD_USER AChurn40 21934 Audrey Churn ADD_PHONE AChurn40 235-294-7081 ADD_PHONE AChurn40 361-551-5980 ADD_PHONE AChurn40 597-919-8261 ADD_USER ADuctil93 882 Anthony Ductile ADD_PHONE ADuctil93 375-449-4138 ADD_PHONE ADuctil93 509-904-5217 ADD_PHONE ADuctil93 644-036-2649 ADD_USER AFluenc43 682 Andrew Fluency PhD ADD_PHONE AFluenc43 495-712-4764 ADD_PHONE AFluenc43 737-246-2569 ADD_USER AInterv57 13 Aiden Interval ADD_PHONE AInterv57 081-142-5426 ADD_PHONE AInterv57 183-790-7235 ADD_PHONE AInterv57 855-670-4758 ADD_USER AJugate14 38987 Austin Jugate ADD_PHONE AJugate14 174-351-3757 ADD_PHONE AJugate14 610-205-1413 ADD_PHONE AJugate14 856-562-1336 ADD_USER BBonifa55 93 Brianna Boniface ADD_PHONE BBonifa55 008-672-3102 ADD_USER CBarge68 24776 Chase Barge ADD_USER DIneffi14 37842 Daniel Inefficient ADD_PHONE DIneffi14 029-131-8159 ADD_PHONE DIneffi14 462-602-7283 ADD_PHONE DIneffi14 569-485-8923 ADD_USER GMax14 235 Gabriel Max Set ADD_PHONE GMax14 556-830-7531 ADD_USER IParks92 696 Isaac Parks ADD_PHONE IParks92 119-480-9038 ADD_PHONE IParks92 177-181-8465 ADD_USER JEcho91 11706 James Echo ADD_USER NSvelte62 59 Noah Svelte ADD_USER OMauve70 6464 Oliver Mauve ADD_PHONE OMauve70 120-797-9587 ADD_PHONE OMauve70 364-503-8235 ADD_PHONE OMauve70 451-559-9059 ADD_USER TVade56 2 Taylor Vade ADD_PHONE TVade56 355-887-8304 ADD_PHONE TVade56 606-440-6857 ADD_PHONE TVade56 914-780-5061 MARK_USED 6ZzSTTdUaCDy6N 7fClHDlcNlxNpl F3W9dZq4NWCp3F jqivzc4eRM0Jt9 sHDNCtoOnMhctK UNIX>Now let's look at the second -- it performs a bunch of commands, and writes six files -- f1.txt through f6.txt
UNIX> cat /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-B.txt REDEEM ACamelb30 cancun WRITE f1.txt ADD_PHONE AEmery68 223-558-4601 REDEEM OMauve70 silver ADD_PHONE AChurn40 914-780-5061 WRITE f2.txt WRITE f3.txt REDEEM DIneffi14 silver REDEEM OMauve70 dogo REDEEM AJugate14 spinner SHOW_PHONES BBonifa55 DELETE_USER NSvelte62 ADD_USER CBarge68 21 James Sanitate WRITE f4.txt REDEEM AChurn40 dogo WRITE f5.txt TEXT_CODE 914-780-5061 AIV9qdDuoE1Lsz REMOVE_PHONE ACamelb30 590-448-0257 REDEEM AJugate14 dogo REMOVE_PHONE ACamelb30 702-497-7232 WRITE f6.txt UNIX>Let's run my program on it. There is some output, so let's examine it:
UNIX> /home/jplank/cs202/Labs/Lab7/bin/cp_tester /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-*.txt ADD_PHONE: Either the user (AEmery68) doesn't exist, or the phone number (223-558-4601) is already assigned ADD_PHONE: Either the user (AChurn40) doesn't exist, or the phone number (914-780-5061) is already assigned 008-672-3102 ADD_USER CBarge68 unsuccessful UNIX>First, let's verify the first error statement by looking for AEmery68 and 223-558-4601 in the two input files. As you can see, we try to set AEmery68's phone number, and there's no such user:
UNIX> egrep 'AEmery68|223-558-4601' /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-*.txt /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-B.txt:ADD_PHONE AEmery68 223-558-4601 UNIX>Let's verify the second error statement. Now you can see that 914-780-5061 was already assigned to TVade56.
UNIX> egrep 'AChurn40|914-780-5061' /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-*.txt /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-A.txt:ADD_USER AChurn40 21934 Audrey Churn /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-A.txt:ADD_PHONE AChurn40 235-294-7081 /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-A.txt:ADD_PHONE AChurn40 361-551-5980 /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-A.txt:ADD_PHONE AChurn40 597-919-8261 /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-A.txt:ADD_PHONE TVade56 914-780-5061 /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-B.txt:ADD_PHONE AChurn40 914-780-5061 /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-B.txt:REDEEM AChurn40 dogo /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-B.txt:TEXT_CODE 914-780-5061 AIV9qdDuoE1Lsz UNIX>The phone number 008-672-3102 was printed out. Let's look for it in the input, and when we find that it belongs to BBonifa55, let's look for BBonifa55. As you can see, we gave the command "SHOW_PHONES BBonifa55", which is what printed "008-672-3102".
UNIX> grep 008-672-3102 /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-*.txt /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-A.txt:ADD_PHONE BBonifa55 008-672-3102 UNIX> grep BBonifa55 /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-*.txt /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-A.txt:ADD_USER BBonifa55 93 Brianna Boniface /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-A.txt:ADD_PHONE BBonifa55 008-672-3102 /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-B.txt:SHOW_PHONES BBonifa55 UNIX>Last, there was an error statement: "ADD_USER CBarge68 unsuccessful". Let's grep for CBarge68, and we can see that that username existed and we tried to add it a second time.
UNIX> grep CBarge68 /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-*.txt /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-A.txt:ADD_USER CBarge68 24776 Chase Barge /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-B.txt:ADD_USER CBarge68 21 James Sanitate UNIX>Let's make the directory correct_dir and move the six files there:
UNIX> mkdir correct_dir UNIX> mv f?.txt correct_dir UNIX> ls correct_dir f1.txt f2.txt f3.txt f4.txt f5.txt f6.txt UNIX>Now, let's run the cp_tester in bin:
UNIX> bin/cp_tester /home/jplank/cs202/Labs/Lab7/Gradescript-Examples/050-*.txt ADD_PHONE: Either the user (AEmery68) doesn't exist, or the phone number (223-558-4601) is already assigned ADD_PHONE: Either the user (AChurn40) doesn't exist, or the phone number (914-780-5061) is already assigned 008-672-3102 ADD_USER CBarge68 unsuccessful UNIX>The output is identical, so that's good. However f1.txt through f6.txt don't match the ones in correct_dir, because this cp_tester implements Write() differently:
UNIX> ls -l correct_dir/f1.txt -rw-r--r--. 1 jplank jplank 2020 Oct 22 14:58 correct_dir/f1.txt UNIX> ls -l f1.txt -rw-r--r--. 1 jplank jplank 2060 Oct 22 15:07 f1.txt UNIX> head correct_dir/f1.txt PRIZE dogo 570 3 Club Dogo 12-Month Subscription PRIZE habitat 35 100 Donation to Habitat for Humanity PRIZE silver 1100 2 Two DMC Theatres Silver Experience movie tickets PRIZE spinner 750 4 Multi-Function Salad Spinner and Chopper ADD_USER ACamelb30 35158 Arianna Camelback ADD_PHONE ACamelb30 590-448-0257 ADD_PHONE ACamelb30 596-598-2816 ADD_PHONE ACamelb30 702-497-7232 ADD_USER AChurn40 21934 Audrey Churn ADD_PHONE AChurn40 235-294-7081 UNIX> head f1.txt MARK_USED 6ZzSTTdUaCDy6N MARK_USED 7fClHDlcNlxNpl MARK_USED F3W9dZq4NWCp3F MARK_USED jqivzc4eRM0Jt9 MARK_USED sHDNCtoOnMhctK ADD_USER ACamelb30 35158 Arianna Camelback ADD_PHONE ACamelb30 590-448-0257 ADD_PHONE ACamelb30 596-598-2816 ADD_PHONE ACamelb30 702-497-7232 ADD_USER AChurn40 21934 Audrey Churn UNIX>So, what I do is append "WRITE your_dir/f1.txt" to the end of f1.txt, create the directory your_dir/f1.txt and then I run my cp_tester on it. If the state of f1.txt is correct, regardless of formatting, then your_dir/f1.txt should match correct_dir/f1.txt exactly (because they were both created by my program):
UNIX> mkdir your_dir UNIX> echo "WRITE your_dir/f1.txt" >> f1.txt UNIX> /home/jplank/cs202/Labs/Lab7/bin/cp_tester f1.txt UNIX> ls -l your_dir total 4 -rw-r--r--. 1 jplank jplank 2020 Oct 22 15:14 f1.txt UNIX> diff your_dir/f1.txt correct_dir/f1.txt UNIX>I hope that helps you understand what the gradescript is doing.