#include "botinterface.hpp" #include "common.hpp" #include #include #include #include #include #include PlayerDirection lastKnownDirection = kNone; AISnake::AISnake() { ; } PlayerDirection AISnake::GetInput(const sf::Vector2f* source) { sf::Vector2f directionDelta; if (*source == path.top()) { path.pop(); } if (path.empty()) { return kUp; } // Snake is trapped directionDelta = *source - path.top(); path.pop(); if ((directionDelta.y == 1) && (lastKnownDirection != kDown)) { lastKnownDirection = kUp; } else if ((directionDelta.y == -1) && (lastKnownDirection != kUp)) { lastKnownDirection = kDown; } else if ((directionDelta.x == 1) && (lastKnownDirection != kRight)) { lastKnownDirection = kLeft; } else if ((directionDelta.x == -1) && (lastKnownDirection != kLeft)) { lastKnownDirection = kRight; } return lastKnownDirection; } void AISnake::UpdateProbability(int snakeSize) { probabilityBFS = 1 - ((double) snakeSize) / 1000; return; } void AISnake::AdjustProbability(double amount) { probabilityBFS += amount; if (probabilityBFS > 1.0) { probabilityBFS = 1.0; } if (probabilityBFS < 0.0) { probabilityBFS = 0.0; } std::cout << "[Info - AISnake] New BFS probability: " << probabilityBFS << std::endl; return; } // Gets a new path for the bot to follow // Uses DFS algorithm void AISnake::GetNewPath(const std::vector< std::vector >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries, const int snakeSize) { // Search for food /* BFS(gameBoard, source, boundaries); if (gameBoard[botPathUnsanitized.top().y][botPathUnsanitized.top().x] != 'X') { while (!botPathUnsanitized.empty()) { botPathUnsanitized.pop(); } DFS(gameBoard, source, boundaries); while (botPathUnsanitized.size() > 15) { botPathUnsanitized.pop(); } } */ // Probability-based approach for fun double roll = ((double) GenerateRandomNumber(RAND_MAX)) / ((double) RAND_MAX); if (roll <= probabilityBFS) { BFS(gameBoard, source, boundaries); } else { DFS(gameBoard, source, boundaries); } // Create path for food path.push(botPathUnsanitized.top()); botPathUnsanitized.pop(); 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()); } botPathUnsanitized.pop(); } } void AISnake::BFS(const std::vector< std::vector >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries) { std::queue search; std::vector> visited(boundaries.y, std::vector (boundaries.x, false)); bool foodFound = false; search.push(source); while (!search.empty()) { sf::Vector2f currentLocation = search.front(); search.pop(); if (foodFound) { break; } if (visited.at(currentLocation.y).at(currentLocation.x)) { continue; } if (gameBoard.at(currentLocation.y).at(currentLocation.x).m_bFood) { foodFound = true; } botPathUnsanitized.push(currentLocation); std::array localLocations; localLocations.fill(currentLocation); localLocations[0].y += 1; localLocations[1].x += 1; localLocations[2].y -= 1; localLocations[3].x -= 1; for (auto i : localLocations) { try { if (gameBoard.at(i.y).at(i.x).m_bFood) { botPathUnsanitized.push(i); foodFound = true; } } catch (const std::out_of_range& error) { continue; // Out of bounds } } for (sf::Vector2f newLocation : localLocations) { try { if ((!visited.at(newLocation.y).at(newLocation.x)) && (gameBoard.at(newLocation.y).at(newLocation.x).m_bFood) && (gameBoard.at(newLocation.y).at(newLocation.x).m_bSnake)) { search.push(newLocation); } } catch (const std::out_of_range& error) { continue; // Out of bounds } } visited.at(currentLocation.y).at(currentLocation.x) = true; } } void AISnake::DFS(const std::vector< std::vector >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries) { std::stack search; std::vector> visited(boundaries.y, std::vector (boundaries.x, false)); bool foodFound = false; search.push(source); while (!search.empty()) { sf::Vector2f currentLocation = search.top(); search.pop(); if (foodFound) { break; } if (visited[currentLocation.y][currentLocation.x]) { continue; } if (gameBoard[currentLocation.y][currentLocation.x].m_bFood) { foodFound = true; } botPathUnsanitized.push(currentLocation); std::array localLocations; localLocations.fill(currentLocation); localLocations[0].y += 1; localLocations[1].x += 1; localLocations[2].y -= 1; localLocations[3].x -= 1; for (auto i : localLocations) { try { if (gameBoard.at(i.y).at(i.x).m_bFood) { botPathUnsanitized.push(i); foodFound = true; } } catch (const std::out_of_range& error) { continue; // Out of bounds } } for (sf::Vector2f newLocation : localLocations) { try { if (newLocation.x < 1 || newLocation.y < 1 || newLocation.x > boundaries.x - 2 || newLocation.y > boundaries.y - 2) { continue; } if ((!visited.at(newLocation.y).at(newLocation.x)) && !(gameBoard.at(newLocation.y).at(newLocation.x).m_bFood) && !(gameBoard.at(newLocation.y).at(newLocation.x).m_bSnake)) { search.push(newLocation); } } catch (const std::out_of_range& error) { continue; // Out of bounds } } visited.at(currentLocation.y).at(currentLocation.x) = true; } }