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