snakeplusplus/src/botinterface.cpp

101 lines
3.7 KiB
C++
Raw Normal View History

#include "botinterface.hpp"
#include "common.hpp"
2023-10-13 19:07:08 -05:00
#include <array>
#include <cstdlib>
#include <queue>
#include <stdexcept>
#include <SFML/System/Vector2.hpp>
namespace snakeplusplus
{
PlayerDirection lastKnownDirection = kNone;
2023-10-13 19:07:08 -05:00
AISnake::AISnake() {
;
}
PlayerDirection AISnake::GetInput(const sf::Vector2f* source)
{
sf::Vector2f directionDelta;
2023-10-13 19:07:08 -05:00
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; }
2023-10-13 19:07:08 -05:00
else if ((directionDelta.y == -1)
&& (lastKnownDirection != kUp))
{ lastKnownDirection = kDown; }
2023-10-13 19:07:08 -05:00
else if ((directionDelta.x == 1)
&& (lastKnownDirection != kRight))
{ lastKnownDirection = kLeft; }
2023-10-13 19:07:08 -05:00
else if ((directionDelta.x == -1)
&& (lastKnownDirection != kLeft))
{ lastKnownDirection = kRight; }
return lastKnownDirection;
}
2023-10-13 19:07:08 -05:00
// Gets a new path for the bot to follow
// Uses DFS algorithm
void AISnake::GetNewPath(const std::vector< std::vector<char> >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries)
{
std::queue<sf::Vector2f> search;
std::stack<sf::Vector2f> botPathUnsanitized;
std::vector<std::vector<bool>> visited(boundaries.y, std::vector<bool> (boundaries.x, false));
sf::Vector2f currentLocation;
std::array<sf::Vector2f, 4> localLocations;
bool foodFound = false;
search.push(source);
// Search for food
while (!search.empty()) {
currentLocation = search.front();
search.pop();
if (foodFound) { break; }
if (visited.at(currentLocation.y).at(currentLocation.x)) { continue; }
botPathUnsanitized.push(currentLocation);
if (gameBoard.at(currentLocation.y).at(currentLocation.x) == 'X') {
foodFound = true;
}
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) == 'X') {
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) == ' ')) {
search.push(newLocation);
}
} catch (const std::out_of_range& error) {
continue; // Out of bounds
}
}
visited.at(currentLocation.y).at(currentLocation.x) = true;
}
// Create path for food
path.push(botPathUnsanitized.top());
botPathUnsanitized.pop();
while (!botPathUnsanitized.empty()) {
currentLocation = botPathUnsanitized.top();
sf::Vector2f deltaVector = currentLocation - path.top();
int delta = abs(deltaVector.x) + abs(deltaVector.y);
if (delta == 1) {
path.push(botPathUnsanitized.top());
}
botPathUnsanitized.pop();
}
}
}