Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

CS 32 – Summer 2023

Project 2:  It’s Not Just a Test, It’s a Cricket Test…Match (due Friday, July 21st a11:59:00 PM)

One thing that everyone who knows me well knows that I love sports.  Whether it’s the Lakers running it back after GM Rob Pelinka played chess from the recent trade

deadline, the Dodgers and their bullpen looking as bad and inconsistent as I’ve ever

seen, or the Rams paying for it now but having a Super Bowl to show for it, I love

following sports.  My favorite sport is baseball, as it was the first sport that I played,

watched, and loved.  As it turns out, baseball has its roots from the sport of cricket.  The reason that I even got interested in it was because I was at one of my discussion

sections for an Electrical Engineering class at 8 AM at UCLA (yes, 8 AM, not 8 PM) and  the TA was bleary-eyed and saw I was the only one there, crazy as that seems.  I asked the TA why the tiredness and I was told it was because of watching cricket.  Now,

cricket, in its original form, is a match that can go up to five days long.  Five days!  It is  the test of skill, will, and endurance, as each side waits for the others to crack one by    one by one.  Cricket has seen expanded to include one-day international and T20 over matches (including a new league in the United States called Major League Cricket).  At the heart of it, it’s a sport where the colonized (including India, the West Indies, and

Australia, among others) are getting back at the colonizers (namely, England).

To help me recreate these cricket teams (those who follow cricket will see I’ve taken the liberty of using teams and players from all formats), you will write the implementation of  the CricketTeam class using a doubly linked list, which should be sorted alphabetically   according to last name, then first name. You will also implement a couple of algorithms   that operate on the CricketTeam class.

Implement CricketTeam

Consider the following CricketTeam interface:

typedef std::string CricketType; // This can change to other types such

// as double and int, not just string

class CricketTeam

