TA Lab Program (Stacks & Queues)

Posted on by on May 29th, 2011 | 0 Comments »

Downloads:

Assignment :

Source Code :

Compiled Executables :

  • Windows (to-add)
  • Linux (to-add)

Documentation :

  • Doxygen (to-add)

Sample Test Files :

Assignment:

GDE Error: Unable to load profile settings

Source Code:

//////////////////////////////////////////////////////////////////////////////
///  
///  \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;
}

Match Making Recursion Program
Buddy Book Program

Categorized Under

ProgrammingProgramsSchoolwork

About Nick Guthrie

» has written 38 posts

Leave a Reply

You must be logged in to post a comment.

History