diff --git a/Sorting-Stick/include/Gameplay/Collection/StickCollectionController.h b/Sorting-Stick/include/Gameplay/Collection/StickCollectionController.h index 02ba30c..b5dbb4a 100644 --- a/Sorting-Stick/include/Gameplay/Collection/StickCollectionController.h +++ b/Sorting-Stick/include/Gameplay/Collection/StickCollectionController.h @@ -11,6 +11,7 @@ namespace Gameplay class StickCollectionModel; struct Stick; enum class SortType; + enum class SortingState; class StickCollectionController { @@ -20,6 +21,7 @@ namespace Gameplay std::vector sticks; SortType sort_type; + SortingState sort_State; std::thread sort_thread; @@ -46,6 +48,8 @@ namespace Gameplay bool isCollectionSorted(); void destroy(); + int color_delay; + public: StickCollectionController(); ~StickCollectionController(); @@ -64,6 +68,20 @@ namespace Gameplay int getNumberOfSticks(); int getDelayMilliseconds(); sf::String getTimeComplexity(); + void processBubbleSort(); + void processInsertionSort(); + void processSelectionSort(); + void processMergeSort(); + void InPlaceMerge(int left, int mid, int right); + void MergeSort(int left, int right); + void processQuickSort(); + int partition(int low, int high); + void quickSort(int low, int high); + void ProcessRadixSort(); + void completedColour(); + void countSort(int exponent); + void RadixSort(); + void updateStickPosition(int i); }; } } \ No newline at end of file diff --git a/Sorting-Stick/include/Gameplay/Collection/StickCollectionModel.h b/Sorting-Stick/include/Gameplay/Collection/StickCollectionModel.h index dbd01c8..89a827c 100644 --- a/Sorting-Stick/include/Gameplay/Collection/StickCollectionModel.h +++ b/Sorting-Stick/include/Gameplay/Collection/StickCollectionModel.h @@ -14,7 +14,10 @@ namespace Gameplay QUICK_SORT, RADIX_SORT, }; - + enum class SortingState { + Sorting, + NotSorting, + }; class StickCollectionModel { public: @@ -29,7 +32,8 @@ namespace Gameplay const sf::Color placement_position_element_color = sf::Color::Green; const sf::Color selected_element_color = sf::Color::Blue; - const long operation_delay = 150; + const long operation_delay = 10; + const int colorDelay = 10; StickCollectionModel(); ~StickCollectionModel(); diff --git a/Sorting-Stick/source/Gameplay/Collection/StickCollectionController.cpp b/Sorting-Stick/source/Gameplay/Collection/StickCollectionController.cpp index 13293eb..72392b5 100644 --- a/Sorting-Stick/source/Gameplay/Collection/StickCollectionController.cpp +++ b/Sorting-Stick/source/Gameplay/Collection/StickCollectionController.cpp @@ -5,6 +5,7 @@ #include "Global/ServiceLocator.h" #include "Gameplay/Collection/Stick.h" #include +#include"../../include/Sound/SoundService.h" namespace Gameplay { @@ -13,6 +14,7 @@ namespace Gameplay using namespace UI::UIElement; using namespace Global; using namespace Graphics; + using namespace Sound; StickCollectionController::StickCollectionController() { @@ -29,7 +31,9 @@ namespace Gameplay void StickCollectionController::initialize() { + sort_State = SortingState::NotSorting; collection_view->initialize(this); + initializeSticks(); reset(); } @@ -114,7 +118,10 @@ namespace Gameplay void StickCollectionController::processSortThreadState() { - if (sort_thread.joinable() && isCollectionSorted()) sort_thread.join(); + if (sort_thread.joinable() && isCollectionSorted()) { + sort_thread.join(); + sort_State = SortingState::NotSorting; + } } @@ -132,6 +139,8 @@ namespace Gameplay void StickCollectionController::reset() { current_operation_delay = 0; + sort_State = SortingState::NotSorting; + color_delay = 0; if (sort_thread.joinable()) sort_thread.join(); shuffleSticks(); @@ -143,13 +152,37 @@ namespace Gameplay { current_operation_delay = collection_model->operation_delay; this->sort_type = sort_type; - - /*switch (sort_type) + color_delay = collection_model->colorDelay; + sort_State = SortingState::Sorting; + switch (sort_type) { case Gameplay::Collection::SortType::BUBBLE_SORT: + time_complexity = "O(n^2)"; sort_thread = std::thread(&StickCollectionController::processBubbleSort, this); break; - }*/ + + case Gameplay::Collection::SortType::INSERTION_SORT: + + sort_thread = std::thread(&StickCollectionController::processInsertionSort, this); + break; + + case Gameplay::Collection::SortType::SELECTION_SORT: + sort_thread = std::thread(&StickCollectionController::processSelectionSort, this); + break; + + case Gameplay::Collection::SortType::MERGE_SORT: + sort_thread = std::thread(&StickCollectionController::processMergeSort, this); + break; + + case Gameplay::Collection::SortType::QUICK_SORT: + sort_thread = std::thread(&StickCollectionController::processQuickSort, this); // Placeholder for quick sort implementation + + case Gameplay::Collection::SortType::RADIX_SORT: + sort_thread = std::thread(&StickCollectionController::ProcessRadixSort, this); // Placeholder for radix sort implementation + } + + + } bool StickCollectionController::isCollectionSorted() @@ -181,6 +214,335 @@ namespace Gameplay int StickCollectionController::getDelayMilliseconds() { return current_operation_delay; } sf::String StickCollectionController::getTimeComplexity() { return time_complexity; } + void StickCollectionController::processBubbleSort() + { + + SoundService* sound = Global::ServiceLocator::getInstance()->getSoundService(); + + for (int j = 0; j < sticks.size(); j++) { // Loop through the sticks array + if (sort_State == SortingState::NotSorting) { break; } // Check if sorting has stopped or been interrupted + + bool swapped = false; // To track if a swap was made + + for (int i = 1; i < sticks.size() - j; i++) { // Loop through the array, reducing the range each pass + if (sort_State == SortingState::NotSorting) { break; } // Check if sorting has stopped or been interrupted + + // Increment the number of array accesses and comparisons + number_of_array_access += 2; + number_of_comparisons++; + + sound->playSound(SoundType::COMPARE_SFX); // Play the compare sound effect + + // Set the current sticks to the processing color + sticks[i - 1]->stick_view->setFillColor(collection_model->processing_element_color); + sticks[i]->stick_view->setFillColor(collection_model->processing_element_color); + + if (sticks[i - 1]->data > sticks[i]->data) { // Check if the current stick is greater than the next stick + // Swap the sticks if necessary + std::swap(sticks[i - 1], sticks[i]); + swapped = true; // Set swapped to true if there was a swap + } + + std::this_thread::sleep_for(std::chrono::milliseconds(current_operation_delay)); + + // Reset the stick colors + sticks[i - 1]->stick_view->setFillColor(collection_model->element_color); + sticks[i]->stick_view->setFillColor(collection_model->element_color); + + updateStickPosition(); + } + + if (sticks.size() - j - 1 >= 0) { // Set the last sorted stick to the placement position color + sticks[sticks.size() - j - 1]->stick_view->setFillColor(collection_model->placement_position_element_color); + } + + if (!swapped) { break; } // If no swaps were made, the array is already sorted + } + + completedColour(); + } + void StickCollectionController::processInsertionSort() + { + /*ServiceLocator::getInstance()->getSoundService()->playSound(Sound::SoundType::COMPARE_SFX);*/ + + ServiceLocator::getInstance()->getSoundService()->playSound(Sound::SoundType::COMPARE_SFX); + + for (int i = 1; i < sticks.size(); i++) { + if (sort_State == SortingState::NotSorting) { break; } // Check if sorting has stopped or been interrupted + + int j = i - 1; + Stick* key = sticks[i]; + number_of_array_access++; + sticks[i]->stick_view->setFillColor(collection_model->processing_element_color); // Set the key stick to processing color + std::this_thread::sleep_for(std::chrono::milliseconds(current_operation_delay)); + + while (j >= 0 && sticks[j]->data > key->data) { + + if (sort_State == SortingState::NotSorting) { break; } + number_of_array_access++; + number_of_comparisons++; + sticks[j + 1] = sticks[j]; + sticks[j + 1]->stick_view->setFillColor(collection_model->processing_element_color); // Set the current stick to processing color + j--; + updateStickPosition(); + std::this_thread::sleep_for(std::chrono::milliseconds(current_operation_delay)); + + + } + + sticks[j + 1] = key; // Insert the key stick at the correct position + number_of_array_access++; + sticks[j + 1]->stick_view->setFillColor(collection_model->processing_element_color); // Set the inserted stick to placement position color + updateStickPosition(); + std::this_thread::sleep_for(std::chrono::milliseconds(current_operation_delay)); + sticks[j + 1]->stick_view->setFillColor(collection_model->selected_element_color); // Set the inserted stick to placement position color + } + completedColour(); + } + void StickCollectionController::processSelectionSort() + { + for (int i = 0; i < sticks.size() - 1; i++) { + + if (sort_State == SortingState::NotSorting) { break; } // Check if sorting has stopped or been interrupted + + int min = i; + sticks[i]->stick_view->setFillColor(collection_model->selected_element_color); + number_of_array_access++; + + for (int j = i; j < sticks.size(); j++) { + if (sort_State == SortingState::NotSorting) { break; } + number_of_array_access++; + number_of_comparisons++; + sticks[j]->stick_view->setFillColor(collection_model->processing_element_color); + std::this_thread::sleep_for(std::chrono::milliseconds(current_operation_delay)); + if (sticks[j]->data < sticks[min]->data) { + sticks[min]->stick_view->setFillColor(collection_model->element_color); + min = j; + sticks[min]->stick_view->setFillColor(collection_model->processing_element_color); + + } + else { + sticks[j]->stick_view->setFillColor(collection_model->element_color); + } + + number_of_array_access += 3; + + + sticks[i]->stick_view->setFillColor(collection_model->placement_position_element_color); // Mark as sorted + updateStickPosition(); + + } + + number_of_array_access += 3; + std::swap(sticks[min], sticks[i]); // Place the found minimum at its final position + + sticks[i]->stick_view->setFillColor(collection_model->placement_position_element_color); // Mark as sorted + updateStickPosition(); + + } + + + // Ensure the last stick is also marked as sorted + sticks[sticks.size() - 1]->stick_view->setFillColor(collection_model->placement_position_element_color); + completedColour(); + + } + + void StickCollectionController::processMergeSort() + { + MergeSort(0, sticks.size() - 1); + completedColour(); + + } + + void StickCollectionController::InPlaceMerge(int left, int mid, int right) + { + int i = left; + int j = mid + 1; + + while (i <= mid && j <= right) { + number_of_comparisons++; + number_of_array_access += 2; + + + + if (sticks[i]->data <= sticks[j]->data) { + + i++; + } + else { + // Save the smaller value + Stick* value = sticks[j]; + int index = j; + + // Shift elements rightward + while (index != i) { + sticks[index] = sticks[index - 1]; + index--; + number_of_array_access += 2; + } + + // Put value at correct place + sticks[i] = value; + number_of_array_access += 2; + + i++; + mid++; + j++; + updateStickPosition(); + } + + sticks[i - 1]->stick_view->setFillColor(collection_model->processing_element_color); + std::this_thread::sleep_for(std::chrono::milliseconds(current_operation_delay)); + sticks[i - 1]->stick_view->setFillColor(collection_model->element_color); + } + } + + void StickCollectionController::MergeSort(int left, int right) + { + if (left < right) { + int mid = left + (right - left) / 2; + + + MergeSort(left, mid); + MergeSort(mid + 1, right); + + + InPlaceMerge(left, mid, right); + } + } + + void StickCollectionController::processQuickSort() + { + quickSort(0, sticks.size() - 1); + completedColour(); + } + + int StickCollectionController::partition(int low, int high) + { + sticks[high]->stick_view->setFillColor(collection_model->selected_element_color); + int i = low - 1; + + for (int j = low; j < high; j++) { + sticks[j]->stick_view->setFillColor(collection_model->processing_element_color); + + if (sticks[j]->data < sticks[high]->data) { + i++; + number_of_array_access += 3; + number_of_comparisons++; + std::swap(sticks[i], sticks[j]); + updateStickPosition(); + std::this_thread::sleep_for(std::chrono::milliseconds(current_operation_delay)); + + } + sticks[j]->stick_view->setFillColor(collection_model->element_color); + } + std::swap(sticks[i + 1], sticks[high]); + number_of_array_access += 3; + return i + 1; + } + + void StickCollectionController::quickSort(int low, int high) + { + if (low < high) { + int location = partition(low, high); + quickSort(low, location - 1); + quickSort(location + 1, high); + } + } + + void StickCollectionController::ProcessRadixSort() + { + RadixSort(); + completedColour(); + } + + + + void StickCollectionController::completedColour() + { + + for (int i = 0; i < sticks.size(); i++) + { + if (sort_State == SortingState::NotSorting) { + break; + } + + sticks[i]->stick_view->setFillColor(collection_model->element_color); // Reset to default color if not completed + + + + for (int j = 0; j < sticks.size(); j++) { + + if (sort_State == SortingState::NotSorting) { + + break; + } + + /*ServiceLocator::getInstance()->getSoundService()->playSound(Sound::SoundType::COMPARE_SFX);*/ + sticks[j]->stick_view->setFillColor(collection_model->placement_position_element_color); + std::this_thread::sleep_for(std::chrono::milliseconds(color_delay)); + + } + + } + } + void StickCollectionController::countSort(int exponent) + { + SoundService* sound = Global::ServiceLocator::getInstance()->getSoundService(); + std::vector output(sticks.size()); + std::vector count(10, 0); + + // Process each element to count digits + for (int i = 0; i < sticks.size(); ++i) { + sound->playSound(SoundType::COMPARE_SFX); + int digit = (sticks[i]->data / exponent) % 10; + count[digit]++; + number_of_array_access++; + sticks[i]->stick_view->setFillColor(collection_model->processing_element_color); + std::this_thread::sleep_for(std::chrono::milliseconds(current_operation_delay / 2)); // Delay for visual processing + sticks[i]->stick_view->setFillColor(collection_model->element_color); // Reset color after processing + } + + // Accumulate the count array + for (int i = 1; i < 10; ++i) { + count[i] += count[i - 1]; + } + + // Sorting based on the current digit + for (int i = sticks.size() - 1; i >= 0; --i) { + + int digit = (sticks[i]->data / exponent) % 10; + output[count[digit] - 1] = sticks[i]; + output[count[digit] - 1]->stick_view->setFillColor(collection_model->processing_element_color); + count[digit]--; + number_of_array_access++; + + } + + // Place elements back into the main array + for (int i = 0; i < sticks.size(); ++i) { + sticks[i] = output[i]; + sticks[i]->stick_view->setFillColor(collection_model->placement_position_element_color); // Final sorted color for this digit + updateStickPosition(i); + std::this_thread::sleep_for(std::chrono::milliseconds(current_operation_delay)); // Delay to observe final sorting state + } + } + void StickCollectionController::RadixSort() + { + int maxElement = INT_MIN; + const int size = sticks.size(); + + for (int i = 0; i < size; ++i) maxElement = std::max(sticks[i]->data, maxElement); + for (int exponent = 1; maxElement / exponent > 0; exponent *= 10) countSort(exponent); + } + void StickCollectionController::updateStickPosition(int i) + { + float x_position = (i * sticks[i]->stick_view->getSize().x) + ((i)*collection_model->elements_spacing); + float y_position = collection_model->element_y_position - sticks[i]->stick_view->getSize().y; + + sticks[i]->stick_view->setPosition(sf::Vector2f(x_position, y_position)); + } } } diff --git a/Sorting-Stick/source/UI/MainMenu/MainMenuUIController.cpp b/Sorting-Stick/source/UI/MainMenu/MainMenuUIController.cpp index 12338d0..b7aa5c4 100644 --- a/Sorting-Stick/source/UI/MainMenu/MainMenuUIController.cpp +++ b/Sorting-Stick/source/UI/MainMenu/MainMenuUIController.cpp @@ -5,6 +5,7 @@ #include "Event/EventService.h" #include "Global/Config.h" #include "Global/ServiceLocator.h" +#include"../../include/Main/GameService.h" namespace UI { @@ -15,6 +16,7 @@ namespace UI using namespace UIElement; using namespace Sound; using namespace Graphics; + MainMenuUIController::MainMenuUIController() { @@ -73,43 +75,56 @@ namespace UI void MainMenuUIController::registerButtonCallback() { - //bubble_sort_button->registerCallbackFuntion(std::bind(&MainMenuUIController::bubbleSortButtonCallback, this)); - //insertion_sort_button->registerCallbackFuntion(std::bind(&MainMenuUIController::insertionSortButtonCallback, this)); - //selection_sort_button->registerCallbackFuntion(std::bind(&MainMenuUIController::selectionSortButtonCallback, this)); - //merge_sort_button->registerCallbackFuntion(std::bind(&MainMenuUIController::mergeSortButtonCallback, this)); - //quick_sort_button->registerCallbackFuntion(std::bind(&MainMenuUIController::quickSortButtonCallback, this)); - //radix_sort_button->registerCallbackFuntion(std::bind(&MainMenuUIController::radixSortButtonCallback, this)); + bubble_sort_button->registerCallbackFuntion(std::bind(&MainMenuUIController::bubbleSortButtonCallback, this)); + insertion_sort_button->registerCallbackFuntion(std::bind(&MainMenuUIController::insertionSortButtonCallback, this)); + selection_sort_button->registerCallbackFuntion(std::bind(&MainMenuUIController::selectionSortButtonCallback, this)); + merge_sort_button->registerCallbackFuntion(std::bind(&MainMenuUIController::mergeSortButtonCallback, this)); + quick_sort_button->registerCallbackFuntion(std::bind(&MainMenuUIController::quickSortButtonCallback, this)); + radix_sort_button->registerCallbackFuntion(std::bind(&MainMenuUIController::radixSortButtonCallback, this)); quit_button->registerCallbackFuntion(std::bind(&MainMenuUIController::quitButtonCallback, this)); } void MainMenuUIController::bubbleSortButtonCallback() { ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::BUTTON_CLICK); + GameService::setGameState(GameState::GAMEPLAY); + ServiceLocator::getInstance()->getGameplayService()->sortElement(Gameplay::Collection::SortType::BUBBLE_SORT); + } void MainMenuUIController::insertionSortButtonCallback() { ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::BUTTON_CLICK); + GameService::setGameState(GameState::GAMEPLAY); + ServiceLocator::getInstance()->getGameplayService()->sortElement(Gameplay::Collection::SortType::INSERTION_SORT); } void MainMenuUIController::selectionSortButtonCallback() { ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::BUTTON_CLICK); + GameService::setGameState(GameState::GAMEPLAY); + ServiceLocator::getInstance()->getGameplayService()->sortElement(Gameplay::Collection::SortType::SELECTION_SORT); } void MainMenuUIController::mergeSortButtonCallback() { ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::BUTTON_CLICK); + GameService::setGameState(GameState::GAMEPLAY); + ServiceLocator::getInstance()->getGameplayService()->sortElement(Gameplay::Collection::SortType::MERGE_SORT); } void MainMenuUIController::quickSortButtonCallback() { ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::BUTTON_CLICK); + GameService::setGameState(GameState::GAMEPLAY); + ServiceLocator::getInstance()->getGameplayService()->sortElement(Gameplay::Collection::SortType::QUICK_SORT); } void MainMenuUIController::radixSortButtonCallback() { ServiceLocator::getInstance()->getSoundService()->playSound(SoundType::BUTTON_CLICK); + GameService::setGameState(GameState::GAMEPLAY); + ServiceLocator::getInstance()->getGameplayService()->sortElement(Gameplay::Collection::SortType::RADIX_SORT); } void MainMenuUIController::quitButtonCallback()