Preliminary implementation of linked-list.c

- Implemented first pass of linked-list.c.

TODO:
- Polish linked-list.c 'till you can see a reflection in it.
- Refactor existing codebase to use linked-list.c.y
This commit is contained in:
Barry Kane 2022-11-11 22:58:05 +00:00
parent c68e66e7bc
commit f3ad758e4f
4 changed files with 582 additions and 17 deletions

467
src/linkedlist.c Normal file
View File

@ -0,0 +1,467 @@
// linkedlist.h: Function definitions for the list type for SilverMUD.
// Barry Kane, 2022.
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
#include "playerdata.h"
#include "linkedlist.h"
// Deallocate a given list node, including it's data:
static inline void deallocateListNode(listNode * node, listDataType type)
{
// Delete the node:
switch(type)
{
case PLAYER:
{
deallocatePlayer(node->data.player);
break;
}
case AREA:
{
// destroyList(node->data.area->paths);
free(node->data.area);
free(node);
break;
}
case PATH:
{
free(node->data.path);
free(node);
break;
}
case SKILL:
{
free(node->data.skill);
free(node);
break;
}
}
}
// Allocates and instantiates a list of the specified type:
list * createList(listDataType type)
{
// Allocate and clear the memory for the list:
list * newList = calloc(sizeof(list), 1);
// Set the appropriate values in the new list:
newList->type = type;
newList->itemCount = 0;
newList->head = NULL;
newList->tail = NULL;
// Return the new list:
return newList;
}
// Deallocates a list and all of it's members:
int destroyList(list ** list)
{
// Check if the list is empty:
if((*list)->itemCount == 0)
{
free(*list);
list = NULL;
return 0;
}
else
{
while((*list)->itemCount > 0)
{
removeFromList((*list), (*list)->type, (*list)->itemCount - 1);
}
free(*list);
*list = NULL;
return 0;
}
}
// Returns the data at a given index in a list:
listData * getFromList(list * list, size_t listIndex)
{
// Check that we were given a valid index:
if(listIndex > (list->itemCount - 1))
{
perror("Invalid index specified.\n");
return NULL;
}
// Return the head if index is 0:
else if(listIndex == 0)
{
return &list->head->data;
}
// Loop through the entries in the list until we get to the right one:
else
{
listNode * currentNode = list->head;
while(listIndex-- > 0)
{
currentNode = currentNode->next;
}
return &currentNode->data;
}
}
// Returns the node at a given index in a list:
listNode * getNodeFromList(list * list, size_t listIndex)
{
// Check that we were given a valid index:
if(listIndex > (list->itemCount - 1))
{
perror("Invalid index specified.\n");
return NULL;
}
// Return the head if index is 0:
else if(listIndex == 0)
{
return list->head;
}
// Loop through the entries in the list until we get to the right one:
else
{
listNode * currentNode = list->head;
while(listIndex-- > 0)
{
currentNode = currentNode->next;
}
return currentNode;
}
}
// Adds the given data to the end of a list:
listNode * addToList(list * list, void * data, listDataType type)
{
// Check the type:
if(type != list->type)
{
fprintf(stderr, "Not the correct type for this list.\n");
return NULL;
}
// If this is the first item in the list:
if(list->itemCount == 0)
{
// Allocate the new node for the list:
list->head = calloc(1, sizeof(listNode));
// Set the appropriate pointers for the list:
list->head->next = NULL;
list->head->previous = NULL;
list->tail = list->head;
// Add the data to the new node:
switch(type)
{
case PATH:
{
list->head->data.path = (playerPath *)data;
break;
}
case AREA:
{
list->head->data.area = (playerArea *)data;
break;
}
case PLAYER:
{
list->head->data.player = (playerInfo *)data;
break;
}
case SKILL:
{
list->head->data.skill = (playerSkill *)data;
break;
}
}
}
else
{
// Allocate the new node at the end of the list:
list->tail->next = calloc(1, sizeof(listNode));
// Add the data to the new node:
switch(type)
{
case PATH:
{
list->tail->next->data.path = (playerPath *)data;
break;
}
case AREA:
{
list->tail->next->data.area = (playerArea *)data;
break;
}
case PLAYER:
{
list->tail->next->data.player = (playerInfo *)data;
break;
}
case SKILL:
{
list->tail->next->data.skill = (playerSkill *)data;
break;
}
}
// Set the appropriate pointers in the new node:
list->tail->next->previous = list->tail;
// Set the list's tail to the new tail:
list->tail = list->tail->next;
}
// Increase the count of items in the list:
list->itemCount++;
// Return the new item in the list:
return list->tail;
}
// Insert the given data at a given index in the list:
listNode * insertIntoList(list * list, void * data, listDataType type, size_t listIndex)
{
// Check that the types are correct:
if(list->type != type)
{
fprintf(stderr, "Types do not match.\n");
return NULL;
}
// Handle the special case of adding to the end of the list:
if(listIndex == (list->itemCount - 1))
{
return addToList(list, data, type);
}
// Handle the special case of adding to the beginning of the list:
if(listIndex == 0)
{
// Create the new node:
listNode * newNode = calloc(1, sizeof(listNode));
// Add the data to the node:
switch(type)
{
case PATH:
{
newNode->data.path = (playerPath *)data;
break;
}
case AREA:
{
newNode->data.area = (playerArea *)data;
break;
}
case PLAYER:
{
newNode->data.player = (playerInfo *)data;
break;
}
case SKILL:
{
newNode->data.skill = (playerSkill *)data;
break;
}
}
// Place it in the list:
newNode->next = list->head;
newNode->previous = NULL;
list->head->previous = newNode;
list->head = newNode;
list->itemCount++;
// Return the node:
return newNode;
}
// Check that the index is valid:
if(listIndex > (list->itemCount - 1))
{
fprintf(stderr, "Index is invalid for the list.\n");
return NULL;
}
// Get the current node at the index:
listNode * currentNode = list->head;
for(size_t index = 0; index < listIndex; index++)
{
currentNode = currentNode->next;
}
// Get the node before the current node:
listNode * previousNode = currentNode->previous;
// Create the new node:
previousNode->next = calloc(1, sizeof(listNode));
currentNode->previous = previousNode->next;
previousNode->next->next = currentNode;
previousNode->next->previous = previousNode;
// Add the data to the node:
switch(type)
{
case PATH:
{
previousNode->next->data.path = (playerPath *)data;
break;
}
case AREA:
{
previousNode->next->data.area = (playerArea *)data;
break;
}
case PLAYER:
{
previousNode->next->data.player = (playerInfo *)data;
break;
}
case SKILL:
{
previousNode->next->data.skill = (playerSkill *)data;
break;
}
}
list->itemCount++;
return previousNode->next;
}
// Delete the given data from a list:
bool deleteFromList(list * list, void * data, listDataType type)
{
size_t index = 0;
if(getIndexFromList(list, data, type, &index) == false)
{
return false;
}
else
{
removeFromList(list, type, index);
return true;
}
}
// Delete the data from a given point in a list:
int removeFromList(list * list, listDataType type, size_t listIndex)
{
// Check that we're removing the correct type:
if(list->type != type)
{
return -1;
}
// Check the list index is valid:
if(listIndex > list->itemCount - 1)
{
return -2;
}
// The first node in the list:
if(listIndex == 0)
{
// Get the current head and move the list's head on:
listNode * oldHead = list->head;
list->head = list->head->next;
// If we haven't removed the last item, set the previous pointer
// in the new head to null.
if(list->head != NULL)
{
list->head->previous = NULL;
}
// Delete the node:
deallocateListNode(oldHead, type);
// Return the new amount of items in the list:
list->itemCount--;
return list->itemCount;
}
// The last node in the list:
else if(listIndex == (list->itemCount - 1))
{
// Move the tail up by one:
list->tail = list->tail->previous;
// Deallocate the former tail:
deallocateListNode(list->tail->next, type);
// Set the appropriate pointer:
list->tail->next = NULL;
// Return the new amount of items in the list:
list->itemCount--;
return list->itemCount;
}
// A node in the middle of the list:
else
{
// Get the needed node as a pointer:
listNode * nodeToDelete = getNodeFromList(list, listIndex);
// Set the appropriate pointers for the surrounding nodes:
nodeToDelete->previous->next = nodeToDelete->next;
nodeToDelete->next->previous = nodeToDelete->previous;
// Deallocate the node:
deallocateListNode(nodeToDelete, type);
// Return the new amount of items in the list:
list->itemCount--;
return list->itemCount;
}
}
// Get the index of a given piece of data in a list:
bool getIndexFromList(list * list, void * data, listDataType type, size_t * index)
{
// Check the list types are the same:
if(list->type == type)
{
fprintf(stderr, "List types do not match.\n");
return false;
}
for(*index = 0; *index < list->itemCount; *index++)
{
switch(type)
{
case AREA:
{
if(getFromList(list, *index)->area == data)
{
return true;
}
break;
}
case PLAYER:
{
if(getFromList(list, *index)->player == data)
{
return true;
}
break;
}
case PATH:
{
if(getFromList(list, *index)->path == data)
{
return true;
}
break;
}
case SKILL:
{
if(getFromList(list, *index)->skill == data)
{
return true;
}
break;
}
}
}
return false;
}

