Insight into something.
|
Assignment : |
|
|
Source Code : |
|
|
Compiled Executables : |
|
|
Documentation : |
|
|
Sample Test Files : |
//////////////////////////////////////////////////////////////////////////////
///
/// \file TALab.c
/// \brief Simulates students visiting TAs for help. Demonstrates stacks and
/// queues.
///
/// <br>Author(s): Nicholas Guthrie
/// <br>Created: 2011-03-21
/// <br>Email: nickguthrie@knights.ucf.edu
/// <br>Web: http://nickguthrie.com
/// <br>Title: TA Lab (Stacks & Queues)
/// <br>Course: COP3502C Compute Science I
/// <br> Class #: 16173
/// <br>Section #: 0001
/// <br>Version #: 276
///
/// THIS SOFTWARE IS PROVIDED BY THE NICHOLAS GUTHRIE''AS IS'' AND ANY EXPRESS
/// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
/// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
/// NO EVENT SHALL UCF BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
/// EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
/// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
/// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
/// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
/// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
/// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///
////////////////////////////////////////////////////////////////////////////////
///////////////////////////
// Library Includes //
///////////////////////////
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h> //necessary for malloc
#include <string.h>
///////////////////////////
// #defines & Constants //
///////////////////////////
#define SIZE 300
#define EMPTY -1
///////////////////////////
// Struct Declarations //
///////////////////////////
typedef struct COP3502student
{
char firstName[20];
char lastName[20];
int enterTime;
int numQuestions;
int numAnswered;
int laptopSerialNum;
int number; ///< reference # so queues can be used
} student;
typedef struct teachingAssistant
{
char name[21]; ///< only use first names for TAs >//
int startTimes[3]; ///< start times for each day of simulatoin >//
int endTimes[3]; ///< end times for each day of simulation >//
student *studentWithTA; ///< pointer to type struct COP3502student >//
int minute; ///< # of minutes TA has spent with a student >//
int number; ///< reference # so queues can be used
int active;
} TA;
////////////////
// Stacl //
////////////////
struct stack
{
int items[SIZE];
int sTop;
};
////////////////
// Queue //
////////////////
// Stores one node of the linked list.
struct node {
int data;
struct node* next;
};
// Stores our queue.
struct queue {
struct node* front;
struct node* back;
};
///////////////////////////
// Function Declarations //
///////////////////////////
///////////
// Stack //
///////////
void sInitialize(struct stack* stackPtr);
int sFull(struct stack* stackPtr);
int sPush(struct stack* stackPtr, int value);
int sEmpty(struct stack* stackPtr);
int sPop(struct stack* stackPtr);
int sTop(struct stack* stackPtr);
///////////
// Queue //
///////////
void qInit(struct queue* qPtr);
int qEnqueue(struct queue* qPtr, int val);
int qDequeue(struct queue* qPtr);
int qEmpty(struct queue* qPtr);
int qFront(struct queue* qPtr);
////////////////////////
// Input & Processing //
////////////////////////
void getTime(int time, FILE *output);
void printSummary(FILE *output, int time, int numStudentsEntered,
int numHappyStudents);
///////////////////////////
// Main //
///////////////////////////
int main()
{
///////////////
// Variables //
///////////////
FILE *input, *output;
struct COP3502student *Student[3][300];
struct teachingAssistant* Mentor[300]; //DEBUG what is max TA? <= students?
struct stack *sLaptop;
struct queue* qLDM; ///< qLDM is a line for students getting laptops
struct queue* qLine; ///< qLine is a line for students w/laptops
struct queue* qTA; ///< qTA is a line of TAs ready to serve
struct queue* qQuestions; ///< gMoreQuestions for students with lots of questions
int numLaptops; ///< numLaptops #(+)laptops to be put in machine
int numStudentsPerDay; ///< numStudentsPerDay #(+)students for M,T,W
int numPrograms; ///< numPrograms #(+)of programs for the semester
int numTAs; ///< numTAs #(+) of TAs on duty
int tserial; ///< tserial temp placeholder for laptop serial #
int time; ///< time stores as minutes past midnight
int day;
int LDMTime; ///< keeps track if LDM has been w/student
int numStudentsEntered; ///< keeps track of students in lab
int LabOpen;
int activeTAs;
int LDMTimer;
int numHappyStudents;
int i, j, k; ///< i,j, k navigation variables
///////////////
// Input //
///////////////
/////////////////////
// Initializations //
/////////////////////
sLaptop = (struct stack*)malloc(sizeof(struct stack));
qQuestions = (struct queue*)malloc(sizeof(struct queue));
qLDM = (struct queue*)malloc(sizeof(struct queue));
qLine = (struct queue*)malloc(sizeof(struct queue));
qTA = (struct queue*)malloc(sizeof(struct queue));
sInitialize(sLaptop);
qInit(qLDM);
qInit(qLine);
qInit(qTA);
qInit(qQuestions);
output = fopen("out.txt", "w");
for(i = 0; i<3; i++){
for(j = 0; j<300; j++){
Student[i][j] =
(struct COP3502student*)malloc(sizeof(struct COP3502student));
}
}
////////////////
// Open File //
////////////////
input = fopen ("input.txt", "r");
//file open error checking
if(input == NULL)
{
printf("File not Found, Press ENTER to exit\n");
getchar();
//return 0;
}
///////////////////
// Collect Input //
///////////////////
// collect laptop serial numbers & store in Stack
fscanf(input, "%d", &numLaptops);
for(i = 0; i < numLaptops; i++){
fscanf(input, "%d", &tserial);
sPush(sLaptop, tserial);
}
// collect TA info
fscanf(input, "%d", &numTAs); //# of TAs
// store data on TAs
for(i = 0; i < numTAs; i++){
Mentor[i] =
(struct teachingAssistant*)malloc(sizeof(struct teachingAssistant));
Mentor[i]->number = i; //store reference # of TA
Mentor[i]->active = 0;
Mentor[i]->studentWithTA = NULL;
Mentor[i]->minute = 0;
fscanf(input, "%s", Mentor[i]->name); // store first name
for(j = 0; j < 3; j++){
fscanf(input, "%d", &Mentor[i]->startTimes[j]); //start times
fscanf(input, "%d", &Mentor[i]->endTimes[j]); //end times
}
}
fscanf(input, "%d", &numPrograms); // # of programs
/////////////////////
// OUTPUT //
/////////////////////
// PROGRAMS
for(i = 0; i<numPrograms; i++){
fprintf(output, "**********\nProgram %d:\n**********\n\n", i+1);
// DAYS
// process all students for given day
for(day = 0; day<4; day++){
switch(day){
case 1:
fprintf(output, "\n\nMonday's Lab Summary:\n");
printSummary(output, time, numStudentsEntered, numHappyStudents);
break;
case 2:
fprintf(output, "\n\nTuesday's Lab Summary:\n");
printSummary(output, time, numStudentsEntered, numHappyStudents);
break;
case 3:
fprintf(output, "\n\nWednesday's Lab Summary:\n");
printSummary(output, time, numStudentsEntered, numHappyStudents);
fclose(input);
fclose(output);
return 0; //exit the program here
}
///////////////
// Variables //
///////////////
time = 0; ///< time stores as minutes past midnight
LDMTime = 0; ///< keeps track if LDM has been w/student
numStudentsEntered = 0; ///< keeps track of students in lab
LabOpen = 0;
activeTAs = 0;
LDMTimer = 0;
numHappyStudents = 0;
time = -1;
fscanf(input, "%d", &numStudentsPerDay);
for(k = 0; k<numStudentsPerDay; k++){
Student[day][k]->number = k;
Student[day][k]->laptopSerialNum = 0;
Student[day][k]->numAnswered = 0;
// store student entry time
fscanf(input, "%d", &Student[day][k]->enterTime);
// store student names
fscanf(input, "%s", Student[day][k]->firstName);
fscanf(input, "%s", Student[day][k]->lastName);
// store student questions
fscanf(input, "%d", &Student[day][k]->numQuestions);
}
// print the day
switch(day){
case 0:
fprintf(output, "Monday:\n\n");
break;
case 1:
fprintf(output, "\n\nTuesday:\n\n");
break;
case 2:
fprintf(output, "\n\nWednesday:\n\n");
break;
}
while(activeTAs != -1 || !qEmpty(qLDM))
{
time++;
//Check Newly Available TAs
for(k = 0; k<numTAs; k++){
if(Mentor[k]->startTimes[day] == time &&
Mentor[k]->endTimes[day] != time){
getTime(time, output);
fprintf(output, "%s has begun lab hours.\n", Mentor[k]->name);
Mentor[k]->active = 1;
qEnqueue(qTA, k);
LabOpen = 1;
activeTAs++;
}}//End Newly Available TAs
//Process LDM
if(!qEmpty(qLDM)){
//time to offset the odd behavior of LDM by 1 minute
if(LDMTimer == 0){
LDMTimer++;
}
else{
LDMTimer = 0;
//student has no laptop (therefore getting one)
if(Student[day][qFront(qLDM)]->laptopSerialNum == 0){
//lab is open so getting a laptop
if(LabOpen == 1){
getTime(time, output);
fprintf(output, "%s %s has borrowed laptop %d and moved to the TA line.\n",
Student[day][qFront(qLDM)]->firstName,
Student[day][qFront(qLDM)]->lastName, sTop(sLaptop));
Student[day][qFront(qLDM)]->laptopSerialNum = sTop(sLaptop);
sPop(sLaptop);
qEnqueue(qLine, qFront(qLDM));
}
//lab is closed so never got a laptop & leaving
else{
getTime(time, output);
fprintf(output, "%s %s never even got a laptop and went home"
" FRUSTRATED.\n",
Student[day][qFront(qLDM)]->firstName,
Student[day][qFront(qLDM)]->lastName);
}
}
//has a serial so returning a laptop
else{
// forced to return the laptop w/questions left
if((double)Student[day][qFront(qLDM)]->numAnswered /
(double)Student[day][qFront(qLDM)]->numQuestions <= 0.75){
getTime(time, output);
fprintf(output, "%s %s has returned laptop %d and went"
" home FRUSTRATED.\n",
Student[day][qFront(qLDM)]->firstName,
Student[day][qFront(qLDM)]->lastName,
Student[day][qFront(qLDM)]->laptopSerialNum);
}
// no questions left, HAPPY
else{
getTime(time, output);
fprintf(output, "%s %s has returned laptop %d and went"
" home HAPPY.\n",
Student[day][qFront(qLDM)]->firstName,
Student[day][qFront(qLDM)]->lastName,
Student[day][qFront(qLDM)]->laptopSerialNum);
numHappyStudents++;
}
sPush(sLaptop, Student[day][qFront(qLDM)]->laptopSerialNum);
}
qDequeue(qLDM); //DEBUG - this doesn't seem to work
}}//LDM Processed
//Answer Questions
for(k = 0; k<numTAs; k++){
if(Mentor[k]->studentWithTA != NULL){
Mentor[k]->minute++;
//if time is 5 remove student (to LDM or Line)
if(Mentor[k]->minute == 5){
Mentor[k]->studentWithTA->numAnswered++;
if(Mentor[k]->studentWithTA->numQuestions -
Mentor[k]->studentWithTA->numAnswered > 0){
qEnqueue(qQuestions, Mentor[k]->studentWithTA->number);
}
else{
getTime(time, output);
fprintf(output, "%s %s has no more questions and will now "
"return the laptop.\n",
Mentor[k]->studentWithTA->firstName,
Mentor[k]->studentWithTA->lastName);
qEnqueue(qLDM, Mentor[k]->studentWithTA->number);
}
Mentor[k]->minute = 0;
Mentor[k]->studentWithTA = NULL;
}}}//Questions Answered
//move the people with more questions to Line (get less priority than
//those who haven't asked)
while(!qEmpty(qQuestions)){
getTime(time, output);
fprintf(output, "%s %s has had one question answered and gotten back"
" in line.\n",
Student[day][qFront(qQuestions)]->firstName,
Student[day][qFront(qQuestions)]->lastName);
qEnqueue(qLine, qFront(qQuestions));
qDequeue(qQuestions);
}//end qQuestions to qLine
//have TAs start working with students
for(k = 0; k<numTAs; k++){
if(Mentor[k]->active == 1 && Mentor[k]->studentWithTA == NULL
&& !qEmpty(qLine)){
getTime(time, output);
fprintf(output, "%s %s is getting help from %s.\n",
Student[day][qFront(qLine)]->firstName,
Student[day][qFront(qLine)]->lastName, Mentor[k]->name);
Mentor[k]->studentWithTA = Student[day][qFront(qLine)];
qDequeue(qLine);
}}//END TA's working with Students
//have students enter from outside
while(Student[day][numStudentsEntered]->enterTime == time &&
LabOpen == 1){
getTime(time, output);
fprintf(output, "%s %s has arrived in the Cave.\n",
Student[day][numStudentsEntered]->firstName,
Student[day][numStudentsEntered]->lastName);
qEnqueue(qLDM, numStudentsEntered);
numStudentsEntered++;
}//End Students Entering
//Check for TA's that have to leave
for(k = 0; k<numTAs; k++){
//DEBUG - having trouble setting special case for TAs + student
if(Mentor[k]->endTimes[day] == time && Mentor[k]->active == 1){
getTime(time, output);
fprintf(output, "%s has finished lab hours.\n",
Mentor[k]->name);
Mentor[k]->active = 0;
activeTAs--;
if(activeTAs == 0){
activeTAs = -1;
LabOpen = 0;
while(!qEmpty(qLine)){
qEnqueue(qLDM, qFront(qLine));
qDequeue(qLine);
}
while(!qEmpty(qQuestions)){
qEnqueue(qLDM, qFront(qQuestions));
qDequeue(qQuestions);
}
}}}//leaving TAs
}//end time
}//end day
}//end program
}
//////////////////////////////
// Function Implamentations //
//////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///
/// \brief Prints time in a structured format to output file.
/// \param time The time to print
/// \param *output The file to output to.
/// \return void
///
////////////////////////////////////////////////////////////////////////////////
void getTime(int time, FILE *output){
if(time/60 == 0)
fprintf(output, "12:%.2d PM: ", time%60);
else
fprintf(output, "%d:%.2d PM: ", time/60, time%60);
}
////////////////////////////////////////////////////////////////////////////////
///
/// \brief Prints the summary of events during a day at the lab.
/// \param *output The file to output to.
/// \param time The time the lab was open.
/// \param numStudentsEntered The number of students that entered the lab.
/// \param numHappyStudents The number of students that left the lab happy.
///
////////////////////////////////////////////////////////////////////////////////
void printSummary(FILE *output, int time, int numStudentsEntered,
int numHappyStudents){
fprintf(output, "The TA Lab was open for %d hours and %d minutes.\n%d students"
"visited the lab. Out of those students, only %d left happy.\n"
"The remaing left frustrated.\n\nLesson Learned: "
"Do not procrastinate! Start programs early!\n",
time/60, time%60, numStudentsEntered, numHappyStudents);
}
///////////////////////////
// Stack Functions //
///////////////////////////
////////////////////////////////////////////////////////////////////////////////
///
/// \brief Initializes a stack by properly setting the value of sTop.
/// \return void
///
////////////////////////////////////////////////////////////////////////////////
void sInitialize(struct stack* stackPtr) {
stackPtr->sTop = -1;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \brief Adds a value onto a stack (pushes).
/// \param stackPtr a valid struct stackPtr
/// \param value value to push
/// \return 1 if the push is successfull
/// 0 if the stack is Full and the pusth can't be done
///
////////////////////////////////////////////////////////////////////////////////
int sPush(struct stack* stackPtr, int value) {
// Check if the stack is full.
if (sFull(stackPtr))
return 0;
// Add value to the top of the stack and adjust the value of the top.
stackPtr->items[stackPtr->sTop+1] = value; //DEBUG - cause segfault
(stackPtr->sTop)++;
return 1;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \brief Checks to see if stackPtr is full.
/// \param stackPtr struct stackPtr to check
/// \return true if the stack pointed to by stackPtr is full.
///
////////////////////////////////////////////////////////////////////////////////
int sFull(struct stack* stackPtr) {
return (stackPtr->sTop == SIZE - 1);
}
////////////////////////////////////////////////////////////////////////////////
///
/// \brief Checks to see if stackPtr is empty.
/// \param stackPtr struct stackPtr to check
/// \return true if the stack pointed to by stackPtr is empty.
///
////////////////////////////////////////////////////////////////////////////////
int sEmpty(struct stack* stackPtr) {
return (stackPtr->sTop == -1);
}
////////////////////////////////////////////////////////////////////////////////
///
/// \brief Checks to see if stackPtr is full.
/// /pre The stack pointed to by stackPtr is NOT empty.
/// \param stackPtr struct stackPtr to check
/// \return The value on the top of the stack is popped and returned IF NOT empty
/// -1 IF the stack pointed to by stackPtr is empty.
///
////////////////////////////////////////////////////////////////////////////////
int sPop(struct stack* stackPtr) {
int retval;
// Check the case that the stack is empty.
if (sEmpty(stackPtr))
return EMPTY;
// Retrieve the item from the top of the stack, adjust the top and return
// the item.
retval = stackPtr->items[stackPtr->sTop];
(stackPtr->sTop)--;
return retval;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \brief Returns the top of stackPtr.
/// \param stackPtr is a NOT empty stack
/// \return The value on the top of the stack if the stack is NOT empty
/// -1 IF the stack pointed to by stackPtr is empty
///
////////////////////////////////////////////////////////////////////////////////
int sTop(struct stack* stackPtr) {
// Take care of the empty case.
if (sEmpty(stackPtr))
return EMPTY;
// Return the desired item.
return stackPtr->items[stackPtr->sTop];
}
///////////////////////////
// Queue Functions //
///////////////////////////
////////////////////////////////////////////////////////////////////////////////
///
/// \brief Initializes a que by properly setting members front & back.
/// \param qPtr valid struct queue
/// \post the struct qPtr points to will be set up to represent an empty queue
/// \return void
///
////////////////////////////////////////////////////////////////////////////////
void qInit(struct queue* qPtr) {
// Just set both pointers to NULL!
qPtr->front = NULL;
qPtr->back = NULL;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \brief Adds val to the front of the queue.
/// \param qPtr points to a valid struct que
/// \param val is the value to enqueue into the queue pointed to by qPtr
/// \return 1 IF the operation is successful
/// 0 IF not successfull, & no change will be made to the queue
///
////////////////////////////////////////////////////////////////////////////////
int qEnqueue(struct queue* qPtr, int val) {
struct node* temp;
// Allocate space for a new node to add into the queue.
temp = (struct node*)malloc(sizeof(struct node));
// This case checks to make sure our space got allocated.
if (temp != NULL) {
// Set up our node to enqueue into the back of the queue.
temp->data = val;
temp->next = NULL;
// If the queue is NOT empty, we must set the old "last" node to point
// to this newly created node.
if (qPtr->back != NULL)
qPtr->back->next = temp;
// Now, we must reset the back of the queue to our newly created node.
qPtr->back = temp;
// If the queue was previously empty we must ALSO set the front of the
// queue.
if (qPtr->front == NULL)
qPtr->front = temp;
// Signifies a successful operation.
return 1;
}
// No change to the queue was made because we couldn't find space for our
// new enqueue.
else
return 0;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \brief Dequeues one element from the front of the queue.
/// \param qPtr points to a valid struct queue.
/// \post IF the queue pointed to by qPtr is non-empty, then the value at the
/// front of the queue is deleted from the queue and returned.
/// Otherwise, -1 is returned to signify that the queue was already empty
/// when the dequeue was attempted.
/// \return value at the front of the que IF the queue is non-empty
/// -1 if the queue was already empty
///
////////////////////////////////////////////////////////////////////////////////
int qDequeue(struct queue* qPtr) {
struct node* tmp;
int retval;
// Check the empty case.
if (qPtr->front == NULL)
return EMPTY;
// Store the front value to return.
retval = qPtr->front->data;
// Set up a temporary pointer to use to free the memory for this node.
tmp = qPtr->front;
// Make front point to the next node in the queue.
qPtr->front = qPtr->front->next;
// If deleting this node makes the queue empty, we have to change the back
// pointer also!
if (qPtr->front == NULL)
qPtr->back = NULL;
// Free our memory.
free(tmp);
// Return the value that just got dequeued.
return retval;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \brief Returns the data of qFront from a struct qPtr.
/// \param qPtr points to a valid struct queue.
/// \return value at front if the queue pointed by qPtr is non-empty
/// -1 if the queue is empty
///
////////////////////////////////////////////////////////////////////////////////
int qFront(struct queue* qPtr) {
if (qPtr->front != NULL)
return qPtr->front->data;
else
return EMPTY;
}
////////////////////////////////////////////////////////////////////////////////
///
/// \brief Checks to see if the queue is empty.
/// \param qPtr points to a valid struct queue.
/// \return true if the queue pointed by qPtr is empty
///
////////////////////////////////////////////////////////////////////////////////
int qEmpty(struct queue* qPtr) {
return qPtr->front == NULL;
}