Я хотел бы рассказать о симуляции библиотеки, которую я создал, используя C++. По сути, он имитирует среду, в которой люди приходят в библиотеку и берут книги, а также выводит информацию о книгах, такую как их полки, страницы и т.д. Есть несколько вещей, которые необходимо знать заранее:
1. Эта программа использует довольно много классов и структур, которые связаны друг с другом для отображения данных, т.е. (Книжная полка содержит книги, книги содержат историю, а люди связаны с активными книгами и т.д.).
2. В этом проекте нет внешних библиотек типа boost.
3. Данные предопределены, но также рандомизированы из жестко закодированного набора значений, что означает, что результат не всегда будет точно таким же, но каждый раз будет похожим.
4. У каждой книги есть только три копии, поэтому, когда этот лимит достигнут, книга не может быть взята снова.
После этого я хотел бы разделить все функции, которые я здесь использовал:
— struct DualReturnType — пользовательская структура, которую я сделал, которая позволяет мне хранить данные указателя, а также его размер в одном возвращаемом значении в качестве средства легкого доступа.
— LibraryGuests int const — постоянное целочисленное значение, которое хранит максимальное количество людей, которых я хотел видеть в симуляции.
— ID — статический счетчик, который увеличивается при добавлении гостей.
— Класс Person — класс, который хранит всю информацию о человеке, например, его имя и книги, которые у него есть на данный момент.
— класс BookHistory — Пользовательский класс, который специально хранит историю книги, в первую очередь, кто ее взял, с информацией о названии в виде, который может быть легко распечатан.
— класс Book — класс Book, который хранит информацию о книге, включая ее название, количество страниц, доступные копии и ссылку на экземпляр BookHistory.
— класс BookShelf — Действует как реальная книжная полка, поэтому содержит список только из 13 книг на полку (экземпляр) и является тем, на что ссылаются при поиске книг. Полки соответствуют буквам A-Z
— класс BookGroup — База данных этой программы. Он ссылается почти на все другие классы, такие как Книги и полки, и имеет ссылки на них. Когда делается запрос, он выполняется через этот класс.
— void SetUpBookNames функция — Занимается задачей установки главной ссылки BookGroup с данными, такими как имена и страницы, которые используются в программе.
— void setUpBookNames функция — То же самое, что и SetUpBookNames, но только с гостями библиотеки.
— void Main — Устанавливает программу с необходимым инстанцированием гостей, имен книг и экземпляров книжных групп для запуска. Зацикливается до тех пор, пока пользователь не завершит программу.
— класс UserInputHelperClass — класс, который обрабатывает направления ввода, которые выполняет пользователь, будь то поиск человека, книги или завершение программы.
Теперь я хотел бы рассказать о каждой из этих переменных и функций более подробно.
Первая из них — это структура DualReturn Type. DualReturnType struct — это структура, которая в своем конструкторе принимает в качестве ссылок указатель и его размер. Это делается для того, чтобы мне было проще ссылаться на указатели в других местах программы, в частности, в классе BookShelf.
Вот код для этого:
// Helper struct that returns pointers and their sizes for use in other functions
struct DualReturnType
{
// The default constructor. Parameters are the array and size.
DualReturnType(int *Ref, int Size)
{
// checker to make sure the parameter value isn't equal to NULL
if (Ref != NULL)
{
int_Array = Ref;
int_size = Size;
}
// If the incoming pointer is NULL, output an error message
else
cout << "Error: failed to initialize integer dual type" << endl;
}
// The default constructor for this struct. Makes everything NULL
DualReturnType()
{
int_Array = NULL;
int_size = 0;
}
// An integer array pointer, and a integer size variable
int *int_Array, int_size;
// Same as the specialized constructor but as a void function
void Initialize_Int_Type(int *Ref, int Size)
{
if (Ref != NULL)
{
int_Array = Ref;
int_size = Size;
}
else
cout << "Error: Failed to initialize integer dual type" << endl;
}
};
Следующий класс — это класс person. Класс person в своем конструкторе инициализирует некоторые значения по умолчанию, включая имя, две книги (массив), которые разрешено проверять («» или пусто), а также счетчик книг (хэш-ключ), который увеличивается при добавлении книги в этот класс. Класс также имеет идентификатор, похожий на библиотечный билет, который специально используется для идентификации людей, даже если вы не знаете их имени, и его можно легко отследить. Единственные три функции этого класса — обновлять массив книг внутри него (убирать или добавлять книги) и выводить их информацию в специальной функции, когда это необходимо.
Ниже приведен код для этого:
// The Person/Guest for this simulation. Has parameters attached to it such as ID, booklimits, name, etc...
class Person
{
public:
//Default constructor which initializes all values to basic functions.
Person()
{
name = "Empty";
BookLimit = 2;
behavior = "Browsing";
GuestID = 0;
books[0] = "";
books[1] = "";
bookcounter = 0;
}
// Copy constructor
Person(const Person ©)
{
name = copy.name;
BookLimit = copy.BookLimit;
behavior = copy.behavior;
GuestID = copy.GuestID;
books[0] = "";
books[1] = "";
bookcounter = 0;
}
// Initialize name if the incoming string is valid
Person(string Name)
{
if (!Name.empty())
this->name = Name;
else
{
cout << "This person doesn't have a valid name." << endl;
name = "Empty";
}
BookLimit = 2;
behavior = "Browsing";
books[0] = "";
books[1] = "";
bookcounter = 0;
}
//Default destructor
~Person()
{
}
// Adds a book to the person's book array
void AddBook(string BookName)
{
if (bookcounter <= 1)
{
books[bookcounter] = BookName;
bookcounter++;
}
else
cout << "Person()::AddBook cannot add more booksn";
}
// Prints the books that a person added
void PrintBooks()
{
if (bookcounter > 0)
{
cout << name << " current books: ";
for (int i = 0; i < bookcounter; ++i)
{
if (books[i] != "")
cout << i+1 << ": " << books[i] << " ";
}
cout << "n";
}
else
cout << name << " has no history yet.n";
}
// Prints the general info about this person
void PrintGeneralInfo()
{
cout << "Name: " << name << "tBooks in possession: " << bookcounter << "tGuestID: " << GuestID << endl;
}
string name, behavior, books[2]; // Name of the person, and arrayof booknames
int BookLimit, GuestID, bookcounter; // BookLimit to limit the person inside the library to a certain amount, and that persons GuestID, bookcounter to access current book
};
Следующий класс — BookHistory. Он имеет публичное меню BookName, приватную переменную counter, указатель Person под названием people, целочисленную переменную currentlimit и строковую переменную order. Внутри этого класса есть только две функции: AddHistory и PrintHistory. AddHistory принимает входящий объект Person и добавляет его к ссылке people этого класса, а другая просто распечатывает данные, содержащиеся в этом классе, вместе с названием книги.
Вот как все это выглядит:
// Records the history of a book which can be called at any time later
class BookHistory
{
public:
string bookName; // Name of the book that is recorded
// Default constructor which initializes all variables
BookHistory()
{
people = new Person[3];
currentLimit = 3;
currentCounter = 0;
order[0] = "first.";
order[1] = "second.";
order[2] = "third.";
}
// Copy constructor which initializes based on another bookHistory reference
BookHistory(const BookHistory &otherBookHistory)
{
currentLimit = otherBookHistory.currentLimit;
people = new Person[currentLimit];
currentCounter = otherBookHistory.currentCounter;
order[0] = "first.";
order[1] = "second.";
order[2] = "third.";
for (int i = 0; i < currentCounter; i++)
people[i] = otherBookHistory.people[i];
}
// Destructor which only destroys our people pointer
~BookHistory()
{
if (people != NULL)
delete [] people;
}
// How people are added to this books history.
void AddHistory(Person person)
{
// If the currentcounter hasn't yet reached the limit, then set the people pointer inside our history to the incoming person. Basically adds it inside the array
if (currentCounter < currentLimit)
{
people[currentCounter] = person;
currentCounter++; // finally increase the currentCounter
}
else
cout << "Cannot update this books history at this time" << endl;
}
// Prints the histoy of this book based on the currentCounter which increases when people check out this book
void PrintHistory()
{
if (currentCounter >= 1)
{
// Will print the persons Info assuming the people pointer isn't NULL and it's name isn't == Empty
for (int i = 0; i < currentCounter; i++)
{
if (people != NULL)
if (people[i].name != "Empty")
cout << people[i].name << " ID: " << people[i].GuestID << " checked out '" << bookName << "' " << order[i] << "nn";
else
cout << "No names setup for this bookn";
}
}
else
cout << bookName << " has no check out history yet.nn"; // This should print out if the current counter isn't at least equal to 1. Book has no history.
}
private:
Person *people; // people pointer which holds references to anyone who checks out this book
int currentLimit; // A max limit variable which is initialized to 3 for this simulation
int currentCounter; // A counter that goes up until it reaches the currentLimit
string order[3]; // Simply a string helper which has strings based on the order of an index. So 0 = first, 1 = seconds, 2 = third.
};
Следующий класс, который я хотел бы затронуть, — это класс Book. Класс Book имеет все открытые члены, включая количество страниц в книге, ее экземпляры, наличие, имя и член класса BookHistory. Его функции включают проверку пустых книг и удаление копий книги, если количество копий равно 0, которое уменьшается при проверке. Конструктор инициализирует большинство данных с переданными аргументами или без них.
Посмотрите здесь:
// Book class which is used to house all information about a book including its name, number of pages, whether it's avaiable or not, its history, and number of copies
class Book
{
public:
// Default constructor for this class. Intializes all values. Name of the book is blank (set elsewhere), pages is also reset elsewhere, copies is set to 3,
// avaialable is set to true, and the the historys bookname is set to empty
Book()
{
name = "Empty";
pages = 0;
copies = 3;
available = true;
thisBookHistory.bookName = "Empty";
}
// Book with all parameters setup to copy into this variables
Book(string BookName, int numPages, int copies, BookHistory book)
{
name = BookName;
pages = numPages;
thisBookHistory = book;
available = true;
this->copies = copies;
}
// Destructor of the book class
~Book()
{
}
// If the book is a dummy or a real book
bool emptyBook()
{
if (name == "" || name == "Empty")
return true;
else
return false;
}
// Removes a copy of the book from the list. Once a copy reaches zero, no one may check out this book
void RemoveCopy()
{
// Simply decrease the number of copies by 1 and return
if (copies >= 2)
{
copies -= 1;
}
// If the copy equals 1, then this is the last copy of the book and available should be set to false for other functions. Copies is also decremented by 1
else if (copies == 1)
{
available = false;
//cout << "This is the last copy of " << name << endl;
copies -= 1;
}
// This shouldn't occur but is set just in case this function is called by accident
else
cout << "Sorry. " << "No more copies of: " << name << " are avaialable.n";
}
string name; // Name of the book
int pages, copies; // The number of pages of the book and its copies
bool available; // Whether the book is available or not. Used in the bookshelf class
BookHistory thisBookHistory; //History variable of the book which can be called by the shelf
};
Следующий класс — Bookshelf. Этот класс напоминает книжную полку в библиотеке, и его дизайн предполагает наличие нескольких классов, соответствующих группам из двух букв. Всего их тринадцать и расположены они в порядке целочисленности. Так, bookshelf[0] соответствует книгам, начинающимся с A и B, bookshelf[1] C и D и так далее. Она имеет все открытые члены, которые включают двенадцать массивов Books (соответствующих полкам), строку, содержащую идентификатор полки, булево значение fillboolean для легкого доступа, массив fullindex размером двенадцать, также соответствующий полке, и счетчик stockcounter, который содержит книги, доступные для использования. Его функции включают функцию AddBook, которая добавляет книгу и ее страницы в класс, класс PrintAllBooksOnShelf, который печатает все книги, доступные в данный момент на этой полке, функцию printbyindex, которая делает то же самое, но в ограниченном виде, сначала проверяя, действителен ли входящий индекс, две функции printbookhistory, которые делают то же самое, что и printindex и printall, булев помощник locateBook, который возвращает true или false, если книга найдена, функция getbookID, которая пытается найти книгу по ее ID вместо названия с помощью функции locateBook, булева функция AllBooksTaken, которая перебирает все книги, чтобы найти ту, которая не является ложной, и, наконец, вспомогательная функция DualReturnType под названием ReferenceArrayHelper, которая использует целочисленное значение StockCounter для ручного создания целочисленной ссылки-указателя, которая может быть использована в других местах, например, в BookGroup, которая будет рассмотрена далее.
Вот как выглядит Книжная полка:
// Bookshelf class that holds all data about a bookshelf instance.
class Bookshelf
{
public:
// Default constructor. Sets stockcounter (current books) to 0, then set fullindex incidies to the value in the loop
Bookshelf()
{
StockCounter = 0;
for (int i = 0; i <= 11; ++i)
fullindex[i] = i;
}
// Destructor
~Bookshelf()
{
}
// Add a book to this shelf. Parameters include the name of the book and its pages.
void AddBook(string BookName, int pages)
{
// If current book couner isn't at its max (12), then proceed
if (StockCounter <= 11)
{
// If the current name of the book is empty, prepare to replace it with the parameters.
if (books[StockCounter].name == "Empty")
{
books[StockCounter].name = BookName;
books[StockCounter].pages = pages;
books[StockCounter].thisBookHistory.bookName = BookName;
StockCounter++; // Increase the number of books on this instance by 1
}
// if we tried to add a name that wasn't valid. However this won't trigger because of the stockCounter variable after the last add
else
cout << "Somehow, this spot is already takenn";
}
else
{
cout << "No more room on this shelf to add new booksn"; // Prints if we tried to add a book but the current value exceeds 11
}
}
// Prints all books data that are currently on the shelf
void PrintAllBooksOnShelf()
{
string available = "";
for (int i = 0; i < StockCounter; ++i)
{
books[i].available ? available = "Yes" : available = "No";
cout << "Shelf ID: " << shelfID << " tBook number: " << i+1 << " Book name: " << books[i].name
<< " tPages: " << books[i].pages << " tAvailabile: " << available << endl;
}
}
// Print the books general data based on a index parameter assuming it is in bounds
void PrintBookByIndex(int index)
{
// Temp string to hold the avialability string to print out to the user
string available = " ";
// If the book we want is available, set the available string to Yes, otherwise it is set to no
books[index].available ? available = "Yes" : available = "No";
// Print the information that we want about this book
if (index >= 0 && index <= 11)
cout << "Shelf ID: " << shelfID << ". Book number: " << index+1 << ". Book name: " << books[index].name
<< ". Pages: " << books[index].pages << ". Available: " << available << endl;
}
// Prints the usage history of a specific book assuming its index is in bounds
void PrintBookHistory(int bookID)
{
if (bookID != -1 && bookID <= 11)
books[bookID].thisBookHistory.PrintHistory();
}
// Prints all of the history of all current books on this shelf only
void PrintAllBookHistory()
{
for (int i = 0; i < StockCounter; ++i)
{
books[i].thisBookHistory.PrintHistory();
}
}
// Attempts to find a single book based on the name.
bool LocateBook(string BookName)
{
//cout << endl;
// Loop through the elements and if the parameter name matches any of the elements name, Simply return true to indicate success.
for (int i = 0; i <= StockCounter - 1; ++i)
{
if (BookName == books[i].name)
return true;
}
// This occurs if we went through all elements and there is no match. In this case print a message and return false to indicate failure.
cout << BookName << " does not exist on shelf " << shelfID << "." << endl;
return false;
}
// Attempts to grab a booksID based on that books name.
int GetBookID(string BookName)
{
int bookID = -1;
if (LocateBook(BookName))
{
for (int i = 0; i < StockCounter; ++i)
{
// If a match was found, then break the loop and set the id to i.
if (BookName == books[i].name)
{
bookID = i;
break;
}
}
}
return bookID;
}
// Boolean return type based on the filled boolean variable. If ANY book is still available, this will return false. Otherwise it will return true.
bool AllBooksTaken()
{
for (int i = 0; i < 12; ++i)
{
// If a book is available, set filled to false and return immediately
if (books[i].available)
{
filled = false;
return filled;
}
// If a book isn't available, then set the fullindex based on that space to -1, used for ReferenceArrayHelper().
else
fullindex[i] = -1;
}
// If we got here, this shelf really is full and return true.
filled = true;
return filled;
}
// DualReturnType reference funcion that will return a pointer and its size together.
DualReturnType ReferenceArrayHelper()
{
int SizeCounter(0); // SizeCounter reference to determine valid books inside the shelf
// Loop through the active books on the shelf and if the fullindex based on the loop value i is equal to -1, increase the sizecounter variable.
// This is to intialize another variable later so that it only contains valid indicies from the shelf.
for (int i = 0; i < StockCounter; ++i)
{
if (fullindex[i] != -1)
SizeCounter += 1;
}
// Assuming that at least one of the elements in the above was valid (SizeCounter >=1), proceed.
if (SizeCounter >= 1)
{
int *indexArray = new int[SizeCounter]; // Create a pointer array that is based on the SizeCounter index;
int indexCounter = 0; // new variable reference that tracks the indices of the indexArray. This is so we can set them as we proceed
// through the loop based on its own counter
// Loop through the StockCounter again and if the sizecounter is greater than or equal to 1, proceed with the following
for (int i = 0; i < StockCounter; ++i)
{
// If the fullindex element isn't -1, the proceed.
if (fullindex[i] != -1)
{
if (SizeCounter >= 1)
{
indexArray[indexCounter] = i; // Set the indexArray element based on the current counter equal to i in the loop to indicate a goood value
indexCounter++; // Increase the index counter by 1 to move to the next element
SizeCounter--; // Decrease the counter since we hit a successfull element
}
else
{
break; // If the sizecounter has gone below 1, stop since there are no other valid elements
}
}
}
// Finally return this newly created array, along with the index counter, which is indexArray's size
return DualReturnType(indexArray, indexCounter);
}
else
return DualReturnType(); // IF we got here, return a default or blank DualReturnType
}
Book books[12]; // Array of books in that shelf
string shelfID; // String that containts the name of each shelfID
int StockCounter; // The number of books that are actually avialable to use, increases when books are added
bool filled; // If the entire structure is taken
int fullindex[12]; // Useful when checking out a book. This is so this same book isn't looked at again. (Removed from the pool)
};
Класс BookGroup содержит всю информацию, связанную с книгами и полками. После основных функций настройки и класса ввода, это класс, на который ссылаются при добавлении, поиске, нахождении или удалении информации, относящейся к книгам, людям и истории. Он имеет один приватный член — массив bookshelf, что сделано для того, чтобы данные, относящиеся к нему, не могли быть легко изменены простым созданием экземпляра этого класса. Изменение данных вокруг него требует использования функций-членов, которые вызывают данные и функции внутри класса, относящиеся к требуемой цели.
В число членов класса входят конструктор, булева функция FindBook, функция void AddBook, функция void AddBooks, индекс getbookshelfID на основе названия книги, строковая функция GetbookshelfID, три варианта printbook, которые печатают все книги, одну по индексу, другую по shelfID, функция void CheckoutBook, которая принимает ссылку на человека и его желаемую книгу, строковая вспомогательная функция randomBookSelection, которая выбирает книгу без необходимости ввода названия, две вспомогательные функции bookhistory, которые печатают историю книг по полкам, возвращаемый тип GetBook Book, который пытается найти книгу по ее идентификатору полки и месту, и, наконец, строковая функция GetBook, которая напрямую дает пользователю название книги в определенном месте. Эта функция очень длинная, поэтому я не буду объяснять ее здесь.
Однако я написал много заметок по этому поводу здесь, если вы хотите пройти через это самостоятельно:
// The main class that controls everything. Operating as the library's database, this class houses all bookshelves and the bookshelves house the books.
class BookGroup
{
public:
// Default constructor that sets up the bookshelves
BookGroup()
{
// Create a string that has all of the letters of the alphabet
string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int stringcounter = 0; // Counter variable that will be used to pull letters out of the alpabet variable
// Loop based on the total number of shelves (12 in total).
for (int i = 0; i < 13; ++i)
{
// Make the shelf ID a group of two from the alphabet. So shelf 1 = AB, 2 = CD, 3 = EF etc...
// Uses the stringcounter as a index from the alphabet in groups of 2. So 0 first then 0 + 1 next. Then simply increase the string counter by 2
// so when we get here again it references the next set of letters.
bookshelf[i].shelfID.append(1, alphabet[stringcounter]);
bookshelf[i].shelfID.append(1, alphabet[stringcounter + 1]);
stringcounter += 2;
}
}
// Default destructor which does nothing
~BookGroup()
{
}
// Find a book based on its name.
bool FindBook(string book)
{
// holder boolean which is initialized to false
bool returnvalue = false;
// Shelf holder that will be changed based on the first letter of the book (parameter)
int Shelf = 0;
// Create a single character variable which references the first character inside the book parameter
char bookcopy = book[0];
// Capatitalize this letter to avoid errors and to match the switch case below
bookcopy = toupper(bookcopy);
// Switches based on the bookcopy variable
switch (bookcopy)
{
case 'A':
//cout << "Letter A n";
break;
case 'B':
//cout << "Letter B n";
break;
case 'C':
//cout << "Letter C n";
Shelf = 1;
break;
case 'D':
//cout << "Letter D n";
Shelf = 1;
break;
case 'E':
//cout << "Letter E n";
Shelf = 2;
break;
case 'F':
//cout << "Letter F n";
Shelf = 2;
break;
case 'G':
//cout << "Letter G n";
Shelf = 3;
break;
case 'H':
//cout << "Letter H n";
Shelf = 3;
break;
case 'I':
//cout << "Letter I n";
Shelf = 4;
break;
case 'J':
//cout << "Letter J n";
Shelf = 4;
break;
case 'K':
//cout << "Letter K n";
Shelf = 5;
break;
case 'L':
//cout << "Letter L n";
Shelf = 5;
break;
case 'M':
//cout << "Letter M n";
Shelf = 6;
break;
case 'N':
//cout << "Letter N n";
Shelf = 6;
break;
case 'O':
//cout << "Letter O n";
Shelf = 7;
break;
case 'P':
//cout << "Letter P n";
Shelf = 7;
break;
case 'Q':
//cout << "Letter Q n";
Shelf = 8;
break;
case 'R':
//cout << "Letter R n";
Shelf = 8;
break;
case 'S':
//cout << "Letter S n";
Shelf = 9;
break;
case 'T':
//cout << "Letter T n";
Shelf = 9;
break;
case 'U':
//cout << "Letter U n";
Shelf = 10;
break;
case 'V':
//cout << "Letter V n";
Shelf = 10;
break;
case 'W':
//cout << "Letter W n";
Shelf = 11;
break;
case 'X':
//cout << "Letter X n";
Shelf = 11;
break;
case 'Y':
//cout << "Letter Y n";
Shelf = 12;
break;
case 'Z':
//cout << "Letter Z n";
Shelf = 12;
break;
default:
cout << "First letter is not A - Z. Error.n";
break;
}
// Now that we have our shelf index, then attempt to find the book based on that shelf
bool FoundBook = bookshelf[Shelf].LocateBook(book);
// If the FoundBook boolean is equal to true, set the returnvalue to true and the same if its the opposite
FoundBook ? returnvalue = true: returnvalue = false;
return returnvalue;
}
// Adds a single book based on a int array value.
void AddBook(string BookName, int *PagesArray, int PageIndex)
{
int Shelf = GetBookShelfID_Index(BookName); // Get the bookID based on the bookName
// If the shelfID isn't equal to negative one proceed normally, otherwise output a error message
if (Shelf != -1)
bookshelf[Shelf].AddBook(BookName, PagesArray[PageIndex]);
else
cout << "Error in AddBook: Impossible to add " << BookName << " to the list";
}
// Adds a array of strings to the shelf based size of the array
void AddBooks(string *Books, int BookSize, int *PageArray)
{
for (int Shelf, i = 0; i < BookSize; ++i)
{
Shelf = GetBookShelfID_Index(Books[i]);
if (Shelf != -1)
{
bookshelf[Shelf].AddBook(Books[i], PageArray[i]);
}
else
break;
}
}
// Get the shelf index based on the first letter of the incoming string. Return that index. If the later cannot be found, return -1
int GetBookShelfID_Index(string Name)
{
Name[0] = toupper(Name[0]);
if (Name[0] == 'A' || Name[0] == 'B')
return 0;
else if (Name[0] == 'C' || Name[0] == 'D')
return 1;
else if (Name[0] == 'E' || Name[0] == 'F')
return 2;
else if (Name[0] == 'G' || Name[0] == 'H')
return 3;
else if (Name[0] == 'I' || Name[0] == 'J')
return 4;
else if (Name[0] == 'K' || Name[0] == 'L')
return 5;
else if (Name[0] == 'M' || Name[0] == 'N')
return 6;
else if (Name[0] == 'O' || Name[0] == 'P')
return 7;
else if (Name[0] == 'Q' || Name[0] == 'R')
return 8;
else if (Name[0] == 'S' || Name[0] == 'T')
return 9;
else if (Name[0] == 'U' || Name[0] == 'V')
return 10;
else if (Name[0] == 'W' || Name[0] == 'X')
return 11;
else if (Name[0] == 'Y' || Name[0] == 'Z')
return 12;
else
{
cout << "Error in the bookshelfID grabber function" << endl;
cout << Name << endl;
return -1;
}
}
// string return of the bookID based on the Name of a book
string GetBookShelfID(string Name)
{
// Get and Set the index variable to the index based off the name
int ShelfID_Index = GetBookShelfID_Index(Name);
// If index is within bounds then return the ID, otherwise return NULL
if (ShelfID_Index >= 0 && ShelfID_Index <= 12)
return bookshelf[ShelfID_Index].shelfID;
else
return "NULL";
}
// Simply prints the books in order by shelves. Calls the shelf variables PrintAllBooksOnShelf
void PrintAllBooks()
{
int AllShelves = sizeof(bookshelf) / sizeof(bookshelf[0]); // Size that we'll loop through
for (int i = 0; i < AllShelves; ++i)
{
bookshelf[i].PrintAllBooksOnShelf(); // Prints all books per shelf in the array
}
}
// Print all the books based on a desired shelf
void PrintBooksByShelf(int shelf)
{
if (shelf >= 0 && shelf <= 12)
bookshelf[shelf].PrintAllBooksOnShelf(); // Prints all books on the shelf that we want
}
// Print a specific book with its shelf and slot index
void PrintBookByShelfAndID(int shelf, int bookID)
{
bookshelf[shelf].PrintBookByIndex(bookID);
}
// The actual function that checks out books from the shelevs. Requires a guest parameter, and that guests desired book to be checked out.
// This function will continue until a successful book has been removed. The library has been adjusted to accomodate this.
void CheckoutBook(Person &guest, string desiredBook)
{
// Guest name cannot be blank
if (guest.name != "Empty")
{
// Guest must be able to at least check out one book
if (guest.BookLimit >= 1)
{
// attempts to find the guests desired book
bool FoundBook = FindBook(desiredBook);
// If it is found proceed.
if (FoundBook)
{
// Gathers the shelfID and the bookID based on the desiredbook
int Shelf = GetBookShelfID_Index(desiredBook);
int bookID = bookshelf[Shelf].GetBookID(desiredBook);
// If the shelf and bookIDs are -1(failure) then proceed.
if (Shelf != -1 && bookID != -1)
{
// Checker to detrmine if all the books on the desired shelf are empty or not
bool AllbooksTaken = bookshelf[Shelf].AllBooksTaken();
// If its NOT TRUE that all the books are gone, proceed
if (!AllbooksTaken)
{
// If the book that we want is still available, proceed
if (bookshelf[Shelf].books[bookID].available)
{
// Add this person to book they wants history. Reduce this persons booklimit by 1 Add the book to their reference. Finally
// reduce the number of the copies of the book by calling the books removecopy function
bookshelf[Shelf].books[bookID].thisBookHistory.AddHistory(guest);
guest.BookLimit--;
guest.AddBook(desiredBook);
bookshelf[Shelf].books[bookID].RemoveCopy();
}
// This shouldn't execute but is set just in case. Simply recalls this same function again but sets SelectRandomBook() as the second
// argument (desiredBook) and keeps the guest reference the same. So the guest is simply searching for another book
else
{
cout << "Sorry, " << desiredBook << " is not currently available" << endl;
return CheckoutBook(guest, SelectRandomBook() );
}
}
else
cout << "Sorry all books have been taken on this shelf. n";
}
else
cout << "Program error. Shelf and or bookID were not initialized properly.nShelfID: " <<
Shelf << ". BookID: " << bookID << ". Desired book: " << desiredBook << endl; // Either there was a failure or something went wrong
}
else
cout << "Sorry. " << desiredBook << " doesn't exist in this library!" << endl;
}
else
cout << "Sorry, you can't check out any more books" << endl;
}
else
cout << "Error, guest must have a valid name" << endl;
}
// Attempts to return a random book name on one of the shelves. This function will repeat until a reliable name is found.
string SelectRandomBook()
{
string bookName = "Empty"; // Empty bookName holder
int shelfID(rand() % 13), // shelfID picks a random shelf between 0 and 13
bookID; // bookID variable that will be used for later
if (shelfID != 13)
{
bool TakenBooks = bookshelf[shelfID].AllBooksTaken(); // create a bool to hold whether or not all books on the desired shelf are taken or not
// If Taken isn't true (or isn't full capacity) then proceed to this branch
if (!TakenBooks)
{
DualReturnType intType = bookshelf[shelfID].ReferenceArrayHelper(); // Uses DualReturnType structure to hold a reference based on the Reference
// Array Helper function with the shelf id and bookshelf.
// If the array pointer inside our dualtype variable (intType) isn't NULL, proceedd
if (intType.int_Array != NULL)
{
// Initialize this variable based on size we pased into our intType variable
bookID = rand() % intType.int_size;
// Important because we created our own array specifically with its own size and values. We get the value inside at the point of the
// randomly generated bookID
int originalBookID = intType.int_Array[bookID];
// If the bookshelf we want and the book inside it that we want are available, proceed.
if (bookshelf[shelfID].books[originalBookID].available)
{
bookName = GetBookName(shelfID, originalBookID);
}
else
{
// If we get here, delete the array reference we set and call this function again(recursion). This will happen until we get a book that isn't taken.
// Note: the TakenBooks variable prevents us from needlessly repeating the search
delete intType.int_Array;
return SelectRandomBook();
}
// This continues if the book we want is avaialable
delete intType.int_Array;
}
// This shouldn't happen but is here just in case. Simply recalls this function again
else
{
cout << "Retrying book selection. " << endl;
return SelectRandomBook();
}
}
}
return bookName; // If we got here that means the selection was a success. The function ends normally
}
// Simply outputs the history of a desiredbook if it exists on any of the shelves. Different from PrintBooks() which only prints all books on the shelves
void PrintBookHistoryByBook(string Book)
{
if (Book != "")
{
bool Found = FindBook(Book); // Bool reference to hold whether or not the book exists on any of the shelves
int BookSlot(-1); // Slot reference initialized to -1 error
// If the book was found continue, if not ouput a error message
if (Found)
{
int ShelfID = GetBookShelfID_Index(Book); // ShelfID variable class the GetShelfID index function based on the book
BookSlot = bookshelf[ShelfID].GetBookID(Book); // BookSlot variable class which uses the bookshelf variable based on shelfID to find a book.
// Basically the shelf is used to quicken search time
// If the bookslot value isn't negative 1 then, then call PrintBookHistory based on the slot we just received
if (BookSlot != -1)
bookshelf[ShelfID].PrintBookHistory(BookSlot);
}
else
cout << Book << " can't be found. (PrintBookHistoryByBook)n";
}
else
cout << "Sorry, you must insert a valid name into PrintBookHistoryByBook().n";
}
// Prints the history of the books in order from the first shelf to the last
void PrintAllBookHistory()
{
for (int i = 0; i <= 12; ++i)
{
bookshelf[i].PrintAllBookHistory();
}
}
// Gets a book based on a shelfID parameter and on spot parameter.
Book GetBook(int ShelfID, int spot)
{
if (ShelfID >= 0 && ShelfID <= 12 && spot >= 0 && spot <= 11)
{
return bookshelf[ShelfID].books[spot];
}
// If the parameters are out of bounds, then simply return a empty book
else
{
cout << "Spot or shelfId inside GetBook() is out of boundsn";
return Book();
}
}
// Does the same as the above but simply gives the name directly instead of the entire book
string GetBookName(int shelfID, int bookspot)
{
// Simply ensures that the shelfID and bookspot variables are within reasonable bounds (0 - 12) & (0 - 11) respectively
if (shelfID >= 0 && shelfID <= 12 && bookspot >= 0 && bookspot <= 11)
{
return bookshelf[shelfID].books[bookspot].name;
}
else
{
cout << "ShelfID or bookspot inside GetBookName() is out of bounds";
return "NULL";
}
}
private:
Bookshelf bookshelf[13]; // array of shelves A-Z AB, CD, EF, etc. Is private so the user can't do things directly
};
Следующий класс — UserInputHelperClass. Этот класс имеет только две функции, это функции HandlePrintBooks и HandlePrintBooksHistory. Функция HandlePrintBooks работает в одном из трех направлений: она печатает все книги по полкам, позволяет пользователю искать книгу, используя название книги и ее идентификатор полки, и, наконец, завершает работу по запросу. В качестве параметра она принимает BookGroup. Что касается функции HandlePrintHistory, то она позволяет просмотреть историю всех книг или конкретной книги, если она существует, а также позволяет пользователю вернуться в главное меню по запросу. Функция позволяет повторять это снова и снова, используя цикл, пока не будет нажата определенная клавиша.
Код для этого приведен здесь:
class UserInputHelperClass
{
public:
// Handles the print case 1 from the center. This function will do 1 of 3 actions: 1.) Terminate upon user request 2.) Find a specific book by asking for a
// shelfID and a bookID 3.) PrintAll books on all shelves
void HanldePrintingAllBooks(BookGroup mainRef)
{
cout << "Would you like to print all books or just one? A for all, 1 for specific, N to returnn";
char input(' ');
// First ask the user for one of three keys, 1, A or N. If the user doesn't do this this will repeat until then
while (input != '1' && input != 'A' && input != 'N')
{
// Asks for only a single key only
input = _getch();
// Digit checkers so digits won't proceed through. If the key that the user has entered is a lowercase letter, then simply raise it to uppercase
if (!isdigit(input) )
if (islower(input))
input = toupper(input);
// Simply repeats the same string as the above but with a error message
if (input != 'A' && input != '1' && input != 'N')
cout << "Sorry please try again. A for All books, 1 for specific, N for terminationn";
}
// Assuming one of the 3 keys above was given, then proceed to execute based on their action.
switch (input)
{
// The first case if the user wants to manually select a book based on index
case '1':
{
cout << "Please enter a shelfID between 1 to 13 or N to terminate" << endl;
int indexShelf = 0; // initialized bookshelf ID
int indexBook = 0; // initialized book ID
bool continueLoop = false; // Boolean to determine whether or not we need to keep asking the user for information
string holdervalue(""); // will hold the input of our user
// This will continue on until the user either quits, or they enter a correct value
while (!continueLoop)
{
// ask for user input
cin >> holdervalue;
// If the value the user just entered is less than or equal to 2 in length, i.e a number (0 - 99) or two letters, proceed
if (holdervalue.size() <= 2)
{
// The case for if the size is only one character long
if (holdervalue.size() == 1)
{
// If the only character is a digit, then set our indexShelfID to what that digit is, if it isn't a digit, then captialize the letter inside
if (isdigit(holdervalue[0]))
{
indexShelf = holdervalue[0] - '0';
}
else
holdervalue[0] = toupper(holdervalue[0]);
}
// The case for if the size is 2, not 1 and not 0
else
{
// If the first character in the input string is a digit, then set the indexShelf variable to this value. Remove the null character to convert
// it to a digit. If we got here then if the second character in the string is also a digit, then mutliply the value that's in the indexShelf
// already by ten, and then add this second value to the string. This is ensure that the number is what was originally typed. I.e, 77 Index = 7.
// 7 * 10 = 70 + 7 = 77
if (isdigit(holdervalue[0]))
{
indexShelf = holdervalue[0] - '0';
if (isdigit(holdervalue[1]))
{
indexShelf *= 10;
indexShelf += holdervalue[1] - '0';
}
}
}
// Start with the null termination first to avoid early cancellation by some other value, and include certain types. If this is true, exit the function
if (holdervalue == "N" || holdervalue == "NN" || holdervalue == "nn")
{
cout << "Terminating" << endl;
return;
}
// If the indexShelf is greater than or equal to 14, then it is too high. Print a string and continue
else if (indexShelf >= 14)
cout << "Number too high. Please enter a shelfID between 1 to 13 or N to terminate" << endl;
// If the indexShelf value is less than or equal to 0, then this value is too low. Print a string and continue
else if (indexShelf <= 0)
cout << "Number too low. Please enter a shelfID between 1 to 13 or N to terminate" << endl;
// If all above conditions were not triggered, then the user entered a valid value. Set the continueLoop to true (!false) and stop the loop.
// Finally decrease by 1, this is to ensure that the values aren't out of bounds
else
{
cout << "Valid input." << endl;
continueLoop = !(continueLoop);
indexShelf -= 1;
}
}
// Then the size is too long. Simply print a string and continue like the above conditions
else
cout << "Value too long. Please enter a valid shelfID between 1 to 13 or N to terminate" << endl;
}
// Reset the basic values again for the bookID
continueLoop = false;
holdervalue = " ";
cout << "Please enter a bookID between 1 to 12 or N to terminate" << endl;
// Repeats the same above while loop but it does this for a bookID, and the max limit is decreased by 1 to match our bookID limit and prevent out of bounds errors
while (!continueLoop)
{
cin >> holdervalue;
// If the value the user just entered is less than or equal to 2 in length, i.e a number (0 - 99) or two letters, proceed
if (holdervalue.size() <= 2)
{
// The case for if the size is only one character long
if (holdervalue.size() == 1)
{
// If the only character is a digit, then set our indexBook to what that digit is, if it isn't a digit, then captialize the letter inside
if (isdigit(holdervalue[0]))
{
indexBook = holdervalue[0] - '0';
}
else
holdervalue[0] = toupper(holdervalue[0]);
}
// The case for if the size is 2, not 1 and not 0
else
{
// If the first character in the input string is a digit, then set the indexBook variable to this value. Remove the null character to convert
// it to a digit. If we got here then if the second character in the string is also a digit, then mutliply the value that's in the indexBook
// already by ten, and then add this second value to the string. This is ensure that the number is what was originally typed. I.e, 77 Index = 7.
// 7 * 10 = 70 + 7 = 77
if (isdigit(holdervalue[0]))
{
indexBook = holdervalue[0] - '0';
if (isdigit(holdervalue[1]))
{
indexBook *= 10;
indexBook += holdervalue[1] - '0';
}
}
}
// Start with the null termination first to avoid early cancellation by some other value, and include certain types. If this is true, exit the function
if (holdervalue == "N" || holdervalue == "NN" || holdervalue == "nn")
{
cout << "Terminating" << endl;
return;
}
// If the indexBook is greater than or equal to 14, then it is too high. Print a string and continue
else if (indexBook >= 13)
cout << "BookID too high. Please enter a shelfID between 1 to 13 or N to terminate" << endl;
// If the indexBook value is less than or equal to 0, then this value is too low. Print a string and continue
else if (indexBook <= 0)
cout << "BookID too low. Please enter a shelfID between 1 to 13 or N to terminate" << endl;
// If all above conditions were not triggered, then the user entered a valid value. Set the continueLoop to true (!false) and stop the loop. Then
// indexBook is decremented by 1 to fit the loop.
else
{
cout << "Valid bookID." << endl;
continueLoop = !(continueLoop);
indexBook -= 1;
}
}
}
// This line is for confirmation only
cout << "IndexShelf: " << indexShelf << " BookID: " << indexBook << endl;
// Call the PrintBookByShelfAndID helper function to take care of the printing of the book we want
mainRef.PrintBookByShelfAndID(indexShelf, indexBook);
break;
}
case 'A':
{
mainRef.PrintAllBooks(); // In this case simply print all the books in the entire library
cout << "Returning to centernn";
break;
}
case 'N':
cout << "Returning." << endl;
break;
}
}
// Function that prints the books history of either all books or a desired book
void HandlePrintingBookHistory(BookGroup &mainRef)
{
cout << "Would you like to enter the name of a book or the ID? 1 for bookID, A for all books, F to search manually , N to return. n";
// Initializes basic variables that we will use for this function
bool continueLoop = false;
bool innerloop = false;
string bookName;
char input = ' ';
// Initial placement loop to determine the outcome based on user value. If it is valid we will either terminate or proceed deeper into the function
while (!continueLoop)
{
// Asks for only a single key press
input = _getch();
// If the input isn't a number that we want, then captialize it. Note: This works because we only gather a single key press, so it is impossible for the user to enter
// a number that is greater than 9 or less than 0. Negatives can't be counted as the '-' is a special character
if (input <= 0 || input >= 10)
input = toupper(input);
// Switch statement based on that input value the user just entered
switch (input)
{
// Easiest case scenario. Simply print the history of all books and then return
case 'A':
{
mainRef.PrintAllBookHistory();
cout << "n";
continueLoop = !continueLoop;
cout << "Returning.nn";
return;
}
// If this key is pressed, simply proceed forward as this is a main case
case '1':
continueLoop = !continueLoop;
break;
// This key is also a special case we will proceed again
case 'F':
continueLoop = !continueLoop;
break;
// This key is a termination key but unlike 'A' we don't print anything and just exist
case 'N':
cout << "Returning. nn";
continueLoop = !continueLoop;
return;
break;
// User didn't print a valid key. Will print a error message and then go back to the top which repeats this entire procees until a valid key is given
default:
cout << "Sorry, you didn't enter a valid character. Please enter 1 to use bookID, A for all books F to search for the bookname, or N to return. n";
break;
}
}
continueLoop = !continueLoop;
// Placeholder values that hold shelfID and bookID values
int shelfID(-1);
int bookID(-1);
// A string that we will use to hold the users input from now on
string bookdetector("");
// The main loop or outer loop that will continue to ask for input until user termination or search failure
while (!continueLoop)
{
// Switch statement based on input
switch (input)
{
case '1':
{
cout << "Please enter a shelfID first between 1 to 13.n";
cin >> bookdetector; // ask for user input
innerloop = false;
// Our loop inside of the main loop. This innerloop is attempting to ask the user for a valid shelfID between 1 to 13 or for N to terminate
while (!innerloop)
{
// Checker for the N key. If pressed then it will break the entire function and return.
if (bookdetector == "N" || bookdetector == "n")
{
cout << "Returning.nn";
innerloop = true;
return;
}
// If the value the user entered is 2 keys or less continue
if (bookdetector.size() <= 2)
{
// If the user only entered 1 key
if (bookdetector.size() == 1)
{
// If that key is a digit, then set the shelfID to this value. If it isn't a digit, then set the users input to E for error handling
if (isdigit(bookdetector[0]))
{
shelfID = bookdetector[0] - '0';
}
else
bookdetector = "E";
}
// The user has entered a size that is equal to 2.
else
{
// If the first key is a digit, then set shelfID to that digit
if (isdigit(bookdetector[0]))
{
shelfID = bookdetector[0] - '0';
// If the second key is a digit, then multiply the shelfID by 10, and then add the second key to the shelfID
if (isdigit(bookdetector[1]))
{
shelfID *= 10;
shelfID += bookdetector[1] - '0';
}
// If the second key isn't a digit, then set the users value to E for error handling
else
bookdetector = "E";
}
// If the first key isn't a digit, then set the users value to E for error handling
else
bookdetector = "E";
}
// Termination key
if (bookdetector == "N" || bookdetector == "n")
{
cout << "Returning.nn";
return;
}
// Error handling key. Will simply print a error message and let the flow proceed normally thus resulting in a repeat
else if (bookdetector == "E")
{
cout << "Invalid value. ShelfID must be between 1 and 13. Retry or press N to terminate.n";
}
// Another error case. This happens if the user entered a value that doesn't corresspond to the program. Prints 2 sepearte message depending on the case
// and lets the program flow normally resulting in a repeat
else if (shelfID <= 0 || shelfID >= 14)
{
if (shelfID == 0)
cout << "Error, shelfID is too low. Please enter a value between 1 to 13 or N to terminate.n";
else
cout << "Error, shelfID is too high. Please enter a value between 1 to 13 or N to terminaten";
}
// If the user got here they successflly entered a valid shelfID. Decrease it by 1 to fit our loop, since value must be between 1 to 13,
// set the innerloop to true now, and then break the flow of the innerLoop which stops repetition
else
{
cout << "Success!! " << shelfID << endl;
shelfID -= 1;
innerloop = !innerloop;
break;
}
}
// User entered a value of 3 or above. These are not accepted
else
{
cout << "Value entered is too long.nPlease enter a shelfID between 1 to 13 or N to trminate.n";
}
// Asks the user for input again at the end if this loop isn't broken
cin >> bookdetector;
}
// reset the innerloop so we will use it again
innerloop = false;
cout << "Please print a bookID between 1 to 12 or press N to terminaten";
// Exactly the same as the above innerloop but with the book condition instead. So values are between 1 to 12
while (!innerloop)
{
cin >> bookdetector;
if (bookdetector == "N" || bookdetector == "n")
{
cout << "Returning.nn";
innerloop,continueLoop = true;
return;
}
if (bookdetector.size() <= 2)
{
if (bookdetector.size() == 1)
{
if (isdigit(bookdetector[0]))
{
bookID = bookdetector[0] - '0';
}
else
bookdetector = "E";
}
else
{
if (isdigit(bookdetector[0]))
{
bookID = bookdetector[0] - '0';
if (isdigit(bookdetector[1]))
{
bookID *= 10;
bookID += bookdetector[1] - '0';
}
else
bookdetector = "E";
}
else
bookdetector = "E";
}
if (bookdetector == "N" || bookdetector == "n")
{
cout << "Returning.nn";
innerloop = true;
continueLoop = true;
return;
}
else if (bookdetector == "E")
{
cout << "Invalid value. bookID must be between 1 and 12. Retry or press N to terminate.n";
}
else if (bookID <= 0 || bookID >= 13)
{
if (bookID == 0)
cout << "Error, bookID is too low. Please enter a value between 1 to 12 or N to terminate.n";
else
cout << "Error, bookID is too high. Please enter a value between 1 to 12 or N to terminaten";
}
else
{
cout << "Success!! " << shelfID << endl;
bookID -= 1;
innerloop = !innerloop;
break;
}
}
else
{
cout << "Value entered is too long.nPlease enter a bookID between 1 to 12 or N to trminate.n";
}
}
// Create a book reference so we can check if the shelfID and bookID found a valid book
Book myBook = mainRef.GetBook(shelfID, bookID);
// If the book we just created isn't empty, then print that books history, otherwise print a error message. Regardless of outcome, terminate this function
if (!myBook.emptyBook() )
mainRef.PrintBookHistoryByBook(myBook.name);
else
cout << "Sorry, but that book doesn't exist. Returning.nn";
continueLoop = true;
break;
}
// The case when the user presses the F key. Allows them to find the book by its name
case 'F':
{
cout << "Please enter the name of the desired book.n";
std::getline(std::cin, bookName);
// If the bookName the user entered exists inside the main structre, then print that books history and terminate this loop
if (mainRef.FindBook(bookName))
{
mainRef.PrintBookHistoryByBook(bookName);
continueLoop = !continueLoop;
}
// If the bookname isn't valid, basically ask them if they'd like to try again. If the input they entered isn't a number between the values we want, captialize it.
else
{
cout << "Would you like to try again (F) or terminate(N)?n";
input = _getch();
if (input < 0 || input >= 10)
input = toupper(input);
}
break;
}
case 'N':
cout << "Returning.nn";
continueLoop = !continueLoop;
return;
default:
{
cout << "Sorry, invalid character entered. Please type 1 to search by 1, F to search by name, or N to terminate.n";
input = _getch();
if (input < 0 || input >= 10)
input = toupper(input);
}
}
}
}
};
Следующая функция — это функция setUpBookNames. Это действительно быстрая и простая функция. Она принимает параметр, указывающий на активный экземпляр BookGroup, и добавляет список случайных названий видеоигр в качестве названий книг и случайный набор страниц, вызывая функцию AddBooks внутри параметра BookGroup.
Это выглядит следующим образом:
ref.AddBooks(Alphabet, books_Ref, Pages);
Переменная Alphabet — строковый массив названий типа «Crash Bandicoot», «Jack and Daxter», «Horizon Zero Dawn», а books_Ref — массив целых чисел, имеющих случайные значения от 20 до 1020. Вот один из таких индексов, хотя все они выглядят одинаково:
rand() % 1000 + 20
Далее следует функция InitializeLibraryGuests, которая принимает в качестве единственного аргумента указатель типа Person. Я использую это пространство для установки двух массивов строк, оба значительных размеров; один только из имен, другой только как фамилии. В конце этой функции я объединяю их в одно имя, передавая их оба вместе в качестве аргумента в аргументе указателя Person, а также увеличивая статический целочисленный ID на единицу для каждого успешного имени и передавая его также. Массивы строк FirstNames и LastNames основаны на переменной LibaryGuestSize, которая, как мы помним, является глобальной. Сгенерировав случайный индекс в этом диапазоне, я могу легко получить индекс, который я использовал для прямого подключения к обоим соответствующим строковым массивам.
Это выглядит примерно так:
// Go through a loop based on the guest size and setup the guests values
for (int i = 0; i < LibraryGuestSize; ++i)
{
randomFirstIndex = rand() % LibraryGuestSize; // Generate a random number between 0 and LibraryGuestSize(156)
randomLastIndex = rand() % LibraryGuestSize; // Same as the above but inside lastindex
// Make the guests name a full value based on random selections between the first name and last names. The indicies we made are used as selectors
Guests[i].name = FirstNames[randomFirstIndex] + " " + LastNames[randomLastIndex];
// Increase the static integer value by 1 so every guests has a incremeting ID value
ID += 1;
Guests[i].GuestID = ID; // Set the guests' ID to the static ID.
}
}
Последняя часть, которую необходимо обсудить, это та, которая собирает все вместе, и это функция main. Функция main сначала создает массив лиц для симуляции:
Person *LibraryGuests = new Person[LibraryGuestSize];
Затем она настраивает их для использования, вызывая функцию InitializeLibraryGuest следующим образом:
InitializeLibraryGuests(LibraryGuests);
А затем создает ссылку на BookGroup и вызывает setUpBookNames, используя этот обработчик.
После этого переменная LibraryGuests, которая была только что создана, добавляется в обработчик BookGroup вместе со случайной книгой в цикле for для легкого доступа. Этот код выглядит следующим образом:
string myBook;
myBook = mainHandle.SelectRandomBook(); // Selects a random book from somewhere on the shelf and returns its value
mainHandle.CheckoutBook(LibraryGuests[i], myBook); // Makes it so that every user checks out a book
Наконец, цикл while используется для различных случаев выбора чисел путем проверки ввода с помощью переменной держателя символов и класса UserInputHelperClass, который обрабатывает все дополнительные случаи и возвращается сюда по завершении или по желанию.
Postmortem
Самое главное, что я бы сделал по-другому, если бы делал это снова, — это изменил бы способ извлечения данных из книг. Хотя все хорошо так, как есть сейчас, я думаю, что все было бы лучше, если бы я просто использовал хэш-таблицу для ключей и индексов, что я в некоторой степени и сделал, но не так, как мне нравится. Я решил не использовать LinkedList, который я добавил, потому что это не имело смысла для меня в то время, постоянно удаляя и удаляя узлы, поскольку они всегда статичны в любом случае. Однако я мог бы просто очистить данные внутри узла, пока он не станет активным. Я не разочарован тем, что сделал, просто интересно, мог ли я сделать это по-другому. Изначально я хотел взять книги, напечатанные BookHistory, и добавить их в файл, который можно было бы легко увидеть. К сожалению, я не сделал этого, а хотелось бы. Было бы здорово посмотреть, потому что результаты не статичны. Еще одна вещь, которую я хотел сделать, это сделать данные более гибкими. Под гибкостью я подразумеваю, что пользователи могут добавлять книги и имена в базу данных, а не жестко кодировать ее, как сейчас. Несмотря на эти недостатки, я все равно доволен тем, что получилось, и это определенно можно улучшить.
Это было довольно длинное и подробное объяснение, и я надеюсь, что оно не было слишком плохим с точки зрения длины. Вы можете посетить мою страницу на GitHub, если хотите попробовать эту программу самостоятельно, здесь.
Спасибо за чтение, если вы дочитали до этого момента, и не стесняйтесь проверить некоторые из моих других работ по кодированию.
Искренне,
Кристиан Бэнкс