75
src/linkedlist.h Normal file
View File

@ -0,0 +1,75 @@
// linkedlist.h: Defines the linked list datatype for SilverMUD.
// Barry Kane, 2022.
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "playerdata.h"
#include "areadata.h"
// ========================
// -=[ Data Structures ]=-:
// ========================
typedef enum listDataType
{
PATH,
AREA,
PLAYER,
SKILL
} listDataType;
typedef union listData
{
playerPath * path;
playerArea * area;
playerInfo * player;
playerSkill * skill;
} listData;
typedef struct listNode listNode;
typedef struct listNode
{
listData data;
listNode * next;
listNode * previous;
} listNode;
typedef struct list
{
listDataType type;
size_t itemCount;
listNode * head;
listNode * tail;
} list;
// ==================
// -=[ Functions ]=-:
// ==================
// Allocates and instantiates a list of the specified type:
list * createList(listDataType type);
// Deallocates a list and all of it's members:
int destroyList(list ** list);
// Returns the data at a given index in a list:
listData * getFromList(list * list, size_t listIndex);
// Returns the node at a given index in a list:
listNode * getNodeFromList(list * list, size_t listIndex);
// Adds the given data to the end of a list:
listNode * addToList(list * list, void * data, listDataType type);
// Insert the given data at a given index in the list:
listNode * insertIntoList(list * list, void * data, listDataType type, size_t listIndex);
// Delete the given data from a list:
bool deleteFromList(list * list, void * data, listDataType type);
// Delete the data from a given point in a list:
int removeFromList(list * list, listDataType type, size_t listIndex);
// Get the index of a given piece of data in a list:
bool getIndexFromList(list * list, void * data, listDataType type, size_t * index);
#endif

