1. //Ifgqueue.h
#ifndef LFGQUEUE_H
#define LFGQUEUE_H
#include "player.h"
class LFGQueue
{
public:
LFGQueue(int scrimmage_threshold);
void add_player(Player* p);
bool remove_next_group(Player** players);
bool remove_next_scrimmage(Player** players);
int player_count();
int position(Player* p);
private:
class Node
{
public:
Player* p;
Node* next;
Node* prev;
};
void remove_node(Node* n);
Node* head;
Node* tail;
int scrimmage_threshold;
int count;
};
#endif
//**************************************************************************
//main.cpp
#include
#include
#include
#include
#include
2. #include "lfgqueue.h"
using namespace std;
void permute(Player** players, int len)
{
for (int i = 0; i < len; ++i)
swap(players[i], players[i + rand() % (len-i)]);
}
int main()
{
// Setup for testing
srand(2017);
Player* group[3];
Player* scrimmage[6];
Player daria("Daria", Player::Defender);
Player daniela("Daniela", Player::Defender);
Player diego("Diego", Player::Defender);
Player hector("Hector", Player::Hunter);
Player hugo("Hugo", Player::Hunter);
Player henri("Henri", Player::Hunter);
Player berta("Berta", Player::Bard);
Player bernardo("Bernardo", Player::Bard);
Player brigida("Brigida", Player::Bard);
// Test that everything compiles and queues
// construct without issue.
LFGQueue q1(3);
// Test when queue contains a single complete group in
// in an undesired order (Bard, Hunter, Defender)
q1.add_player(&bernardo);
q1.add_player(&hugo);
q1.add_player(&daria);
assert(q1.player_count() == 3);
assert(q1.position(&bernardo) == 1);
assert(q1.position(&hugo) == 2);
assert(q1.position(&daria) == 3);
3. group[0] = group[1] = group[2] = 0;
assert(q1.remove_next_group(group));
assert(group[0] == &daria);
assert(group[0]->name == "Daria");
assert(group[0]->role == Player::Defender);
assert(group[1] == &hugo);
assert(group[1]->name == "Hugo");
assert(group[1]->role == Player::Hunter);
assert(group[2] == &bernardo);
assert(group[2]->name == "Bernardo");
assert(group[2]->role == Player::Bard);
assert(q1.player_count() == 0);
cout << "20% earned." << endl;
// Test what happens when not enough group
group[0] = group[1] = group[2] = 0;
assert(!q1.remove_next_group(group));
assert(group[0] == 0);
assert(group[1] == 0);
assert(group[2] == 0);
for (int i = 0; i < 6; ++i)
scrimmage[i] = 0;
assert(!q1.remove_next_scrimmage(scrimmage));
for (int i = 0; i < 6; ++i)
assert(scrimmage[i] == 0);
cout << "25% earned." << endl;
// Test what happens when two full groups of players
// not in the right order (Def, Hunt, Hunt, Bard, Bard, Def)
q1.add_player(&daria);
q1.add_player(&hector);
q1.add_player(&hugo);
q1.add_player(&bernardo);
q1.add_player(&berta);
q1.add_player(&daniela);
assert(q1.player_count() == 6);
6. // 1000xBards in a nice order
// and max size of 2000 players.
LFGQueue q2(2000);
Player** all = new Player*[3000];
ostringstream oss;
for (int i = 0; i < 3000; i += 3)
{
oss.str("");
oss << "Defender_" << i+1;
all[i] = new Player(oss.str(), Player::Defender);
oss.str("");
oss << "Hunter_" << i+2;
all[i+1] = new Player(oss.str(), Player::Hunter);
oss.str("");
oss << "Bard_" << i+3;
all[i+2] = new Player(oss.str(), Player::Bard);
}
for (int i = 0; i < 3000; ++i)
{
q2.add_player(all[i]);
assert(q2.player_count() == i+1);
}
// First, remove 1 scrimmage.
for (int j = 0; j < 6; ++j)
scrimmage[j] = 0;
assert(q2.remove_next_scrimmage(scrimmage));
assert(q2.player_count() == 3000 - 6);
assert(scrimmage[0]->name == "Defender_2995");
assert(scrimmage[0]->role == Player::Defender);
assert(scrimmage[1]->name == "Hunter_2996");
assert(scrimmage[1]->role == Player::Hunter);
assert(scrimmage[2]->name == "Bard_2997");
assert(scrimmage[2]->role == Player::Bard);
assert(scrimmage[3]->name == "Defender_2998");
assert(scrimmage[3]->role == Player::Defender);
assert(scrimmage[4]->name == "Hunter_2999");
7. assert(scrimmage[4]->role == Player::Hunter);
assert(scrimmage[5]->name == "Bard_3000");
assert(scrimmage[5]->role == Player::Bard);
cout << "70% earned." << endl;
// Now remove 165 more scrimmages
for (int i = 0; i < 165; ++i)
{
for (int j = 0; j < 6; ++j)
scrimmage[j] = 0;
assert(q2.remove_next_scrimmage(scrimmage));
assert(q2.player_count() == 3000 - 6 - 6*(i+1));
assert(scrimmage[0]->role == Player::Defender);
assert(scrimmage[1]->role == Player::Hunter);
assert(scrimmage[2]->role == Player::Bard);
assert(scrimmage[3]->role == Player::Defender);
assert(scrimmage[4]->role == Player::Hunter);
assert(scrimmage[5]->role == Player::Bard);
}
// Now 3000 - 166 * 6 = 2004 players remain
assert(!q2.remove_next_scrimmage(scrimmage));
// Now remove the rest of the queue as groups
group[0] = group[1] = group[2] = 0;
assert(q2.remove_next_group(group));
assert(q2.player_count() == 2001);
assert(group[0]->name == "Defender_1");
assert(group[0]->role == Player::Defender);
assert(group[1]->name == "Hunter_2");
assert(group[1]->role == Player::Hunter);
assert(group[2]->name == "Bard_3");
assert(group[2]->role == Player::Bard);
// (1 + 667) * 3 = 2004
for (int i = 0; i < 667; ++i)
{
group[0] = group[1] = group[2] = 0;
assert(q2.remove_next_group(group));
8. assert(q2.player_count() == 2001 - 3 * (i+1));
assert(group[0]->role == Player::Defender);
assert(group[1]->role == Player::Hunter);
assert(group[2]->role == Player::Bard);
}
assert(!q2.remove_next_group(group));
cout << "80% earned." << endl;
// Timing test. Make a queue with 3000000 players:
// 1000000xDefender, 1000000xHunter, 1000000xBard,
// in collections of shuffled 30 complete groups.
LFGQueue qt(100000);
const int timing_player_count = 1000000;
all = new Player*[timing_player_count];
for (int i = 0; i < timing_player_count; i += 3)
{
all[i] = new Player("Defender_???", Player::Defender);
all[i+1] = new Player("Hunter_???", Player::Hunter);
all[i+2] = new Player("Bard_???", Player::Bard);
}
for (int i = 0; i < timing_player_count; i += 30)
permute(&(all[i]), 30);
// Time how long it takes to add all players
clock_t start = clock();
for (int i = 0; i < timing_player_count; ++i)
qt.add_player(all[i]);
float duration = static_cast(clock() - start) / CLOCKS_PER_SEC;
assert(qt.player_count() == timing_player_count);
assert(duration < 2.0);
// Time how long it takes to form 10000 scrimmages
start = clock();
for (int i = 0; i < 10000; ++i)
assert(qt.remove_next_scrimmage(scrimmage));
duration = static_cast(clock() - start) / CLOCKS_PER_SEC;
assert(qt.player_count() == timing_player_count - 60000);
9. assert(duration < 0.1);
// Time how long it takes to form 10000 groups
start = clock();
for (int i = 0; i < 10000; ++i)
assert(qt.remove_next_group(group));
duration = static_cast(clock() - start) / CLOCKS_PER_SEC;
assert(qt.player_count() == timing_player_count - 60000 - 30000);
assert(duration < 0.1);
// Test removing a group correctly
group[0] = group[1] = group[2] = 0;
assert(qt.remove_next_group(group));
assert(group[0]->role == Player::Defender);
assert(group[1]->role == Player::Hunter);
assert(group[2]->role == Player::Bard);
cout << "100% earned." << endl;
}
//************************************************************************
//player.h
#ifndef PLAYER_H
#define PLAYER_H
#include
using namespace std;
class Player
{
public:
enum Role {Defender, Hunter, Bard};
Player(string name, Role role)
{
this->name = name;
this->role = role;
}
string name;
Role role;
};
10. #endif
//***********************************************************************
/*
Long queuing times are common in many games, leading to player boredom as they wait idly. As
a solution, many games have a “scrimmage” mode where players at the end of a long queue are
placed into large, unstructured groups to play a casual game.
Here you’ll add such a scrimmage feature to a “looking for group” queue. Whenever more than 6
additional players past the queue’s specified “threshold” size have joined the queue, the last such
6 players are removed from the queue and placed into a scrimmage (group) with no role
requirements.
Since reducing wait times is the entire purpose of this feature, it must run extremely quick and a
doubly linked list is needed. Since the feature is triggered only when the queue is larger than a
specified maximum size, the number of players in the queue must also be computed extremely
fast.
*/
Solution
Given below is the implementation of lfgqueue.cpp. Please use it along with other files from
question - lfgqueue.h, main.cpp, player.h. These files are not modified. The only new file is
lfgqueue.cpp. Output shown in the end. Please don't forget to rate the answer if it helped. Thank
you very much.
player.h
//************************************************************************
//player.h
#ifndef PLAYER_H
#define PLAYER_H
#include
using namespace std;
class Player
{
public:
enum Role {Defender, Hunter, Bard};
Player(string name, Role role)
{
11. this->name = name;
this->role = role;
}
string name;
Role role;
};
#endif
//***********************************************************************
/*
Long queuing times are common in many games, leading to player boredom as they wait idly.
As a solution, many games have a “scrimmage” mode where players at the end of a long queue
are placed into large, unstructured groups to play a casual game.
Here you’ll add such a scrimmage feature to a “looking for group” queue. Whenever more than
6 additional players past the queue’s specified “threshold” size have joined the queue, the last
such 6 players are removed from the queue and placed into a scrimmage (group) with no role
requirements.
Since reducing wait times is the entire purpose of this feature, it must run extremely quick and a
doubly linked list is needed. Since the feature is triggered only when the queue is larger than a
specified maximum size, the number of players in the queue must also be computed extremely
fast.
*/
lfgqueue.h
//Ifgqueue.h
#ifndef LFGQUEUE_H
#define LFGQUEUE_H
#include "player.h"
class LFGQueue
{
public:
LFGQueue(int scrimmage_threshold);
void add_player(Player* p);
14. }
return false;
}
//simliar to remove_next_group, but removing players from tail
bool LFGQueue::remove_next_scrimmage(Player** players)
{
if(count < 6 + scrimmage_threshold) return false;
for(int i = 5; i >= 0; i--)
{
players[i] = tail->p;
remove_node(tail);
}
return true;
}
int LFGQueue::player_count()
{
return count;
}
int LFGQueue::position(Player* p)
{
Node *curr = head;
int position = 1;
while(curr != NULL)
{
if(curr->p->name == p->name && curr->p->role == p->role)
return position;
position++;
curr = curr->next;
}
return -1;
}
void LFGQueue::remove_node(Node* n)
{
if(n == NULL || head == NULL)
return;
15. if(n->prev == NULL) //deleteing head node
{
head = n->next;
if(head != NULL) //make head's previous as NULL, if queue si not empty
head->prev = NULL;
else //head is NULL , so no more nodes in queue
tail = NULL;
}
else
{
//make previous node to point to a node after the node to be deleted
n->prev->next = n->next;
if(n->next != NULL) //not deleting tail node
n->next->prev = n->prev;
else //deleting tail node
tail = n->prev;
}
delete n;
count --;
}
main.cpp
//**************************************************************************
//main.cpp
#include
#include
#include
#include
#include
#include "lfgqueue.h"
using namespace std;
void permute(Player** players, int len)
{
for (int i = 0; i < len; ++i)
swap(players[i], players[i + rand() % (len-i)]);
}
16. int main()
{
// Setup for testing
srand(2017);
Player* group[3];
Player* scrimmage[6];
Player daria("Daria", Player::Defender);
Player daniela("Daniela", Player::Defender);
Player diego("Diego", Player::Defender);
Player hector("Hector", Player::Hunter);
Player hugo("Hugo", Player::Hunter);
Player henri("Henri", Player::Hunter);
Player berta("Berta", Player::Bard);
Player bernardo("Bernardo", Player::Bard);
Player brigida("Brigida", Player::Bard);
// Test that everything compiles and queues
// construct without issue.
LFGQueue q1(3);
// Test when queue contains a single complete group in
// in an undesired order (Bard, Hunter, Defender)
q1.add_player(&bernardo);
q1.add_player(&hugo);
q1.add_player(&daria);
assert(q1.player_count() == 3);
assert(q1.position(&bernardo) == 1);
assert(q1.position(&hugo) == 2);
assert(q1.position(&daria) == 3);
group[0] = group[1] = group[2] = 0;
assert(q1.remove_next_group(group));
assert(group[0] == &daria);
17. assert(group[0]->name == "Daria");
assert(group[0]->role == Player::Defender);
assert(group[1] == &hugo);
assert(group[1]->name == "Hugo");
assert(group[1]->role == Player::Hunter);
assert(group[2] == &bernardo);
assert(group[2]->name == "Bernardo");
assert(group[2]->role == Player::Bard);
assert(q1.player_count() == 0);
cout << "20% earned." << endl;
// Test what happens when not enough group
group[0] = group[1] = group[2] = 0;
assert(!q1.remove_next_group(group));
assert(group[0] == 0);
assert(group[1] == 0);
assert(group[2] == 0);
for (int i = 0; i < 6; ++i)
scrimmage[i] = 0;
assert(!q1.remove_next_scrimmage(scrimmage));
for (int i = 0; i < 6; ++i)
assert(scrimmage[i] == 0);
cout << "25% earned." << endl;
// Test what happens when two full groups of players
// not in the right order (Def, Hunt, Hunt, Bard, Bard, Def)
q1.add_player(&daria);
q1.add_player(&hector);
q1.add_player(&hugo);
q1.add_player(&bernardo);
q1.add_player(&berta);
q1.add_player(&daniela);
assert(q1.player_count() == 6);
22. assert(q2.remove_next_group(group));
assert(q2.player_count() == 2001);
assert(group[0]->name == "Defender_1");
assert(group[0]->role == Player::Defender);
assert(group[1]->name == "Hunter_2");
assert(group[1]->role == Player::Hunter);
assert(group[2]->name == "Bard_3");
assert(group[2]->role == Player::Bard);
// (1 + 667) * 3 = 2004
for (int i = 0; i < 667; ++i)
{
group[0] = group[1] = group[2] = 0;
assert(q2.remove_next_group(group));
assert(q2.player_count() == 2001 - 3 * (i+1));
assert(group[0]->role == Player::Defender);
assert(group[1]->role == Player::Hunter);
assert(group[2]->role == Player::Bard);
}
assert(!q2.remove_next_group(group));
cout << "80% earned." << endl;
// Timing test. Make a queue with 3000000 players:
// 1000000xDefender, 1000000xHunter, 1000000xBard,
// in collections of shuffled 30 complete groups.
LFGQueue qt(100000);
const int timing_player_count = 1000000;
all = new Player*[timing_player_count];
for (int i = 0; i < timing_player_count; i += 3)
{
all[i] = new Player("Defender_???", Player::Defender);
all[i+1] = new Player("Hunter_???", Player::Hunter);
all[i+2] = new Player("Bard_???", Player::Bard);
}
for (int i = 0; i < timing_player_count; i += 30)
23. permute(&(all[i]), 30);
// Time how long it takes to add all players
clock_t start = clock();
for (int i = 0; i < timing_player_count; ++i)
qt.add_player(all[i]);
float duration = static_cast(clock() - start) / CLOCKS_PER_SEC;
assert(qt.player_count() == timing_player_count);
assert(duration < 2.0);
// Time how long it takes to form 10000 scrimmages
start = clock();
for (int i = 0; i < 10000; ++i)
assert(qt.remove_next_scrimmage(scrimmage));
duration = static_cast(clock() - start) / CLOCKS_PER_SEC;
assert(qt.player_count() == timing_player_count - 60000);
assert(duration < 0.1);
// Time how long it takes to form 10000 groups
start = clock();
for (int i = 0; i < 10000; ++i)
assert(qt.remove_next_group(group));
duration = static_cast(clock() - start) / CLOCKS_PER_SEC;
assert(qt.player_count() == timing_player_count - 60000 - 30000);
assert(duration < 0.1);
// Test removing a group correctly
group[0] = group[1] = group[2] = 0;
assert(qt.remove_next_group(group));
assert(group[0]->role == Player::Defender);
assert(group[1]->role == Player::Hunter);
assert(group[2]->role == Player::Bard);
cout << "100% earned." << endl;
}
output
20% earned.