diff --git a/src/botinterface.cpp b/src/botinterface.cpp index d72b498..9d3317f 100755 --- a/src/botinterface.cpp +++ b/src/botinterface.cpp @@ -52,7 +52,7 @@ void AISnake::AdjustProbability(double amount) // 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) +void AISnake::GetNewPath(const std::vector< std::vector >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries, const int snakeSize) { // Search for food /* @@ -80,7 +80,7 @@ void AISnake::GetNewPath(const std::vector< std::vector >& gameBoard, cons } } -void AISnake::BFS(const std::vector< std::vector >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries) { +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; @@ -90,7 +90,7 @@ void AISnake::BFS(const std::vector< std::vector >& gameBoard, const sf::V search.pop(); if (foodFound) { break; } if (visited.at(currentLocation.y).at(currentLocation.x)) { continue; } - if (gameBoard.at(currentLocation.y).at(currentLocation.x) == 'X') { + if (gameBoard.at(currentLocation.y).at(currentLocation.x).m_bFood) { foodFound = true; } botPathUnsanitized.push(currentLocation); @@ -102,7 +102,7 @@ void AISnake::BFS(const std::vector< std::vector >& gameBoard, const sf::V localLocations[3].x -= 1; for (auto i : localLocations) { try { - if (gameBoard.at(i.y).at(i.x) == 'X') { + if (gameBoard.at(i.y).at(i.x).m_bFood) { botPathUnsanitized.push(i); foodFound = true; } @@ -113,7 +113,8 @@ void AISnake::BFS(const std::vector< std::vector >& gameBoard, const sf::V for (sf::Vector2f newLocation : localLocations) { try { if ((!visited.at(newLocation.y).at(newLocation.x)) - && (gameBoard.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) { @@ -124,7 +125,7 @@ void AISnake::BFS(const std::vector< std::vector >& gameBoard, const sf::V } } -void AISnake::DFS(const std::vector< std::vector >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries) { +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; @@ -133,8 +134,8 @@ void AISnake::DFS(const std::vector< std::vector >& gameBoard, const sf::V sf::Vector2f currentLocation = search.top(); search.pop(); if (foodFound) { break; } - if (visited.at(currentLocation.y).at(currentLocation.x)) { continue; } - if (gameBoard.at(currentLocation.y).at(currentLocation.x) == 'X') { + if (visited[currentLocation.y][currentLocation.x]) { continue; } + if (gameBoard[currentLocation.y][currentLocation.x].m_bFood) { foodFound = true; } botPathUnsanitized.push(currentLocation); @@ -146,7 +147,7 @@ void AISnake::DFS(const std::vector< std::vector >& gameBoard, const sf::V localLocations[3].x -= 1; for (auto i : localLocations) { try { - if (gameBoard.at(i.y).at(i.x) == 'X') { + if (gameBoard.at(i.y).at(i.x).m_bFood) { botPathUnsanitized.push(i); foodFound = true; } @@ -163,7 +164,8 @@ void AISnake::DFS(const std::vector< std::vector >& gameBoard, const sf::V } if ((!visited.at(newLocation.y).at(newLocation.x)) - && (gameBoard.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) { diff --git a/src/botinterface.hpp b/src/botinterface.hpp index bfe68fe..1f60659 100755 --- a/src/botinterface.hpp +++ b/src/botinterface.hpp @@ -10,15 +10,15 @@ class AISnake { public: std::stack path; AISnake(); - void GetNewPath(const std::vector< std::vector >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries, const int snakeSize); + void GetNewPath(const std::vector< std::vector >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries, const int snakeSize); PlayerDirection GetInput(const sf::Vector2f* source); void UpdateProbability(int snakeSize); void AdjustProbability(double amount); private: double probabilityBFS = 0.500; std::stack botPathUnsanitized; - void BFS(const std::vector< std::vector >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries); - void DFS(const std::vector< std::vector >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries); + void BFS(const std::vector< std::vector >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries); + void DFS(const std::vector< std::vector >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries); }; #endif diff --git a/src/common.cpp b/src/common.cpp index 7a83edd..3ff09ed 100755 --- a/src/common.cpp +++ b/src/common.cpp @@ -16,3 +16,8 @@ int GenerateRandomNumber(int generationLimit) generatedNumber = distribution(generator); return generatedNumber; } + +GameSpace::GameSpace(void) { + m_bFood = 0; + m_bSnake = 0; +} diff --git a/src/common.hpp b/src/common.hpp index d11a937..61be1d0 100755 --- a/src/common.hpp +++ b/src/common.hpp @@ -1,16 +1,28 @@ -#ifndef COMMON_HPP -#define COMMON_HPP - -void InitializeGenerator(void); -int GenerateRandomNumber(int generationLimit); - -enum PlayerDirection -{ - kNone = 0, - kLeft = 1, - kUp = 2, - kDown = 3, - kRight = 4 -}; - -#endif +#ifndef COMMON_HPP +#define COMMON_HPP + +void InitializeGenerator(void); +int GenerateRandomNumber(int generationLimit); + +enum PlayerDirection +{ + kNone = 0, + kLeft = 1, + kUp = 2, + kDown = 3, + kRight = 4 +}; + +struct GameSpace { + GameSpace(); + unsigned char m_bFood : 1 = 0; + unsigned char m_bSnake : 1 = 0; + unsigned char _2 : 1 = 0; + unsigned char _3 : 1 = 0; + unsigned char _4 : 1 = 0; + unsigned char _5 : 1 = 0; + unsigned char _6 : 1 = 0; + unsigned char _7 : 1 = 0; +}; + +#endif diff --git a/src/gamestate.cpp b/src/gamestate.cpp index cc95091..311390e 100755 --- a/src/gamestate.cpp +++ b/src/gamestate.cpp @@ -16,7 +16,8 @@ GameEngine::GameEngine() void GameEngine::Start() { PrepareGameBoard(); - graphics.StartGameWindow(); + if (!state.m_bNoDisplay) + graphics.StartGameWindow(); Loop(); return; } @@ -25,16 +26,19 @@ void GameEngine::Reset() { AddIteration(); player.Reset(); - if (isBotControlled) { while (!bot.path.empty()) { bot.path.pop(); } } + if (state.m_bIsBotControlled) { while (!bot.path.empty()) { bot.path.pop(); } } PrepareGameBoard(); - isGameOver = false; - graphics.SetShowGame((amountPlayed + 1) % 50 == 0); + state.m_bIsGameOver = false; + if (state.m_bNoDisplay) + graphics.SetShowGame(false); + else + graphics.SetShowGame((amountPlayed + 1) % 50 == 0); return; } void GameEngine::AddIteration(void) { - graphics.CheckContinue(isBotControlled); + graphics.CheckContinue(state.m_bIsBotControlled); if (player.body.size() > 40) { UpdateAverage(); @@ -50,15 +54,16 @@ void GameEngine::AddIteration(void) void GameEngine::Loop(void) { int currentScore = 0; - while (graphics.IsOpen()) + while (graphics.IsOpen() || state.m_bNoDisplay) { - if (isGameOver) { Reset(); } + if (state.m_bIsGameOver) { Reset(); } UpdatePlayerSpeed(); PlaceNewSnakePart(MovePlayer()); RegenerateFood(); currentScore = player.body.size() * 100; //bot.UpdateProbability(player.body.size()); - graphics.DisplayGameState(gameBoard, currentScore); + if (!state.m_bNoDisplay) + graphics.DisplayGameState(gameBoard, currentScore); } return; } @@ -77,17 +82,19 @@ sf::Vector2f GameEngine::GetGameBoundaries(void) void GameEngine::PlaceNewSnakePart(sf::Vector2f location) { if (!player.speed.x && !player.speed.y) { return; } try { - char* locationState = &gameBoard.at(location.y).at(location.x); - if (*locationState == 'O' && (player.body.size() > 1)) { - isGameOver = true; // Game should end (Snake touching snake) + GameSpace* locationState = &gameBoard.at(location.y).at(location.x); + if (locationState->m_bSnake && (player.body.size() > 1)) { + state.m_bIsGameOver = true; // Game should end (Snake touching snake) } - *locationState = 'O'; + locationState->m_bSnake = true; player.body.push(locationState); player.headLocation = location; if (playerFood.location != location) player.Pop(); + else + locationState->m_bFood = false; } catch (const std::out_of_range& error) { - isGameOver = true; // Snake ran into edge + state.m_bIsGameOver = true; // Snake ran into edge } return; } @@ -97,12 +104,12 @@ void GameEngine::PlaceNewSnakePart(sf::Vector2f location) { void GameEngine::RegenerateFood() { // Generate a new food location if the current one is occupied - while (gameBoard.at(playerFood.location.y).at(playerFood.location.x) == 'O') { + while (gameBoard[playerFood.location.y][playerFood.location.x].m_bSnake) { playerFood.GenerateNewFood(GetGameBoundaries()); } // Update the game board with the new food location - gameBoard.at(playerFood.location.y).at(playerFood.location.x) = 'X'; + gameBoard[playerFood.location.y][playerFood.location.x].m_bFood = 1; } @@ -110,25 +117,25 @@ void GameEngine::PrepareGameBoard(void) { gameBoard.clear(); sf::Vector2f boardDimensions = GetGameBoundaries(); - gameBoard.resize(boardDimensions.y, std::vector (boardDimensions.x, ' ')); + gameBoard.resize(boardDimensions.y, std::vector(boardDimensions.x)); // Snake setup player.headLocation.x = GenerateRandomNumber(boardDimensions.x); player.headLocation.y = GenerateRandomNumber(boardDimensions.y); { - char* locationState = &gameBoard.at(player.headLocation.y).at(player.headLocation.x); + GameSpace* locationState = &gameBoard[player.headLocation.y][player.headLocation.x]; player.body.push(locationState); - *locationState = 'O'; + locationState->m_bSnake = true; } // Food setup playerFood.GenerateNewFood(boardDimensions); - gameBoard.at(playerFood.location.y).at(playerFood.location.x) = 'X'; + gameBoard[playerFood.location.y][playerFood.location.x].m_bFood = true; return; } void GameEngine::UpdatePlayerSpeed(void) { PlayerDirection controller; - if (isBotControlled) { + if (state.m_bIsBotControlled) { if (bot.path.empty()) { bot.GetNewPath(gameBoard, player.headLocation, GetGameBoundaries(), player.body.size()); } diff --git a/src/gamestate.hpp b/src/gamestate.hpp index ec9e118..297b57c 100755 --- a/src/gamestate.hpp +++ b/src/gamestate.hpp @@ -18,15 +18,22 @@ public: void Reset(void); void AddIteration(void); sf::Vector2f GetGameBoundaries(void); + struct GameState { + unsigned char m_bIsGameOver : 1 = 0; + unsigned char m_bIsBotControlled : 1 = 1; + unsigned char m_bNoDisplay : 1 = 0; + unsigned char _3 : 1 = 0; + unsigned char _4 : 1 = 0; + unsigned char _5 : 1 = 0; + unsigned char _6 : 1 = 0; + unsigned char _7 : 1 = 0; + } state; private: - std::vector< std::vector > gameBoard; + std::vector< std::vector > gameBoard; PlayerOutput graphics; Snake player; Food playerFood; AISnake bot; - bool isGameOver = 0; - bool isBotControlled = 1; - void DisplayEndScreen(void); void Loop(void); sf::Vector2f MovePlayer(void); void PlaceNewSnakePart(sf::Vector2f location); diff --git a/src/main.cpp b/src/main.cpp index cdf6822..8c591b7 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,20 @@ #include "gamestate.hpp" #include +#include +#include +#include -int main(void) +int main(int argc, char* argv[]) { + std::vector args{argv + 1, argv + argc}; + for (auto it = args.begin(); it != args.end(); it++) { + if (it->compare("--no-gui") == 0) { + g_pEngine->state.m_bNoDisplay = true; + } else { + std::cerr << "[ERROR] Argument option not found, exiting..." << std::endl; + return 1; + } + } g_pEngine = std::make_unique(); g_pEngine->Start(); return 0; diff --git a/src/playerinterface.cpp b/src/playerinterface.cpp index 7bbbadf..2a7ff00 100755 --- a/src/playerinterface.cpp +++ b/src/playerinterface.cpp @@ -21,7 +21,7 @@ PlayerDirection GetPlayerInput(void) bool PlayerOutput::IsOpen(void) { - return gameWindow.isOpen(); + return isWindowAlive; } PlayerOutput::PlayerOutput(void) @@ -47,6 +47,7 @@ void PlayerOutput::CheckContinue(bool isBotControlled) || (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))) { gameWindow.close(); + isWindowAlive = false; return; } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Enter)) { return; } @@ -82,7 +83,7 @@ void PlayerOutput::DisplayScore(int score) { } -void PlayerOutput::DisplayGameState(std::vector< std::vector >& gameBoard, int score) +void PlayerOutput::DisplayGameState(std::vector< std::vector >& gameBoard, int score) { CheckWindowEvents(); if (delay == sf::milliseconds(0)) { return; } @@ -91,19 +92,12 @@ void PlayerOutput::DisplayGameState(std::vector< std::vector >& gameBoard, { for (float x = 0; x < gameBoundaries.x; x++) { - letterOnBoard = &gameBoard.at(y).at(x); - switch (*letterOnBoard) - { - case 'O': + if (gameBoard[y][x].m_bSnake) DrawSnake(sf::Vector2f(x, y)); - break; - case 'X': + else if (gameBoard[y][x].m_bFood) DrawFood(sf::Vector2f(x,y)); - break; - default: + else DrawEmpty(sf::Vector2f(x,y)); - break; - } } } DisplayScore(score); diff --git a/src/playerinterface.hpp b/src/playerinterface.hpp index 3fad189..fea4a70 100755 --- a/src/playerinterface.hpp +++ b/src/playerinterface.hpp @@ -15,7 +15,7 @@ public: PlayerOutput(void); bool IsOpen(void); void CheckContinue(bool isBotControlled); - void DisplayGameState(std::vector< std::vector >& gameBoard, int score); + void DisplayGameState(std::vector< std::vector >& gameBoard, int score); void DisplayScore(int score); void StartGameWindow(void); void SetShowGame(bool isShowing); @@ -29,7 +29,7 @@ private: sf::VideoMode gameVideoSettings; sf::RectangleShape drawObject; sf::Event event; - bool isWindowAlive; + bool isWindowAlive = false; sf::Time delay = sf::milliseconds(1); }; diff --git a/src/snake.cpp b/src/snake.cpp index 65357a7..3ec32ab 100755 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -6,7 +6,7 @@ void Snake::Pop(void) { - *(body.front()) = ' '; + body.front()->m_bSnake = false; body.pop(); return; } diff --git a/src/snake.hpp b/src/snake.hpp index a2388e4..c6f145e 100755 --- a/src/snake.hpp +++ b/src/snake.hpp @@ -4,13 +4,14 @@ #include #include +#include "common.hpp" struct Snake { public: sf::Vector2f headLocation; sf::Vector2f speed; - std::queue body; + std::queue body; void Pop(void); void Reset(void); };