/*     COP 3502C Assignment 1
This program is written by: Talasia Aleris Calderon */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_CHAR 50
#define MAX_QUEUES 12

//STRUCTURES
typedef struct Customer
{
    char* name;
    int checkIn;
    int numTickets;
    int assignedQueue;

} Customer;

typedef struct Node
{
    struct Customer* customerPtr;
    struct Node* next;

} Node;

typedef struct Queue
{
    struct Node* front;
    struct Node* back;
    int size;

} Queue;



//FUNCTION PROTOTYPES
Customer* createCustomer(char customerName[MAX_CHAR], int numOfTickets, int arrivalTime);
Customer* peek(Queue* queuePtr);
int isEmpty(Queue queue);
int queueSize(Queue queue);
void enqueue(Queue* queue, Customer* customer);
Customer* dequeue(Queue* queue);


int main(void) {
    int numCustomers, numBooths;

    //create and initialize static array of 12 queues
    Queue queues[MAX_QUEUES];

    for (int i = 0; i < MAX_QUEUES; ++i)
    {
        queues[i].front = NULL;
        queues[i].back = NULL;
        queues[i].size = 0;
    }


    scanf("%d %d", &numCustomers, &numBooths);

    //take user input for each customer and initialize customer vals
    for (int i = 0; i < numCustomers; ++i)
    {
        char name[50];
        int numTickets;
        int checkIn;

        scanf("%s %d %d", name, &numTickets, &checkIn);


        Customer* currCustomer = createCustomer(name, numTickets, checkIn);

        if (currCustomer == NULL)
        {
            printf("Customer could not be created.\n");
        }
        else
        {
            int queueNum = currCustomer->name[0] % 13;

            //assign currCustomer to their queue
            if (queueNum != 0)
            {
                currCustomer->assignedQueue = queueNum;
            }
            else
            {
                int smallestQueueIndex = -1; //index of smallest queue
                int leastSize = -1;            //size of smallest queue

                //set current leastSize to size of first non-empty queue
                while ((smallestQueueIndex < MAX_QUEUES - 1) && (leastSize == -1))
                {

                    if (isEmpty(queues[++smallestQueueIndex]) == 0)   //smallestQueueIndex will be the first nonempty queue's index   
                    {
                        leastSize = queues[smallestQueueIndex].size;  //leastSize will be the first nonempty queue's size
                        break;
                    }
                }

                //starting from queue after first non-empty queue
                for (int currQueueIndex = smallestQueueIndex + 1; currQueueIndex < MAX_QUEUES; ++currQueueIndex)
                {
                    //if size of currQueue is less than current leastSize
                    //update least size and update smallestQueueIndex
                    if ((isEmpty(queues[currQueueIndex]) == 0) && (queues[currQueueIndex].size < leastSize))
                    {
                        leastSize = queues[currQueueIndex].size;
                        smallestQueueIndex = currQueueIndex;
                    }
                }

                currCustomer->assignedQueue = smallestQueueIndex + 1;    //assign currCustomer's queue
            }

            enqueue(&queues[currCustomer->assignedQueue - 1], currCustomer); ////currCustomer enters assigned queue
        }
    }


//find num of customers each booth will get
    int nonEmptyQueues = 0;
    int startingQueueIndex;            //index of first queue assigned to booth

    //find num of nonEmptyQueues and first nonempty queue
    for (int i = 0; i < MAX_QUEUES; ++i)
    {
        if (isEmpty(queues[i]) == 0)
        {
            ++nonEmptyQueues;

            if (nonEmptyQueues == 1)
            {
                startingQueueIndex = i;
            }
        }
    }

    int numQueuesForBooth;                                     //num of queues assigned per booth
    int additionalQueue = nonEmptyQueues % numBooths;       //num of booths assigned an additional queue


    for (int i = 0; i < numBooths; ++i)
    {
        int totalCustomersForBooth = 0;
        int time = 0;                            //booths begin dequeuing at zero seconds

        printf("Booth %d\n", i + 1);

        if (i < additionalQueue)                //for booths with additional queue
        {
            numQueuesForBooth = (nonEmptyQueues / numBooths) + 1;
        }
        else
        {
            numQueuesForBooth = nonEmptyQueues / numBooths;
        }


    //find totalCustomersForBooth and lastQueueForBooth
        int nonempty = 0;
        int lastQueueForBooth = -1;

        while (nonempty < numQueuesForBooth)
        {
            if (isEmpty(queues[++lastQueueForBooth]) == 0)
            {
                ++nonempty;
                totalCustomersForBooth += queues[lastQueueForBooth].size;
            }
        }


        //dequeue customers by arrival time
        int queuesFinished = 0;

        //peek assigned queues and find customer with earliest arrival time
        for (int currCustomer = 0; currCustomer < totalCustomersForBooth; ++currCustomer)
        {
            int i = -1;
            int peekedQueues = queuesFinished;

            int earliestArrivalTime = peek(&queues[startingQueueIndex])->checkIn;
            int queueOfEarliestCustomer = startingQueueIndex;

            while (peekedQueues < numQueuesForBooth)
            {
                ++i;

                int currQueueIndex = startingQueueIndex + i;

                if (isEmpty(queues[currQueueIndex]) == 0)
                {
                    int frontArrivalTime = peek(&queues[currQueueIndex])->checkIn; //arrival time of front customer

                    if (frontArrivalTime <= earliestArrivalTime)
                    {
                        earliestArrivalTime = frontArrivalTime;
                        queueOfEarliestCustomer = currQueueIndex;
                    }

                    peekedQueues++;
                }

            }

            //dequeue ealiest arriving customer's node in queue
            Customer* dequeuedCustomer = dequeue(&queues[queueOfEarliestCustomer]);

            int processingTime = 30 + dequeuedCustomer->numTickets * 5;

            //update time if needed
            if (time < dequeuedCustomer->checkIn)
            {
                time = dequeuedCustomer->checkIn;
            }

            time += processingTime;

            printf("%s from line %d checks out at time %d.\n", dequeuedCustomer->name, dequeuedCustomer->assignedQueue, time);

            if (isEmpty(queues[dequeuedCustomer->assignedQueue - 1]) == 1)
            {
                ++queuesFinished;
            }

            free(dequeuedCustomer->name);
            free(dequeuedCustomer);


            //update starting queue to next nonempty queue
            int flag = 1;
            int y = -1;

            while (flag == 1)
            {
                ++y;

                if (isEmpty(queues[y]) == 0)
                {
                    startingQueueIndex = y;
                    flag = 0;
                }   
            }
        }
        printf("\n");
    }
  return 0;
}



