Added queue.c and queue.h.
- Added a singular queue type for input/output messages and commands. - Added a test of the queue type in tests. - Made some edits to the Makefile to enable the addition of debug code using the preprocessor. - Minor styling and spelling updates in gamelogic.c/h and text effects .h. - Ready to integrate the new queue type in place of the previous ones.
This commit is contained in:
parent
2ab873b40b
commit
8ae3eaf2b8
2
Makefile
2
Makefile
|
@ -25,5 +25,5 @@ clean:
|
||||||
|
|
||||||
all: clean SilverMUDClient SilverMUDServer
|
all: clean SilverMUDClient SilverMUDServer
|
||||||
all: CFLAGS += -Wall -Wextra -Ofast
|
all: CFLAGS += -Wall -Wextra -Ofast
|
||||||
debug: CFLAGS += -Wall -Wextra -pg -ggdb -Og
|
debug: CFLAGS += -Wall -Wextra -pg -ggdb -Og -D debug
|
||||||
debug: clean SilverMUDClientDebug SilverMUDServerDebug
|
debug: clean SilverMUDClientDebug SilverMUDServerDebug
|
||||||
|
|
|
@ -136,6 +136,8 @@ int queueMessagedCommand(commandQueue * queue, inputMessage * messageToQueue)
|
||||||
// Check that we're not overflowing the queue:
|
// Check that we're not overflowing the queue:
|
||||||
if ((queue->currentLength + 1) > MAXQUEUELENGTH)
|
if ((queue->currentLength + 1) > MAXQUEUELENGTH)
|
||||||
{
|
{
|
||||||
|
// Free the new command, it's getting dumped:
|
||||||
|
free(newCommand);
|
||||||
// Unlock the queue:
|
// Unlock the queue:
|
||||||
queue->lock = false;
|
queue->lock = false;
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// gamelogic.h: Header file contatning function prototypes and datastructures
|
// gamelogic.h: Function prototypes and data-structures for dealing with game logic.
|
||||||
// for dealing with the game's logic.
|
|
||||||
// Barry Kane, 2022.
|
// Barry Kane, 2022.
|
||||||
#ifndef GAMELOGIC_H
|
#ifndef GAMELOGIC_H
|
||||||
#define GAMELOGIC_H
|
#define GAMELOGIC_H
|
||||||
|
@ -12,7 +11,7 @@
|
||||||
// -=[ Main Game Loop ]=-:
|
// -=[ Main Game Loop ]=-:
|
||||||
// =======================
|
// =======================
|
||||||
|
|
||||||
// A datastructure containing the needed parameters for a main game loop:
|
// A data-structure containing the needed parameters for a main game loop:
|
||||||
typedef struct gameLogicParameters
|
typedef struct gameLogicParameters
|
||||||
{
|
{
|
||||||
int * playerCount;
|
int * playerCount;
|
||||||
|
|
|
@ -47,9 +47,9 @@ typedef struct list
|
||||||
listNode * tail;
|
listNode * tail;
|
||||||
} list;
|
} list;
|
||||||
|
|
||||||
// ==================
|
// ========================
|
||||||
// -=[ Functions ]=-:
|
// -=[ Functions ]=-:
|
||||||
// ==================
|
// ========================
|
||||||
|
|
||||||
// Allocates and instantiates a list of the specified type:
|
// Allocates and instantiates a list of the specified type:
|
||||||
list * createList(listDataType type);
|
list * createList(listDataType type);
|
||||||
|
|
|
@ -0,0 +1,206 @@
|
||||||
|
// queue.c: Implements the queue data type and associated functions for SilverMUD.
|
||||||
|
// Barry Kane, 2022
|
||||||
|
#include "queue.h"
|
||||||
|
|
||||||
|
// Allocates and instantiates a queue:
|
||||||
|
queue * createQueue(void)
|
||||||
|
{
|
||||||
|
// Allocate the memory for the queue:
|
||||||
|
queue * newQueue = malloc(sizeof(queue));
|
||||||
|
|
||||||
|
// Instantiate the variables in the data-structure:
|
||||||
|
newQueue->itemCount = 0;
|
||||||
|
newQueue->front = NULL;
|
||||||
|
newQueue->back = NULL;
|
||||||
|
|
||||||
|
// Return the pointer to the new queue:
|
||||||
|
return newQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroys a queue and all of it's members:
|
||||||
|
void destroyQueue(queue ** queue)
|
||||||
|
{
|
||||||
|
// Pop everything off of the queue:
|
||||||
|
while ((*queue)->itemCount > 0)
|
||||||
|
{
|
||||||
|
popQueue(*queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deallocate the queue:
|
||||||
|
free(*queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the data at the front of the given queue:
|
||||||
|
queueNode * peekQueue(queue * queue)
|
||||||
|
{
|
||||||
|
return queue->front;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes the current data from the front of the queue:
|
||||||
|
void popQueue(queue * queue)
|
||||||
|
{
|
||||||
|
// Check if the queue is locked, and wait:
|
||||||
|
while (queue->lock);
|
||||||
|
|
||||||
|
// Lock the queue:
|
||||||
|
queue->lock = true;
|
||||||
|
|
||||||
|
// Check there is actually anything to remove:
|
||||||
|
if (queue->itemCount == 0)
|
||||||
|
{
|
||||||
|
queue->lock = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the special case of being the last item in the queue:
|
||||||
|
else if (queue->itemCount == 1)
|
||||||
|
{
|
||||||
|
// Deallocate the correct data:
|
||||||
|
switch (queue->front->type)
|
||||||
|
{
|
||||||
|
case EVENT:
|
||||||
|
{
|
||||||
|
// TODO: Implement events.
|
||||||
|
}
|
||||||
|
case COMMAND:
|
||||||
|
{
|
||||||
|
free(queue->front->data.command->command);
|
||||||
|
free(queue->front->data.command->arguments);
|
||||||
|
free(queue->front->data.command);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INPUT_MESSAGE:
|
||||||
|
{
|
||||||
|
free(queue->front->data.inputMessage->content);
|
||||||
|
free(queue->front->data.inputMessage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OUTPUT_MESSAGE:
|
||||||
|
{
|
||||||
|
free(queue->front->data.outputMessage->content);
|
||||||
|
free(queue->front->data.outputMessage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deallocate the node:
|
||||||
|
free(queue->front);
|
||||||
|
|
||||||
|
// Set the correct variables for the queue:
|
||||||
|
queue->front = NULL;
|
||||||
|
queue->back = NULL;
|
||||||
|
queue->itemCount = 0;
|
||||||
|
|
||||||
|
// Unlock the queue:
|
||||||
|
queue->lock = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the current front of the queue:
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Deallocate the correct data:
|
||||||
|
switch (queue->front->type)
|
||||||
|
{
|
||||||
|
case EVENT:
|
||||||
|
{
|
||||||
|
// TODO: Implement events.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COMMAND:
|
||||||
|
{
|
||||||
|
free(queue->front->data.command->command);
|
||||||
|
free(queue->front->data.command->arguments);
|
||||||
|
free(queue->front->data.command);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INPUT_MESSAGE:
|
||||||
|
{
|
||||||
|
free(queue->front->data.inputMessage->content);
|
||||||
|
free(queue->front->data.inputMessage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OUTPUT_MESSAGE:
|
||||||
|
{
|
||||||
|
free(queue->front->data.outputMessage->content);
|
||||||
|
free(queue->front->data.outputMessage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save a pointer to the current node so we don't leak it:
|
||||||
|
queueNode * nodeToDelete = queue->front;
|
||||||
|
|
||||||
|
// Advance the queue:
|
||||||
|
queue->front = queue->front->next;
|
||||||
|
queue->itemCount--;
|
||||||
|
|
||||||
|
// Deallocate the old node:
|
||||||
|
free(nodeToDelete);
|
||||||
|
|
||||||
|
// Unlock the queue:
|
||||||
|
queue->lock = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds data to the back of a queue:
|
||||||
|
void pushQueue(queue * queue, void * data, queueDataType type)
|
||||||
|
{
|
||||||
|
// Create a new node:
|
||||||
|
queueNode * newNode = malloc(sizeof(queueNode));
|
||||||
|
|
||||||
|
// Copy the data into the correct slot for the type:
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case EVENT:
|
||||||
|
{
|
||||||
|
// TODO: Implement events.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COMMAND:
|
||||||
|
{
|
||||||
|
newNode->data.command = data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INPUT_MESSAGE:
|
||||||
|
{
|
||||||
|
newNode->data.inputMessage = data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OUTPUT_MESSAGE:
|
||||||
|
{
|
||||||
|
newNode->data.outputMessage = data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the queue is locked:
|
||||||
|
while (queue->lock);
|
||||||
|
|
||||||
|
// Lock the queue:
|
||||||
|
queue->lock = true;
|
||||||
|
|
||||||
|
// Set the correct pointers:
|
||||||
|
newNode->next = NULL;
|
||||||
|
|
||||||
|
if (queue->itemCount == 0)
|
||||||
|
{
|
||||||
|
queue->front = newNode;
|
||||||
|
queue->back = newNode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
queue->back->next = newNode;
|
||||||
|
queue->back = newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increase the queue item count:
|
||||||
|
queue->itemCount++;
|
||||||
|
|
||||||
|
// Unlock the queue:
|
||||||
|
queue->lock = false;
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
// queue.h: Defines the queue data type and associated function prototypes for SilverMUD.
|
||||||
|
// Barry Kane, 2022
|
||||||
|
#ifndef QUEUE_H
|
||||||
|
#define QUEUE_H
|
||||||
|
#include "gamelogic.h"
|
||||||
|
#include "inputoutput.h"
|
||||||
|
|
||||||
|
// ========================
|
||||||
|
// -=[ Data Structures ]=-:
|
||||||
|
// ========================
|
||||||
|
|
||||||
|
typedef enum queueDataType
|
||||||
|
{
|
||||||
|
EVENT,
|
||||||
|
COMMAND,
|
||||||
|
INPUT_MESSAGE,
|
||||||
|
OUTPUT_MESSAGE
|
||||||
|
} queueDataType;
|
||||||
|
|
||||||
|
typedef union queueData
|
||||||
|
{
|
||||||
|
outputMessage * outputMessage;
|
||||||
|
inputMessage * inputMessage;
|
||||||
|
commandEvent * command;
|
||||||
|
} queueData;
|
||||||
|
|
||||||
|
typedef struct queueNode queueNode;
|
||||||
|
typedef struct queueNode
|
||||||
|
{
|
||||||
|
queueDataType type;
|
||||||
|
queueData data;
|
||||||
|
queueNode * next;
|
||||||
|
} queueNode;
|
||||||
|
|
||||||
|
typedef struct queue
|
||||||
|
{
|
||||||
|
bool lock;
|
||||||
|
size_t itemCount;
|
||||||
|
queueNode * front;
|
||||||
|
queueNode * back;
|
||||||
|
} queue;
|
||||||
|
|
||||||
|
// ========================
|
||||||
|
// -=[ Functions ]=-:
|
||||||
|
// ========================
|
||||||
|
|
||||||
|
// Allocates and instantiates a queue:
|
||||||
|
queue * createQueue(void);
|
||||||
|
|
||||||
|
// Destroys a queue and all of it's members:
|
||||||
|
void destroyQueue(queue ** queue);
|
||||||
|
|
||||||
|
// Returns the node at the front of the given queue:
|
||||||
|
queueNode * peekQueue(queue * queue);
|
||||||
|
|
||||||
|
// Removes the current node from the front of the queue:
|
||||||
|
void popQueue(queue * queue);
|
||||||
|
|
||||||
|
// Adds data to the back of a queue:
|
||||||
|
void pushQueue(queue * queue, void * data, queueDataType type);
|
||||||
|
|
||||||
|
#endif
|
|
@ -29,7 +29,7 @@ typedef struct sockaddr sockaddr;
|
||||||
void sigintHandler(int signal)
|
void sigintHandler(int signal)
|
||||||
{
|
{
|
||||||
printf("Caught signal %d.\n", signal);
|
printf("Caught signal %d.\n", signal);
|
||||||
exit(EXIT_SUCCESS);
|
_exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char ** argv)
|
int main(int argc, char ** argv)
|
||||||
|
|
|
@ -33,4 +33,5 @@ char * logostring =
|
||||||
" # # ### ##### ##### ### # # # # #### ### /\n";
|
" # # ### ##### ##### ### # # # # #### ### /\n";
|
||||||
|
|
||||||
void wrapString(char * stringToWrap, int stringLength, int screenWidth);
|
void wrapString(char * stringToWrap, int stringLength, int screenWidth);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
// Test for the queue type in SilverMUD:
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "../src/queue.h"
|
||||||
|
|
||||||
|
#define formatBoolean(b) ((b) ? "true" : "false")
|
||||||
|
#define formatEquality(b) ((b) ? "equal" : "not equal")
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
// Create a queue:
|
||||||
|
printf("-=[ Creating queue ]=-:\n");
|
||||||
|
queue * testQueue = createQueue();
|
||||||
|
|
||||||
|
// Check that the queue has the correct values:
|
||||||
|
printf("-=[ Checking initial values ]=-:\n");
|
||||||
|
|
||||||
|
printf("- Item count should be 0:\n");
|
||||||
|
assert(testQueue->itemCount == 0);
|
||||||
|
printf("Item count is %d.\n\n", testQueue->itemCount);
|
||||||
|
|
||||||
|
printf("- Lock should be false:\n");
|
||||||
|
assert(testQueue->lock == false);
|
||||||
|
printf("Lock is %s.\n\n", formatBoolean(testQueue->lock));
|
||||||
|
|
||||||
|
printf("- Front should be (nil):\n");
|
||||||
|
assert(testQueue->front == NULL);
|
||||||
|
printf("Front is %p.\n\n", testQueue->front);
|
||||||
|
|
||||||
|
printf("- Back should be (nil):\n");
|
||||||
|
assert(testQueue->back == NULL);
|
||||||
|
printf("Back is %p.\n\n", testQueue->front);
|
||||||
|
|
||||||
|
// Create some items for the queue:
|
||||||
|
inputMessage * testInputMessage = malloc(sizeof(inputMessage));
|
||||||
|
testInputMessage->sender = NULL;
|
||||||
|
testInputMessage->next = NULL;
|
||||||
|
testInputMessage->content = malloc(sizeof(userMessage));
|
||||||
|
strcpy(testInputMessage->content->senderName,"Queue Test Input Sender");
|
||||||
|
strcpy(testInputMessage->content->messageContent, "Queue Test Input Content - Hello!");
|
||||||
|
|
||||||
|
outputMessage * testOutputMessage = malloc(sizeof(outputMessage));
|
||||||
|
for(int index = 0; index < PLAYERCOUNT; index++)
|
||||||
|
{
|
||||||
|
testOutputMessage->targets[index] = NULL;
|
||||||
|
}
|
||||||
|
testOutputMessage->next = NULL;
|
||||||
|
testOutputMessage->content = malloc(sizeof(userMessage));
|
||||||
|
strcpy(testOutputMessage->content->senderName, "Queue Test Output Sender");
|
||||||
|
strcpy(testOutputMessage->content->messageContent, "Queue Test Output Content - World!");
|
||||||
|
|
||||||
|
commandEvent * testCommandEvent = malloc(sizeof(commandEvent));
|
||||||
|
testCommandEvent->next = NULL;
|
||||||
|
testCommandEvent->caller = NULL;
|
||||||
|
testCommandEvent->command = malloc(5 * sizeof(char));
|
||||||
|
testCommandEvent->arguments = malloc(15 * sizeof(char));
|
||||||
|
strcpy(testCommandEvent->command, "Test");
|
||||||
|
strcpy(testCommandEvent->arguments, "Test Arguments");
|
||||||
|
|
||||||
|
// Add them to the queue:
|
||||||
|
printf("-=[ Adding items to the queue ]=-:\n");
|
||||||
|
printf("- First item, Item count should be 1. Front and Back should be equal.\n");
|
||||||
|
pushQueue(testQueue, testInputMessage, INPUT_MESSAGE);
|
||||||
|
assert(testQueue->itemCount == 1);
|
||||||
|
assert(testQueue->front == testQueue->back);
|
||||||
|
printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
|
||||||
|
formatEquality(testQueue->front == testQueue->back));
|
||||||
|
|
||||||
|
printf("- Second item, Item count should be 2. Front and Back should be not equal.\n");
|
||||||
|
pushQueue(testQueue, testOutputMessage, OUTPUT_MESSAGE);
|
||||||
|
assert(testQueue->itemCount == 2);
|
||||||
|
assert(testQueue->front != testQueue->back);
|
||||||
|
printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
|
||||||
|
formatEquality(testQueue->front == testQueue->back));
|
||||||
|
|
||||||
|
printf("- Third item, Item count should be 3. Front and Back should be not equal.\n");
|
||||||
|
pushQueue(testQueue, testCommandEvent, COMMAND);
|
||||||
|
assert(testQueue->itemCount == 3);
|
||||||
|
assert(testQueue->front != testQueue->back);
|
||||||
|
printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
|
||||||
|
formatEquality(testQueue->front == testQueue->back));
|
||||||
|
|
||||||
|
printf("-=[ Checking items and popping from queue ]=-:\n");
|
||||||
|
printf("- First item peeked should point to testInputMessage.\n");
|
||||||
|
assert(peekQueue(testQueue)->data.inputMessage == testInputMessage);
|
||||||
|
printf("Peeked data is located at: %p, testInputMessage is located at: %p.\n\n",
|
||||||
|
peekQueue(testQueue)->data.inputMessage, testInputMessage);
|
||||||
|
|
||||||
|
printf("- Popping first item, Item count should be 2, Front and Back should not be equal.\n");
|
||||||
|
popQueue(testQueue);
|
||||||
|
assert(testQueue->itemCount == 2);
|
||||||
|
assert(testQueue->front != testQueue->back);
|
||||||
|
printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
|
||||||
|
formatEquality(testQueue->front == testQueue->back));
|
||||||
|
|
||||||
|
printf("- Second item peeked should point to testOutputMessage.\n");
|
||||||
|
assert(peekQueue(testQueue)->data.outputMessage == testOutputMessage);
|
||||||
|
printf("Peeked data is located at: %p, testOutputMessage is located at: %p.\n\n",
|
||||||
|
peekQueue(testQueue)->data.outputMessage, testOutputMessage);
|
||||||
|
|
||||||
|
printf("- Popping second item, Item count should be 1, Front and Back should be equal.\n");
|
||||||
|
popQueue(testQueue);
|
||||||
|
assert(testQueue->itemCount == 1);
|
||||||
|
assert(testQueue->front == testQueue->back);
|
||||||
|
printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
|
||||||
|
formatEquality(testQueue->front == testQueue->back));
|
||||||
|
|
||||||
|
printf("- Third item peeked should point to testCommandEvent.\n");
|
||||||
|
assert(peekQueue(testQueue)->data.command == testCommandEvent);
|
||||||
|
printf("Peeked data is located at: %p, testCommandEvent is located at: %p.\n\n",
|
||||||
|
peekQueue(testQueue)->data.command, testCommandEvent);
|
||||||
|
|
||||||
|
printf("- Popping third item:\n");
|
||||||
|
popQueue(testQueue);
|
||||||
|
|
||||||
|
printf("- Item count should be 0:\n");
|
||||||
|
assert(testQueue->itemCount == 0);
|
||||||
|
printf("Item count is %d.\n\n", testQueue->itemCount);
|
||||||
|
|
||||||
|
printf("- Lock should be false:\n");
|
||||||
|
assert(testQueue->lock == false);
|
||||||
|
printf("Lock is %s.\n\n", formatBoolean(testQueue->lock));
|
||||||
|
|
||||||
|
printf("- Front should be (nil):\n");
|
||||||
|
assert(testQueue->front == NULL);
|
||||||
|
printf("Front is %p.\n\n", testQueue->front);
|
||||||
|
|
||||||
|
printf("- Back should be (nil):\n");
|
||||||
|
assert(testQueue->back == NULL);
|
||||||
|
printf("Back is %p.\n\n", testQueue->front);
|
||||||
|
}
|
Loading…
Reference in New Issue