View File

@ -21,6 +21,7 @@
#include "../gamelogic.h"
#include "../constants.h"
#include "../playerdata.h"
#include "../linkedlist.h"
#include "../texteffects.h"
#include "../inputoutput.h"

View File

@ -1,24 +1,46 @@
#include "../src/lists.h"
#include "../src/playerdata.h"
#include "../src/linkedlist.h"
#include <stdio.h>
static inline void printAreaList(list * areaList)
{
listData * currentData;
for(int index = 0; index < areaList->itemCount; index++)
{
currentData = getFromList(areaList, index);
printf("%d\t| %s - %s\n", index, currentData->area->areaName, currentData->area->areaDescription);
}
}
void main()
{
areaNode * areaList = createAreaList(createArea("Test Area A", "This is Test Area A"));
areaNode * counter = areaList;
addAreaNodeToList(areaList, createArea("Test Area B", "This is Test Area B"));
addAreaNodeToList(areaList, createArea("Test Area C", "This is Test Area C"));
for(int index = 0; index <= 2; index++)
list * areaList = createList(AREA);
char areaName[256];
char areaDescription[256];
printf("\n--==[ Generating a list of ten items. ]==--\n\n");
for(int count = 1; count <= 10; count++)
{
printf("%s\n", counter->data->areaName);
counter = counter->next;
}
deleteAreaNodeFromList(areaList, getAreaFromList(areaList, 1));
addAreaNodeToList(areaList, createArea("Test Area D", "This is Test Area D"));
counter = areaList;
for(int index = 0; index <= 2; index++)
{
printf("%s\n", counter->data->areaName);
counter = counter->next;
sprintf(areaName, "Area %d", count);
sprintf(areaDescription, "This is Area %d.", count);
addToList(areaList, createArea(areaName, areaDescription) , AREA);
}
printAreaList(areaList);
printf("\n--==[ Inserting items into specific indexes. ]==--\n\n");
insertIntoList(areaList, createArea("Cool, it worked.", "Cool, it worked."), AREA, 0);
insertIntoList(areaList, createArea("Cool, it worked.", "Cool, it worked."), AREA, 6);
insertIntoList(areaList, createArea("Cool, it worked.", "Cool, it worked."), AREA, 11);
printAreaList(areaList);
printf("\n--==[ Removing certain areas from the list. ]==--\n\n");
removeFromList(areaList, AREA, 12);
removeFromList(areaList, AREA, 6);
removeFromList(areaList, AREA, 0);
printAreaList(areaList);
destroyList(&areaList);
printf("");
}