diff --git a/homework_6/CMakeLists.txt b/homework_6/CMakeLists.txt index 564863c..b8ddcfb 100644 --- a/homework_6/CMakeLists.txt +++ b/homework_6/CMakeLists.txt @@ -3,4 +3,5 @@ project(homework_6) set(homeworkName "${PROJECT_NAME}") add_subdirectory(task_1) +add_subdirectory(task_2) add_subdirectory(task_3) diff --git a/homework_6/README.md b/homework_6/README.md index 5f1034b..fc204d6 100644 --- a/homework_6/README.md +++ b/homework_6/README.md @@ -2,4 +2,6 @@ [Task 1. Merge sort](/homework_6/task_1) +[Task 2. Counting rhyme](/homework_6/task_2) + [Task 3. Sorted list](/homework_6/task_3) diff --git a/homework_6/task_2/CMakeLists.txt b/homework_6/task_2/CMakeLists.txt new file mode 100644 index 0000000..39ae0b1 --- /dev/null +++ b/homework_6/task_2/CMakeLists.txt @@ -0,0 +1,9 @@ +project("${homeworkName}_task_2") + +add_library(cyclicList cyclicList.c) + +add_executable(${PROJECT_NAME} main.c) +target_link_libraries(${PROJECT_NAME} cyclicList) + +add_executable(${PROJECT_NAME}_test test.c) +target_link_libraries(${PROJECT_NAME}_test cyclicList) diff --git a/homework_6/task_2/cyclicList.c b/homework_6/task_2/cyclicList.c new file mode 100644 index 0000000..d5d7a96 --- /dev/null +++ b/homework_6/task_2/cyclicList.c @@ -0,0 +1,59 @@ +#include "cyclicList.h" + +#include +#include + +typedef struct ListElement { + struct ListElement *left; + struct ListElement *right; + int value; +} ListElement; + +bool addElementAfter(ListElement *previous, ListElement **newElement, int value) { + ListElement *element = malloc(sizeof(ListElement)); + if (element == NULL) { + return false; + } + + if (previous == NULL) { + element->left = element; + element->right = element; + } else { + ListElement *next = previous->right; + element->left = previous; + element->right = next; + + next->left = element; + previous->right = element; + } + + element->value = value; + *newElement = element; + + return true; +} + +ListElement *getNext(ListElement *element) { + return element->right; +} + +int getValue(ListElement *element) { + return element->value; +} + +void removeElement(ListElement *element) { + ListElement *left = element->left; + ListElement *right = element->right; + left->right = right; + right->left = left; + free(element); +} + +void removeAllElements(ListElement *element) { + ListElement *right = element->right; + do { + ListElement *next = right->right; + removeElement(right); + right = next; + } while (right != element); +} diff --git a/homework_6/task_2/cyclicList.h b/homework_6/task_2/cyclicList.h new file mode 100644 index 0000000..bed6111 --- /dev/null +++ b/homework_6/task_2/cyclicList.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +/// @brief Cyclic list element +typedef struct ListElement ListElement; + +/// @brief Adds new element after specified element +/// @param previous Element that will be on the left relative to new element, +/// must be `NULL` when creating new list +/// @param newElement Pointer to store created `ListElement` to +/// @param value Value to store in new element +/// @return `true` if added successfully, `false` otherwise (allocaton failed) +bool addElementAfter(ListElement *previous, ListElement **newElement, int value); + +/// @brief Gets element on the right of the specified element +/// @param element Element of cyclic list +/// @return Element on the right of the specified element +ListElement *getNext(ListElement *element); + +/// @brief Gets value of the specified element +/// @param element Element of cyclic list +/// @return Value of specified element +int getValue(ListElement *element); + +/// @brief Removes an element (and calls `free()` on it) +/// @param element Element to remove +void removeElement(ListElement *element); + +/// @brief Removes all elements of cyclic list +/// @param element Any element of the list +void removeAllElements(ListElement *element); diff --git a/homework_6/task_2/main.c b/homework_6/task_2/main.c new file mode 100644 index 0000000..b2aa61b --- /dev/null +++ b/homework_6/task_2/main.c @@ -0,0 +1,56 @@ +#include +#include + +#include "cyclicList.h" + +bool getLastWarrior(int warriorsCount, int killersPerWarrior, int *result) { + ListElement *lastElement = NULL; + for (int i = 0; i < warriorsCount; ++i) { + ListElement *newElement = NULL; + if (!addElementAfter(lastElement, &newElement, i + 1)) { + return false; + } + + lastElement = newElement; + } + + // set lastElement to point to element + lastElement = getNext(lastElement); + + while (getNext(lastElement) != lastElement) { + for (int i = 0; i < killersPerWarrior; ++i) { + lastElement = getNext(lastElement); + } + ListElement *next = getNext(lastElement); + removeElement(lastElement); + lastElement = next; + } + + *result = getValue(lastElement); + removeAllElements(lastElement); + + return true; +} + +int readValue(const char *prompt, const char *incorrectValueMessage) { + int value; + printf("%s", prompt); + while ((scanf("%d", &value) != 1) || value <= 0) { + while (getchar() != '\n') {} + printf("%s", incorrectValueMessage); + } + return value; +} + +int main(void) { + int warriorsCount = readValue("warriors count: ", "incorrect value; warriors count should be greater than zero; try again: "); + int nthWarrior = readValue("n-th warrior to be killed: ", "incorrect value; n should be greater than zero; try again: "); + + int result = 0; + if (!getLastWarrior(warriorsCount, nthWarrior - 1, &result)) { + printf("allocation error\n"); + return 1; + } + + printf("last warrior: %d\n", result); +} diff --git a/homework_6/task_2/test.c b/homework_6/task_2/test.c new file mode 100644 index 0000000..6a22df2 --- /dev/null +++ b/homework_6/task_2/test.c @@ -0,0 +1,65 @@ +#define CTEST_MAIN +#define CTEST_SEGFAULT +#include "../../ctest/ctest.h" + +#include + +#include "cyclicList.h" + +int main(int argc, const char *argv[]) { + return ctest_main(argc, argv); +} + +ListElement *add(ListElement *after, int value) { + ListElement *element; + ASSERT_TRUE(addElementAfter(after, &element, value)); + ASSERT_NOT_NULL(element); + + return element; +} + +CTEST(cyclicListTests, createTest) { + ListElement *element = add(NULL, 0); + + ASSERT_TRUE(getNext(element) == element); + ASSERT_TRUE(getNext(getNext(element)) == element); + + removeAllElements(element); +} + +CTEST(cyclicListTests, addElementTest) { + ListElement *elementA = add(NULL, 0); + ListElement *elementB = add(elementA, 1); + ListElement *elementC = add(elementB, 2); + ListElement *elementD = add(elementC, 3); + + ASSERT_TRUE(getNext(elementA) == elementB); + ASSERT_TRUE(getNext(elementB) == elementC); + ASSERT_TRUE(getNext(elementC) == elementD); + ASSERT_TRUE(getNext(elementD) == elementA); + + ASSERT_EQUAL(getValue(elementA), 0); + ASSERT_EQUAL(getValue(elementB), 1); + ASSERT_EQUAL(getValue(elementC), 2); + ASSERT_EQUAL(getValue(elementD), 3); + + removeAllElements(elementA); +} + +CTEST(cyclicListTests, removeElementTest) { + ListElement *elementA = add(NULL, 0); + ListElement *elementB = add(elementA, 0); + ListElement *elementC = add(elementB, 0); + ListElement *elementD = add(elementC, 0); + + removeElement(elementB); + ASSERT_TRUE(getNext(elementA) == elementC); + + removeElement(elementC); + ASSERT_TRUE(getNext(elementA) == elementD); + + removeElement(elementD); + ASSERT_TRUE(getNext(elementA) == elementA); + + removeAllElements(elementA); +}