{

public:

CricketTeam();       // Create an empty CricketTeam list

bool noTeam () const;  // Return true if the CricketTeam list

// is empty, otherwise false.

int cricketerCount() const;  // Return the number of matches

// on the CricketTeam list.

bool addCricketer(const std::string& firstName, const std::string& lastName, const CricketType& value);

// If the full name (both the first and last name) is not equal  // to any full name currently in the list then add it and return // true. Elements should be added according to their last name.  // Elements with the same last name should be added according to

// their first names. Otherwise, make no change to the list and // return false (indicating that the name is already in the

// list).

bool substituteCricketer(const std::string& firstName, const std::string& lastName, const CricketType & value);

// If the full name is equal to a full name currently in the

// list, then make that full name no longer map to the value it // currently maps to, but instead map to the value of the third

// parameter; return true in this case. Otherwise, make no // change to the list and return false.

bool addOrSubstitute(const std::string& firstName, const std::string& lastName, const CricketType& value);

// If full name is equal to a name currently in the list, then

// make that full name no longer map to the value it currently

// maps to, but instead map to the value of the third parameter; // return true in this case. If the full name is not equal to

// any full name currently in the list then add it and return // true. In fact, this function always returns true.

bool releaseCricketer(const std::string& firstName, const std::string& lastName);

// If the full name is equal to a full name currently in the

// list, remove the full name and value from the list and return // true.  Otherwise, make no change to the list and return

// false.

bool rosteredOnCricketTeam(const std::string& firstName, const std::string& lastName) const;

// Return true if the full name is equal to a full name // currently in the list, otherwise false.

bool searchForCricketer(const std::string& firstName, const std::string& lastName, CricketType& value) const;

// If the full name is equal to a full name currently in the

// list, set value to the value in the list that that full name // maps to, and return true.  Otherwise, make no change to the  // value parameter of this function and return false.

bool checkTeamForCricketer(int i, std::string& firstName, std::string& lastName, CricketType & value) const;

// If 0 <= i < size(), copy into firstName, lastName and value // parameters the corresponding information of the element at

// position i in the list and return true.  Otherwise, leave the // parameters unchanged and return false. (See below for details // about this function.)

void tradeCricketTeams(CricketTeam& other);

// Exchange the contents of this list with the other one. };

The addCricketer function primarily places elements so that they are sorted in the list based on last name. If there are multiple entries with the same last name then those

elements, with the same last name, are added so that they are sorted by their first

name. In other words, this code fragment

CricketTeam rajasthanRoyals;

rajasthanRoyals.addCricketer ("Sanju", "Samson", 11);

rajasthanRoyals.addCricketer ("Jos", "Buttler", 63);

rajasthanRoyals.addCricketer ("Yashavi", "Jaiswal", 19);

rajasthanRoyals.addCricketer ("Shimron", "Hetmeyer", 189); rajasthanRoyals.addCricketer ("Trent", "Boult", 18);

rajasthanRoyals.addCricketer ("Ravichandran", "Ashwin", 99); rajasthanRoyals.addCricketer ("Yuzvendra", "Chahal", 3);

for (int n = 0; n < rajasthanRoyals.cricketerCount(); n++) {

string first;

string last;

int val;

rajasthanRoyals.checkTeamForCricketer (n, first, last,

val);

cout << first << " " << last << " " << val << endl; }

must result in the output:

Trent Boult 18

Jos Buttler 63

Yuzvendra Chahal 3

Shimron Hetmeyer 189

Yashavi Jaiswal 19

Sanju Samson 11

Notice that the empty string is just as good a string as any other; you should not treat it in any special way:

CricketTeam mumbaiIndians;

mumbaiIndians.addCricketer("Rohit", "Sharma", 36.25);

mumbaiIndians.addCricketer("Suryakumar", "Yadav", 32.75); assert(!mumbaiIndians.rosteredOnCricketTeam ("",""));

mumbaiIndians.addCricketer("Jasprit", "Bumrah", 29.5); mumbaiIndians.addCricketer("", "", 21.0);

mumbaiIndians.addCricketer("Cameron", "Green", 24.0); assert(mumbaiIndians.rosteredOnCricketTeam ("", "")); mumbaiIndians.releaseCricketer("Jasprit", "Bumrah");

assert(mumbaiIndians.cricketerCount() == 4

&& mumbaiIndians.rosteredOnCricketTeam("Rohit", "Sharma")

&& mumbaiIndians.rosteredOnCricketTeam ("Suryakumar", "Yadav")

&& mumbaiIndians.rosteredOnCricketTeam ("Cameron", "Green")

&& mumbaiIndians.rosteredOnCricketTeam ("", ""));

When comparing keys for addCricketer, substituteCricketer,

addOrSubstitute, releaseCricketer, rosteredOnCricketTeam, and

searchForCricketer, just use the == or != operators provided for the string type by the library. These do case-sensitive comparisons, and that's fine.

For this project, implement this CricketTeam interface using a doubly-linked list. (You must not use any container from the C++ library.)

For your implementation, if you let the compiler write the destructor, copy constructor, and assignment operator, they will do the wrong thing, so you will have to declare and implement these public member functions as well:

Destructor

When a CricketTeam is destroyed, all dynamic memory must be deallocated.

Copy Constructor

When a brand new CricketTeam is created as a copy of an existing CricketTeam, a deep copy should be made.

Assignment Operator

When an existing CricketTeam (the left-hand side) is assigned the value of another CricketTeam (the right-hand side), the result must be that the left-hand side object is a duplicate of the right-hand side object, with no memory leak (i.e. no memory from the old value of the left-hand side should be still allocated yet inaccessible).

Notice that there is no a priori limit on the maximum number of elements in the CricketTeam (so addOrSubstitute should always return true). Also, if a    CricketTeam has a size of n, then the values of the first parameter to the checkTeamForCricketer member function are 0, 1, 2, ..., n – 1; for other values, it returns false without setting its parameters.

Implement Some Non-Member Functions

Using only the public interface of CricketTeam, implement the following two functions. (Notice that they are non-member functions; they are not members of CricketTeam or any other class.)

bool mergeCricketers(const CricketTeam & odOne,

const CricketTeam & odTwo,

CricketTeam & odJoined);

When this function returns, odJoined must consist of pairs determined by these rules:

If a full name appears in exactly one of odOne and odTwo, then odJoined must contain an element consisting of that full name and its corresponding value.

If a full name appears in both odOne and odTwo, with the same corresponding value in both, then odJoined must contain an element with that full name and value.

When this function returns, odJoined must contain no elements other than those

required by these rules. (You must not assume odJoined is empty when it is passed in to this function; it might not be.)

If there exists a full name that appears in both odOne and odTwo, but with different

corresponding values, then this function returns false; if there is no full name like this, the function returns true. Even if the function returns false, result must be constituted as defined by the above rules.

For example, suppose a CricketTeam maps the full name to integers. If odOne consists of these three elements

"Trent" "Boult" 18 "Tim" "David" 8 "Rashid" "Khan" 19

and odTwo consists of

"Trent" "Boult" 18 "Tim" "Southee" 38 "Kane" "Williamson" 22

then no matter what value it had before, odJoined must end up as a list consisting of

"Trent" "Boult" 18 "Tim" "David" 8 "Rashid" "Khan" 19 "Tim" "Southee" 38 "Kane" "Williamson" 22

and mergeCricketers must return true.

If instead, odOne consists of

"Quinton" "DeCock" 12 "Faf" "DuPlessis" 17 "Kagiso" "Rabada" 25

and odTwo consists of

"Faf" "DuPlessis" 13 "Virat" "Kohli" 18

then no matter what value it had before, odJoined must end up as a list consisting of

"Quinton" "DeCock" 12 "Virat" "Kohli" 18 "Kagiso" "Rabada" 25

and mergeCricketers must return false.

void checkCricketers (const std::string& fsearch,

const std::string& lsearch,

const CricketTeam& odOne,

CricketTeam& odResult);

When this function returns, odResult must contain a copy of all the elements in odOne that match the search terms; it must not contain any other elements. You can wildcard

the first name, last name or both by supplying "*". (You must not assume result is empty when it is passed in to this function; it may not be.)

For example, if cricketers consists of the elements

"Rahul" "Dravid" 15 "David" "Miller" 13 "Rahul" "Tewatia" 9 "David" "Wiese" 96

and the following call is made:

checkCricketers("David", "*", cricketers, odResult);

then no matter what value it had before, odResult must end up as a CricketTeam consisting of

"David" "Miller" 13 "David" "Wiese" 96

If instead, westIndians were

"Darren" "Bravo" 46 "Dwayne" "Bravo" 47 "Kieron" "Pollard" 55

"Nicolas" "Pooran" 29

and the following call is made:

checkCricketers("*", "Bravo", westIndians, result);

then no matter what value it had before, result must end up as a list consisting of

"Darren" "Bravo" 46 "Dwayne" "Bravo" 47

If the following call is made:

checkCricketers("*", "*", westIndians, result);

then no matter what value it had before, result must end up being a copy of westIndians.

Be sure these functions behave correctly in the face of aliasing: What if westIndians and result refer to the same CricketTeam, for example?

Other Requirements

Regardless of how much work you put into the assignment, your program will receive a low score for correctness if you violate these requirements:

.    Your class definition, declarations for the two required non-member functions,

and the implementations of any functions you choose to inline must be in a file named CricketTeam.h, which must have appropriate include guards. The

implementations of the functions you declared in CricketTeam.h that you did    not inline must be in a file named CricketTeam.cpp. Neither of those files may have a main routine (unless it's commented out). You may use a separate file for the main routine to test your CricketTeam class; you won't turn in that separate file.

.    Except to add a destructor, copy constructor, assignment operator, and dump

function (described below), you must not add functions to, delete functions from, or change the public interface of the CricketTeam class. You must not declare any additional struct/class outside the CricketTeam class, and you must not

declare any public struct/class inside the CricketTeam class. You may add

whatever private data members and private member functions you like, and you may declare private structs/classes inside the CricketTeam class if you like.

The source files you submit for this project must not contain the word friend. You must not use any global variables whose values may be changed during

execution.

.    If you wish, you may add a public member function with the signature void

dump() const. The intent of this function is that for your own testing purposes, you can call it to print information about the map; we will never call it. You do not have to add this function if you don't want to, but if you do add it, it must not

make any changes to the map; if we were to replace your implementation of this function with one that simply returned immediately, your code must still work

correctly. The dump function must not write to cout, but it's allowed to write to cerr.

.    Your code must build successfully (under both g32 and either clang++ or Visual C++) if linked with a file that contains a main routine.

.    You must have an implementation for every member function of CricketTeam, as well as the non-member functions mergeCricketers and

checkCricketers. Even if you can't get a function implemented correctly, it must have an implementation that at least builds successfully. For example, if you don't have time to correctly implement

CricketTeam::releaseCricketer or checkCricketers, say, here are

implementations that meet this requirement in that they at least build successfully:

bool CricketTeam::releaseCricketer(const std::string& fname, const std::string& lname) {

return false; // not correct, but at least this code compiles }

void checkCricketers(const std::string& fsearch, const std::string&

lsearch, const CricketTeam& odOne, CricketTeam& odResult) { return; // not correct, but at least this code compiles

}

You've probably met this requirement if the following file compiles and links with your code. (This uses magic beyond the scope of CS 32.)

#include "CricketTeam.h"

#include <type_traits>

#define CHECKTYPE(f, t) { auto p = (t)(f); (void)p; }

static_assert(std::is_default_constructible<CricketTeam>::value, "Map must be default-constructible.");

static_assert(std::is_copy_constructible<CricketTeam>::value, "Map must be copy-constructible.");

void ThisFunctionWillNeverBeCalled() {

CHECKTYPE(&CricketTeam::operator=, CricketTeam&

(CricketTeam::*)(const CricketTeam&));

CHECKTYPE(&CricketTeam::noTeam, bool

(CricketTeam::*)() const);

CHECKTYPE(&CricketTeam::cricketerCount, int

(CricketTeam::*)() const);

CHECKTYPE(&CricketTeam::addCricketer, bool (CricketTeam::*)

(const std::string&, const std::string&, const

CricketType&));

CHECKTYPE(&CricketTeam::substituteCricketer, bool

(CricketTeam::*)(const std::string&, const std::string&, const CricketType&));

CHECKTYPE(&CricketTeam::addOrSubstitute, bool

(CricketTeam::*)(const std::string&, const std::string&, const CricketType&));

CHECKTYPE(&CricketTeam::releaseCricketer, bool

(CricketTeam::*)

(const std::string&, const std::string&));

CHECKTYPE(&CricketTeam::rosteredOnCricketTeam, bool

(CricketTeam::*)(const std::string&, const std::string&) const);

CHECKTYPE(&CricketTeam::searchForCricketer, bool

(CricketTeam::*)

(const std::string&, const std::string&, CricketType&) const);

CHECKTYPE(&CricketTeam::checkTeamForCricketer, bool (CricketTeam::*)

(int, std::string&, std::string&, CricketType&) const);

CHECKTYPE(&CricketTeam::tradeCricketTeams, void

(CricketTeam::*)(CricketTeam&));

CHECKTYPE(mergeCricketers,  bool (*)(const CricketTeam&,

const

CricketTeam&, CricketTeam&));

CHECKTYPE(checkCricketers, void (*)(const std::string&,

const std::string&, const CricketTeam&, CricketTeam&)); }

int main() {}

If you add #include <string> to CricketTeam.h, have the typedef define CricketType as std::string, and link your code to a file containing

#include "CricketTeam.h"

#include <string>

#include <iostream>

#include <cassert>

using namespace std;

void test() {

CricketTeam pakistanCricket;

assert(pakistanCricket.addCricketer("Mohammad", "Rizwan", "[email protected]"));

assert(pakistanCricket.addCricketer("Babar", "Azam", "[email protected]"));

assert(pakistanCricket.cricketerCount() == 2);

string first, last, e;

assert(pakistanCricket.checkTeamForCricketer(0, first, last, e) && e == "[email protected]");

assert(pakistanCricket.checkTeamForCricketer(1, first, last,

e) && (first == "Mohammad" && e ==

"[email protected]"));

return;

}

int main() {

test();

cout << "Passed all tests" << endl;

return 0;

}

the linking must succeed. When the resulting executable is run, it must write Passed all tests to cout and nothing else to cout.

If we successfully do the above, then make no changes to CricketTeam.h other than   to change the typedefs for CricketTeam so that CricketType specifies int, recompile CricketTeam.cpp, and link it to a file containing

#include "CricketTeam.h"

#include <string>

#include <iostream>

#include <cassert>

using namespace std;

void test() {

CricketTeam englandCricket;

assert(englandCricket.addCricketer("Joe", "Root", 66));

assert(englandCricket.addCricketer("Sam", "Curran", 58)); assert(englandCricket.cricketerCount() == 2);

string first, last;

int jn;

assert(englandCricket.checkTeamForCricketer(0, first, last, jn) && jn == 58);

assert(englandCricket.checkTeamForCricketer(1, first, last, jn) && (first == "Joe" && jn == 66));

return;

}

int main() {

test();

cout << "Passed all tests" << endl;

return 0;

}

the linking must succeed. When the resulting executable is run, it must write Passed all tests to cout and nothing else to cout.

During execution, if a client performs actions whose behavior is defined by this spec,   your program must not perform any undefined actions, such as dereferencing a null or uninitialized pointer.

Your code in CricketTeam.h and CricketTeam.cpp must not read anything from   cin and must not write anything whatsoever to cout. If you want to print things out for debugging purposes, write to cerr instead of cout. cerr is the standard error

destination; items written to it by default go to the screen. When we test your program,

we will cause everything written to cerr to be discarded instead — we will never see

that output, so you may leave those debugging output statements in your program if you wish.

Turn It In

You will use BruinLearn to turn in this project. Turn in one zip file that contains your solution to the project. The zip file itself must be named in the following format (no   spaces):  LastNameFirstName_SID_AssignmentTypeAssignmentNumber.zip

(AssignmentType:  P=project, H=homework; AssignmentNumber = {1,2,3,4}).  An

example is BruinJoe_123456789_P2.  If you resubmit, do not worry about the additional

_1, _2, etc. that gets added with every resubmission.  This is normal.

The zip file must contain these files:

.    CricketTeam.h. When you turn in this file, the typedefs must specify std::string as the CricketType.

.    CricketTeam.cpp. Function implementations should be appropriately commented to guide a reader of the code.

.    A file named report.doc or report.docx (in Microsoft Word format),

report.txt (an ordinary text file), or report.pdf (in Adobe Acrobat PDF format) that contains:

o A description of the design of your implementation and why you chose it. (A couple of sentences will probably suffice, perhaps with a picture of a    typical List and an empty List. Is your list circular? Does it have a dummy node? What's in your nodes?)

o A brief description of notable obstacles you overcame.

o Pseudocode for non-trivial algorithms (e.g.,

CricketTeam::releaseCricketer and mergeCricketers)

o A list of test cases that would thoroughly test the functions. Be sure to    indicate the purpose of the tests. For example, here's the beginning of a presentation in the form of code:

The tests were performed on a map from strings to integers:

// default constructor

CricketTeam sriLankaCricket;

// For an empty list:

assert(sriLankaCricket.cricketerCount() == 0);      // test size

assert(sriLankaCricket.noTeam ());          // test empty

assert(!sriLankaCricket.releaseCricketer("Wan indu",

"Hasaranga")); // nothing to erase

Even if you do not correctly implement all the functions, you must still list test cases that would test them. Don't lose points by thinking "Well, I didn't implement this function, so I won't bother saying how I would have tested it if I had implemented it."