//FUNCTION DEFINITIONS
Customer* createCustomer(char customerName[MAX_CHAR], int numOfTickets, int arrivalTime)
{
    //initialize new Customer
    Customer* newCustomer = (Customer*) malloc(sizeof(Customer));

    newCustomer->name = (char*) malloc(strlen(customerName) + 1);
    strcpy(newCustomer->name, customerName);

    newCustomer->numTickets = numOfTickets;
    newCustomer->checkIn = arrivalTime;

    printf("%s\t%d\t%d", newCustomer->name, newCustomer->numTickets, newCustomer->checkIn);

    return newCustomer;
}


int isEmpty(Queue queue)
{
    if (queue.size == 0)
    {
        return 1;
    }

    return 0;
}


int queueSize(Queue queue)
{
    return queue.size;
}


Customer* peek(Queue* queuePtr)
{

    return queuePtr->front->customerPtr;
}

void enqueue(Queue* queuePtr, Customer* customer)
{
    //create node pointing to customer
    Node* newNode = (Node*) malloc(sizeof(Node));

    if(newNode == NULL)
    {
        printf("Customer could not be added to list.\n");
        return;
    }

    newNode->customerPtr = customer;
    newNode->next = NULL;

    //insert node to end of line
    if (queuePtr->front == NULL)
    {
        queuePtr->front = newNode;
    }
    else
    {
        queuePtr->back->next = newNode;
    }

    queuePtr->back = newNode;

    ++queuePtr->size;
}

Customer* dequeue(Queue* queuePtr)
{
    Customer* customerPtr = queuePtr->front->customerPtr;

    Node* dequeuedNode = queuePtr->front;

    queuePtr->front = queuePtr->front->next;

    free(dequeuedNode);

    --queuePtr->size;
    return customerPtr;
} 

C Language online compiler

Write, Run & Share C Language code online using OneCompiler's C online compiler for free. It's one of the robust, feature-rich online compilers for C language, running the latest C version which is C18. Getting started with the OneCompiler's C editor is really simple and pretty fast. The editor shows sample boilerplate code when you choose language as 'C' and start coding!

Read inputs from stdin

OneCompiler's C online editor supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample C program which takes name as input and print your name with hello.

#include <stdio.h>
int main()
{
    char name[50];
    printf("Enter name:");
    scanf("%s", name);
    printf("Hello %s \n" , name );
    return 0;
    
}

About C

C language is one of the most popular general-purpose programming language developed by Dennis Ritchie at Bell laboratories for UNIX operating system. The initial release of C Language was in the year 1972. Most of the desktop operating systems are written in C Language.

Key features:

  • Structured Programming
  • Popular system programming language
  • UNIX, MySQL and Oracle are completely written in C.
  • Supports variety of platforms
  • Efficient and also handle low-level activities.
  • As fast as assembly language and hence used as system development language.

Syntax help

Loops

1. If-Else:

When ever you want to perform a set of operations based on a condition if-else is used.

if(conditional-expression) {
   // code
} else {
   // code
}

You can also use if-else for nested Ifs and if-else-if ladder when multiple conditions are to be performed on a single variable.

2. Switch:

Switch is an alternative to if-else-if ladder.

switch(conditional-expression) {    
case value1:    
 // code    
 break;  // optional  
case value2:    
 // code    
 break;  // optional  
...    
    
default:     
 // code to be executed when all the above cases are not matched;    
} 

3. For:

For loop is used to iterate a set of statements based on a condition.

for(Initialization; Condition; Increment/decrement){  
  // code  
} 

4. While:

While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.

while(condition) {  
 // code 
}  

5. Do-While:

Do-while is also used to iterate a set of statements based on a condition. It is mostly used when you need to execute the statements atleast once.

do {
  // code 
} while (condition); 

Arrays

Array is a collection of similar data which is stored in continuous memory addresses. Array values can be fetched using index. Index starts from 0 to size-1.

Syntax

One dimentional Array:

data-type array-name[size];

Two dimensional array:

data-type array-name[size][size];

Functions

Function is a sub-routine which contains set of statements. Usually functions are written when multiple calls are required to same set of statements which increases re-usuability and modularity.

Two types of functions are present in C

  1. Library Functions:

Library functions are the in-built functions which are declared in header files like printf(),scanf(),puts(),gets() etc.,

  1. User defined functions:

User defined functions are the ones which are written by the programmer based on the requirement.

How to declare a Function

return_type function_name(parameters);

How to call a Function

function_name (parameters)

How to define a Function

return_type function_name(parameters) {  
  //code
}