diff --git a/src/botinterface.cpp b/src/botinterface.cpp index ed22273..f72d7f3 100755 --- a/src/botinterface.cpp +++ b/src/botinterface.cpp @@ -16,7 +16,6 @@ AISnake::AISnake() { PlayerDirection AISnake::GetInput(const sf::Vector2f* source) { - // TODO: Figure out why bot is suddenly going rogue sf::Vector2f directionDelta; if (!source) { std::cout << "[ERROR - AI] Source was borked, bailing" << std::endl; @@ -67,7 +66,6 @@ void AISnake::AddIteration(const int size) } std::cout << "[Info - AI] Current average: " << average << std::endl; std::cout << "[Info - AI] Previous iteration size: " << size << std::endl; - } void AISnake::ResetPath(void) { @@ -76,29 +74,34 @@ void AISnake::ResetPath(void) { // Gets a new path for the bot to follow // Uses DFS algorithm -void AISnake::GetNewPath(const sf::Vector2f& source, const sf::Vector2f& boundaries, const int snakeSize) +void AISnake::GetNewPath(const sf::Vector2f& source) { // Search for food // Probability-based approach for fun double roll = ((double) GenerateRandomNumber(RAND_MAX)) / ((double) RAND_MAX); - if (roll <= probabilityBFS) { BFS(source, boundaries); } - else { DFS(source, boundaries); } + if (roll <= probabilityBFS) { BFS(source); } + else { DFS(source); } UnvisitBoard(); - // Create path for food - path.push(botPathUnsanitized.top()); - botPathUnsanitized.pop(); - TrimPath(); + if (pathFailed) { + pathFailed = false; + EmptyPath(); + path.push(GetAnyOpenPath(source)); + } else { + TrimPath(); + if (path.empty()) + path.push(GetAnyOpenPath(source)); + } } -void AISnake::BFS(const sf::Vector2f& source, const sf::Vector2f& boundaries) { +void AISnake::BFS(const sf::Vector2f& source) { + std::cout << "[Info - AI] Rolled BFS" << std::endl; std::queue search; - bool foodFound = false; search.push(source); while (!search.empty()) { sf::Vector2f currentLocation = search.front(); search.pop(); - if (foodFound) { break; } - if (g_pEngine->gameBoard.at(currentLocation.y).at(currentLocation.x).m_bVisited) { continue; } + if (g_pEngine->gameBoard.at(currentLocation.y).at(currentLocation.x).m_bVisited) + continue; botPathUnsanitized.push(currentLocation); std::array localLocations; localLocations.fill(currentLocation); @@ -108,14 +111,21 @@ void AISnake::BFS(const sf::Vector2f& source, const sf::Vector2f& boundaries) { localLocations[3].x -= 1; for (sf::Vector2f nearby : localLocations) { try { - if (g_pEngine->gameBoard.at(nearby.y).at(nearby.x).m_bFood) { + GameSpace* space = &g_pEngine->gameBoard.at(nearby.y).at(nearby.x); + if (space->m_bFood) { botPathUnsanitized.push(nearby); - foodFound = true; - break; + std::cout << "[TRACE - BFS] Path successfully found food" << std::endl; + return; } - if (g_pEngine->gameBoard.at(nearby.y).at(nearby.x).m_bVisited) + if (nearby.x < 1 || nearby.y < 1 + || nearby.x > g_pEngine->GetGameBoundaries().x - 1 + || nearby.y > g_pEngine->GetGameBoundaries().y - 1) { + continue; + + } + if (space->m_bVisited) continue; - if (g_pEngine->gameBoard.at(nearby.y).at(nearby.x).m_bSnake) + if (space->m_bSnake) continue; search.push(nearby); } catch (const std::out_of_range& error) { @@ -124,18 +134,19 @@ void AISnake::BFS(const sf::Vector2f& source, const sf::Vector2f& boundaries) { } g_pEngine->gameBoard.at(currentLocation.y).at(currentLocation.x).m_bVisited = true; } + std::cout << "[ERROR - BFS] Failed to get a path to food" << std::endl; + pathFailed = true; } -void AISnake::DFS(const sf::Vector2f& source, const sf::Vector2f& boundaries) { +void AISnake::DFS(const sf::Vector2f& source) { + std::cout << "[Info - AI] Rolled DFS" << std::endl; std::stack search; - bool foodFound = false; search.push(source); while (!search.empty()) { sf::Vector2f currentLocation = search.top(); search.pop(); - if (foodFound) { break; } - if (g_pEngine->gameBoard.at(currentLocation.y).at(currentLocation.x).m_bVisited) { continue; } - if (g_pEngine->gameBoard.at(currentLocation.y).at(currentLocation.x).m_bFood) { foodFound = true; } + if (g_pEngine->gameBoard.at(currentLocation.y).at(currentLocation.x).m_bVisited) + continue; botPathUnsanitized.push(currentLocation); std::array localLocations; localLocations.fill(currentLocation); @@ -145,15 +156,21 @@ void AISnake::DFS(const sf::Vector2f& source, const sf::Vector2f& boundaries) { localLocations.at(3).x -= 1; for (sf::Vector2f nearby : localLocations) { try { - if (g_pEngine->gameBoard.at(nearby.y).at(nearby.x).m_bFood) { + GameSpace* space = &g_pEngine->gameBoard.at(nearby.y).at(nearby.x); + if (space->m_bFood) { botPathUnsanitized.push(nearby); - foodFound = true; - std::cout << "[TRACE - AI] Found food, breaking..." << std::endl; - break; + std::cout << "[TRACE - DFS] Path successfully found food" << std::endl; + return; } - if (g_pEngine->gameBoard.at(nearby.y).at(nearby.x).m_bVisited) + if (nearby.x < 1 || nearby.y < 1 + || nearby.x > g_pEngine->GetGameBoundaries().x - 1 + || nearby.y > g_pEngine->GetGameBoundaries().y - 1) { + continue; + + } + if (space->m_bVisited) continue; - if (g_pEngine->gameBoard.at(nearby.y).at(nearby.x).m_bSnake) + if (space->m_bSnake) continue; search.push(nearby); } catch (const std::out_of_range& error) { @@ -162,18 +179,17 @@ void AISnake::DFS(const sf::Vector2f& source, const sf::Vector2f& boundaries) { } g_pEngine->gameBoard.at(currentLocation.y).at(currentLocation.x).m_bVisited = true; } + std::cout << "[ERROR - DFS] Failed to get a path to food" << std::endl; + pathFailed = true; } sf::Vector2f AISnake::GetAnyOpenPath(const sf::Vector2f& source) { sf::Vector2f bail; - sf::Vector2f paths[4]; - paths[0] = source; + std::array paths; + paths.fill(source); paths[0].x -= 1; - paths[1] = source; paths[1].x += 1; - paths[2] = source; paths[2].y -= 1; - paths[3] = source; paths[3].y += 1; for (auto path : paths) { @@ -192,9 +208,10 @@ sf::Vector2f AISnake::GetAnyOpenPath(const sf::Vector2f& source) { } void AISnake::UnvisitBoard(void) { - for (auto i : g_pEngine->gameBoard) - for (auto j : i) + for (std::vector& i : g_pEngine->gameBoard) + for (GameSpace& j : i) j.m_bVisited = false; + std::cout << "[TRACE - AI] Unvisited board" << std::endl; } void AISnake::UpdateAverage(const int size) { @@ -204,12 +221,24 @@ void AISnake::UpdateAverage(const int size) { } void AISnake::TrimPath(void) { + bool reachedSnake = false; + path.push(botPathUnsanitized.top()); // Push food location while (!botPathUnsanitized.empty()) { - sf::Vector2f deltaVector = botPathUnsanitized.top() - path.top(); - int delta = abs(deltaVector.x) + abs(deltaVector.y); - if (delta == 1) { - path.push(botPathUnsanitized.top()); + if (!reachedSnake) { + sf::Vector2f location = botPathUnsanitized.top(); + if (g_pEngine->gameBoard[location.y][location.x].m_bSnake) + reachedSnake = true; + sf::Vector2f deltaVector = location - path.top(); + int delta = abs(deltaVector.x) + abs(deltaVector.y); + if (delta == 1) + path.push(location); } botPathUnsanitized.pop(); } + std::cout << "[TRACE - AI] Trimmed path" << std::endl; +} + +void AISnake::EmptyPath(void) { + while (!botPathUnsanitized.empty()) + botPathUnsanitized.pop(); } diff --git a/src/botinterface.hpp b/src/botinterface.hpp index b1615cf..76a5331 100755 --- a/src/botinterface.hpp +++ b/src/botinterface.hpp @@ -9,7 +9,7 @@ class AISnake { public: std::stack path; AISnake(); - void GetNewPath(const sf::Vector2f& source, const sf::Vector2f& boundaries, const int snakeSize); + void GetNewPath(const sf::Vector2f& source); PlayerDirection GetInput(const sf::Vector2f* source); void UpdateProbability(int snakeSize); void AdjustProbability(double amount); @@ -19,14 +19,16 @@ public: private: int totalLength = 0; double average = 0; - double probabilityBFS = 0.500; + double probabilityBFS = 0.800; + bool pathFailed = false; std::stack botPathUnsanitized; - void BFS(const sf::Vector2f& source, const sf::Vector2f& boundaries); - void DFS(const sf::Vector2f& source, const sf::Vector2f& boundaries); + void BFS(const sf::Vector2f& source); + void DFS(const sf::Vector2f& source); sf::Vector2f GetAnyOpenPath(const sf::Vector2f& source); void UnvisitBoard(void); void UpdateAverage(const int size); void TrimPath(void); + void EmptyPath(void); }; #endif diff --git a/src/gamestate.cpp b/src/gamestate.cpp index b246f6e..8454225 100755 --- a/src/gamestate.cpp +++ b/src/gamestate.cpp @@ -126,7 +126,7 @@ void GameEngine::UpdatePlayerSpeed(void) PlayerDirection controller; if (state.m_bIsBotControlled) { if (bot.path.empty()) { - bot.GetNewPath(player.headLocation, GetGameBoundaries(), player.body.size()); + bot.GetNewPath(player.headLocation); } controller = bot.GetInput(&player.headLocation); }