diff --git a/src/botinterface.cpp b/src/botinterface.cpp index 15bfbba..d72b498 100755 --- a/src/botinterface.cpp +++ b/src/botinterface.cpp @@ -7,172 +7,169 @@ #include #include -namespace snakeplusplus +PlayerDirection lastKnownDirection = kNone; + +AISnake::AISnake() { + ; +} + +PlayerDirection AISnake::GetInput(const sf::Vector2f* source) { - PlayerDirection lastKnownDirection = kNone; + 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; +} - AISnake::AISnake() { - ; +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(); } } - - 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()); } - */ - // 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) == 'X') { - 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) == '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; - } - } - - 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.at(currentLocation.y).at(currentLocation.x)) { continue; } - if (gameBoard.at(currentLocation.y).at(currentLocation.x) == 'X') { - 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) == 'X') { - 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) == ' ')) { - search.push(newLocation); - } - } catch (const std::out_of_range& error) { - continue; // Out of bounds - } - } - visited.at(currentLocation.y).at(currentLocation.x) = true; - } + } +} + +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) == 'X') { + 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) == '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; + } +} + +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.at(currentLocation.y).at(currentLocation.x)) { continue; } + if (gameBoard.at(currentLocation.y).at(currentLocation.x) == 'X') { + 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) == 'X') { + 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) == ' ')) { + search.push(newLocation); + } + } catch (const std::out_of_range& error) { + continue; // Out of bounds + } + } + visited.at(currentLocation.y).at(currentLocation.x) = true; } } diff --git a/src/botinterface.hpp b/src/botinterface.hpp index 7bf29b7..bfe68fe 100755 --- a/src/botinterface.hpp +++ b/src/botinterface.hpp @@ -6,22 +6,19 @@ #include #include -namespace snakeplusplus -{ - 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); - 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); - }; -} +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); + 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); +}; #endif diff --git a/src/common.cpp b/src/common.cpp index 62088ee..7a83edd 100755 --- a/src/common.cpp +++ b/src/common.cpp @@ -2,20 +2,17 @@ #include #include "common.hpp" -namespace snakeplusplus +std::default_random_engine generator; +void InitializeGenerator(void) { - std::default_random_engine generator; - void InitializeGenerator(void) - { - generator.seed(std::random_device{}()); - } - - // Returns a newly generated number - int GenerateRandomNumber(int generationLimit) - { - int generatedNumber; - std::uniform_int_distribution<> distribution(0, generationLimit - 1); - generatedNumber = distribution(snakeplusplus::generator); - return generatedNumber; - } + generator.seed(std::random_device{}()); +} + +// Returns a newly generated number +int GenerateRandomNumber(int generationLimit) +{ + int generatedNumber; + std::uniform_int_distribution<> distribution(0, generationLimit - 1); + generatedNumber = distribution(generator); + return generatedNumber; } diff --git a/src/common.hpp b/src/common.hpp index 82f60e2..d11a937 100755 --- a/src/common.hpp +++ b/src/common.hpp @@ -1,20 +1,16 @@ #ifndef COMMON_HPP #define COMMON_HPP -namespace snakeplusplus +void InitializeGenerator(void); +int GenerateRandomNumber(int generationLimit); + +enum PlayerDirection { - void InitializeGenerator(void); - int GenerateRandomNumber(int generationLimit); - - enum PlayerDirection - { - kNone = 0, - kLeft = 1, - kUp = 2, - kDown = 3, - kRight = 4 - }; - -} + kNone = 0, + kLeft = 1, + kUp = 2, + kDown = 3, + kRight = 4 +}; #endif diff --git a/src/gamestate.cpp b/src/gamestate.cpp index 98840d0..cc95091 100755 --- a/src/gamestate.cpp +++ b/src/gamestate.cpp @@ -7,165 +7,163 @@ #include "playerinterface.hpp" #include "gamestate.hpp" -namespace snakeplusplus +GameEngine::GameEngine() { - GameEngine::GameEngine() - { - InitializeGenerator(); - return; - } - - void GameEngine::Start() - { - PrepareGameBoard(); - graphics.StartGameWindow(); - Loop(); - return; - } - - void GameEngine::Reset() - { - AddIteration(); - player.Reset(); - if (isBotControlled) { while (!bot.path.empty()) { bot.path.pop(); } } - PrepareGameBoard(); - isGameOver = false; - graphics.SetShowGame((amountPlayed + 1) % 50 == 0); - return; - } - - void GameEngine::AddIteration(void) - { - graphics.CheckContinue(isBotControlled); - if (player.body.size() > 40) - { - UpdateAverage(); - double adjustmentAmount = 0.002; - if (average > player.body.size()) { bot.AdjustProbability(adjustmentAmount); } - else { bot.AdjustProbability(-adjustmentAmount); } - } - std::cout << "[Info - GameEngine] Current average: " << average << std::endl; - std::cout << "[Info - GameEngine] Previous iteration size: " << player.body.size() << std::endl; - - } - - void GameEngine::Loop(void) - { - int currentScore = 0; - while (graphics.IsOpen()) - { - if (isGameOver) { Reset(); } - UpdatePlayerSpeed(); - PlaceNewSnakePart(MovePlayer()); - RegenerateFood(); - currentScore = player.body.size() * 100; - //bot.UpdateProbability(player.body.size()); - graphics.DisplayGameState(gameBoard, currentScore); - } - return; - } - - sf::Vector2f GameEngine::MovePlayer(void) - { - return sf::Vector2f(player.headLocation.x + player.speed.x, player.headLocation.y + player.speed.y); - } - - - sf::Vector2f GameEngine::GetGameBoundaries(void) - { - return graphics.gameBoundaries; - } - - 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) - } - *locationState = 'O'; - player.body.push(locationState); - player.headLocation = location; - if (playerFood.location != location) - player.Pop(); - } catch (const std::out_of_range& error) { - isGameOver = true; // Snake ran into edge - } - return; - } - - - // Generates new food until not colliding with player - 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') { - playerFood.GenerateNewFood(GetGameBoundaries()); - } - - // Update the game board with the new food location - gameBoard.at(playerFood.location.y).at(playerFood.location.x) = 'X'; - } - - - void GameEngine::PrepareGameBoard(void) - { - gameBoard.clear(); - sf::Vector2f boardDimensions = GetGameBoundaries(); - 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); - player.body.push(locationState); - *locationState = 'O'; - } - // Food setup - playerFood.GenerateNewFood(boardDimensions); - gameBoard.at(playerFood.location.y).at(playerFood.location.x) = 'X'; - return; - } - - void GameEngine::UpdatePlayerSpeed(void) - { - PlayerDirection controller; - if (isBotControlled) { - if (bot.path.empty()) { - bot.GetNewPath(gameBoard, player.headLocation, GetGameBoundaries(), player.body.size()); - } - controller = bot.GetInput(&player.headLocation); - } - else { controller = GetPlayerInput(); } - switch (controller) { - case kUp: - if (player.speed.y == kUnitSpeed) { break; } - player.speed.x = 0; - player.speed.y = -kUnitSpeed; - break; - case kLeft: - if (player.speed.x == kUnitSpeed) { break; } - player.speed.x = -kUnitSpeed; - player.speed.y = 0; - break; - case kRight: - if (player.speed.x == -kUnitSpeed) { break; } - player.speed.x = kUnitSpeed; - player.speed.y = 0; - break; - case kDown: - if (player.speed.y == -kUnitSpeed) { break; } - player.speed.x = 0; - player.speed.y = kUnitSpeed; - break; - default: - break; - } - return; - } - void GameEngine::UpdateAverage() { - totalLength += player.body.size(); - amountPlayed += 1; - average = (double)totalLength / amountPlayed; - } + InitializeGenerator(); + return; +} + +void GameEngine::Start() +{ + PrepareGameBoard(); + graphics.StartGameWindow(); + Loop(); + return; +} + +void GameEngine::Reset() +{ + AddIteration(); + player.Reset(); + if (isBotControlled) { while (!bot.path.empty()) { bot.path.pop(); } } + PrepareGameBoard(); + isGameOver = false; + graphics.SetShowGame((amountPlayed + 1) % 50 == 0); + return; +} + +void GameEngine::AddIteration(void) +{ + graphics.CheckContinue(isBotControlled); + if (player.body.size() > 40) + { + UpdateAverage(); + double adjustmentAmount = 0.002; + if (average > player.body.size()) { bot.AdjustProbability(adjustmentAmount); } + else { bot.AdjustProbability(-adjustmentAmount); } + } + std::cout << "[Info - GameEngine] Current average: " << average << std::endl; + std::cout << "[Info - GameEngine] Previous iteration size: " << player.body.size() << std::endl; + +} + +void GameEngine::Loop(void) +{ + int currentScore = 0; + while (graphics.IsOpen()) + { + if (isGameOver) { Reset(); } + UpdatePlayerSpeed(); + PlaceNewSnakePart(MovePlayer()); + RegenerateFood(); + currentScore = player.body.size() * 100; + //bot.UpdateProbability(player.body.size()); + graphics.DisplayGameState(gameBoard, currentScore); + } + return; +} + +sf::Vector2f GameEngine::MovePlayer(void) +{ + return sf::Vector2f(player.headLocation.x + player.speed.x, player.headLocation.y + player.speed.y); +} + + +sf::Vector2f GameEngine::GetGameBoundaries(void) +{ + return graphics.gameBoundaries; +} + +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) + } + *locationState = 'O'; + player.body.push(locationState); + player.headLocation = location; + if (playerFood.location != location) + player.Pop(); + } catch (const std::out_of_range& error) { + isGameOver = true; // Snake ran into edge + } + return; +} + + +// Generates new food until not colliding with player +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') { + playerFood.GenerateNewFood(GetGameBoundaries()); + } + + // Update the game board with the new food location + gameBoard.at(playerFood.location.y).at(playerFood.location.x) = 'X'; +} + + +void GameEngine::PrepareGameBoard(void) +{ + gameBoard.clear(); + sf::Vector2f boardDimensions = GetGameBoundaries(); + 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); + player.body.push(locationState); + *locationState = 'O'; + } + // Food setup + playerFood.GenerateNewFood(boardDimensions); + gameBoard.at(playerFood.location.y).at(playerFood.location.x) = 'X'; + return; +} + +void GameEngine::UpdatePlayerSpeed(void) +{ + PlayerDirection controller; + if (isBotControlled) { + if (bot.path.empty()) { + bot.GetNewPath(gameBoard, player.headLocation, GetGameBoundaries(), player.body.size()); + } + controller = bot.GetInput(&player.headLocation); + } + else { controller = GetPlayerInput(); } + switch (controller) { + case kUp: + if (player.speed.y == kUnitSpeed) { break; } + player.speed.x = 0; + player.speed.y = -kUnitSpeed; + break; + case kLeft: + if (player.speed.x == kUnitSpeed) { break; } + player.speed.x = -kUnitSpeed; + player.speed.y = 0; + break; + case kRight: + if (player.speed.x == -kUnitSpeed) { break; } + player.speed.x = kUnitSpeed; + player.speed.y = 0; + break; + case kDown: + if (player.speed.y == -kUnitSpeed) { break; } + player.speed.x = 0; + player.speed.y = kUnitSpeed; + break; + default: + break; + } + return; +} + +void GameEngine::UpdateAverage() { + totalLength += player.body.size(); + amountPlayed += 1; + average = (double)totalLength / amountPlayed; } diff --git a/src/gamestate.hpp b/src/gamestate.hpp index e71949d..cbee036 100755 --- a/src/gamestate.hpp +++ b/src/gamestate.hpp @@ -3,42 +3,40 @@ #define GAMESTATE_HPP #include +#include #include "botinterface.hpp" #include "snake.hpp" #include "playerinterface.hpp" -namespace snakeplusplus -{ - const int kUnitSpeed = 1; +const int kUnitSpeed = 1; - class GameEngine - { - public: - GameEngine(); - void Start(void); - void Reset(void); - void AddIteration(void); - sf::Vector2f GetGameBoundaries(void); - private: - 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); - void RegenerateFood(void); - void PrepareGameBoard(void); - void UpdatePlayerSpeed(); - void UpdateAverage(); - int totalLength = 0; - int amountPlayed = 0; - double average = 0; - }; -} +class GameEngine +{ +public: + GameEngine(); + void Start(void); + void Reset(void); + void AddIteration(void); + sf::Vector2f GetGameBoundaries(void); +private: + 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); + void RegenerateFood(void); + void PrepareGameBoard(void); + void UpdatePlayerSpeed(); + void UpdateAverage(); + int totalLength = 0; + int amountPlayed = 0; + double average = 0; +}; #endif diff --git a/src/main.cpp b/src/main.cpp index 2d529fb..a26a74d 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ int main(void) { - snakeplusplus::GameEngine game; + GameEngine game; game.Start(); return 0; } diff --git a/src/playerinterface.cpp b/src/playerinterface.cpp index fe4a5f4..7bbbadf 100755 --- a/src/playerinterface.cpp +++ b/src/playerinterface.cpp @@ -2,173 +2,170 @@ #include #include -namespace snakeplusplus +PlayerDirection GetPlayerInput(void) { - PlayerDirection GetPlayerInput(void) - { - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) - || sf::Keyboard::isKeyPressed(sf::Keyboard::A)) - return kLeft; - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up) - || sf::Keyboard::isKeyPressed(sf::Keyboard::W)) - return kUp; - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) - || sf::Keyboard::isKeyPressed(sf::Keyboard::S)) - return kDown; - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right) - || sf::Keyboard::isKeyPressed(sf::Keyboard::D)) - return kRight; - return kNone; - } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) + || sf::Keyboard::isKeyPressed(sf::Keyboard::A)) + return kLeft; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up) + || sf::Keyboard::isKeyPressed(sf::Keyboard::W)) + return kUp; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) + || sf::Keyboard::isKeyPressed(sf::Keyboard::S)) + return kDown; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right) + || sf::Keyboard::isKeyPressed(sf::Keyboard::D)) + return kRight; + return kNone; +} - bool PlayerOutput::IsOpen(void) - { - return gameWindow.isOpen(); - } +bool PlayerOutput::IsOpen(void) +{ + return gameWindow.isOpen(); +} - PlayerOutput::PlayerOutput(void) - { - float kWidth = 1025; - float kHeight = 725; - float kBoardWidth = kWidth / kGridSize; - float kBoardHeight = kHeight / kGridSize; - gameBoundaries = sf::Vector2f(kBoardWidth, kBoardHeight); - gameVideoSettings = sf::VideoMode(kWidth, kHeight); - drawObject.setSize(sf::Vector2f(kGridSize, kGridSize)); - return; - } +PlayerOutput::PlayerOutput(void) +{ + float kWidth = 1025; + float kHeight = 725; + float kBoardWidth = kWidth / kGridSize; + float kBoardHeight = kHeight / kGridSize; + gameBoundaries = sf::Vector2f(kBoardWidth, kBoardHeight); + gameVideoSettings = sf::VideoMode(kWidth, kHeight); + drawObject.setSize(sf::Vector2f(kGridSize, kGridSize)); + return; +} - void PlayerOutput::CheckContinue(bool isBotControlled) +void PlayerOutput::CheckContinue(bool isBotControlled) +{ + if (isBotControlled) { return; } + DisplayEndScreen(); + while (true) { - if (isBotControlled) { return; } - DisplayEndScreen(); - while (true) + gameWindow.pollEvent(event); + if ((event.type == sf::Event::Closed) + || (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))) { - gameWindow.pollEvent(event); - if ((event.type == sf::Event::Closed) - || (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))) - { - gameWindow.close(); - return; - } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Enter)) { return; } - sf::sleep(delay); + gameWindow.close(); + return; } - } - - void PlayerOutput::DisplayEndScreen(void) - { - gameWindow.clear(); - sf::Vector2f textPosition(gameBoundaries); - textPosition.x = textPosition.x / 2; - textPosition.y = textPosition.y / 2; - sf::Font font; - font.loadFromFile("Arial.ttf"); - sf::Text gameOverText("Game Over\nPress 'Enter' to play again", font); - gameOverText.setPosition(textPosition); - gameWindow.draw(gameOverText); - gameWindow.display(); - return; - } - - void PlayerOutput::DisplayScore(int score) { - sf::Vector2f textPosition(gameBoundaries); - textPosition.x = textPosition.x / 2; - textPosition.y = textPosition.y / 2; - sf::Font font; - font.loadFromFile("Arial.ttf"); - std::string text = "Score: " + std::to_string(score); - sf::Text ScoreText(text, font); - ScoreText.setPosition(textPosition); - gameWindow.draw(ScoreText); - - } - - void PlayerOutput::DisplayGameState(std::vector< std::vector >& gameBoard, int score) - { - CheckWindowEvents(); - if (delay == sf::milliseconds(0)) { return; } - char* letterOnBoard; - for (float y = 0; y < gameBoundaries.y; y++) - { - for (float x = 0; x < gameBoundaries.x; x++) - { - letterOnBoard = &gameBoard.at(y).at(x); - switch (*letterOnBoard) - { - case 'O': - DrawSnake(sf::Vector2f(x, y)); - break; - case 'X': - DrawFood(sf::Vector2f(x,y)); - break; - default: - DrawEmpty(sf::Vector2f(x,y)); - break; - } - } - } - DisplayScore(score); - gameWindow.display(); + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Enter)) { return; } sf::sleep(delay); - return; - } - - void PlayerOutput::StartGameWindow(void) - { - gameWindow.create(gameVideoSettings, "SnakePlusPlus"); - isWindowAlive = true; - return; - } - - void PlayerOutput::SetShowGame(bool isShowing) { - if (isShowing) { delay = sf::milliseconds(2); } - else { delay = sf::milliseconds(0); } - return; - } - - void PlayerOutput::CheckWindowEvents(void) - { - while (gameWindow.pollEvent(event)) - { - if ((event.type == sf::Event::Closed) - || (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))) - gameWindow.close(); - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Equal)) { - if (delay > sf::milliseconds(16)) { continue; } - delay += sf::milliseconds(1); - } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Hyphen)) { - if (delay == sf::milliseconds(0)) { continue; } - delay -= sf::milliseconds(1); - } - } - } - - void PlayerOutput::DrawEmpty(sf::Vector2f location) - { - location *= static_cast(kGridSize); - drawObject.setPosition(location); - drawObject.setFillColor(sf::Color::Black); - gameWindow.draw(drawObject); - return; - } - - void PlayerOutput::DrawFood(sf::Vector2f location) - { - location *= static_cast(kGridSize); - drawObject.setPosition(location); - drawObject.setFillColor(sf::Color::Red); - gameWindow.draw(drawObject); - return; - } - - void PlayerOutput::DrawSnake(sf::Vector2f location) - { - location *= static_cast(kGridSize); - drawObject.setPosition(location); - drawObject.setFillColor(sf::Color::Green); - gameWindow.draw(drawObject); - return; } } + +void PlayerOutput::DisplayEndScreen(void) +{ + gameWindow.clear(); + sf::Vector2f textPosition(gameBoundaries); + textPosition.x = textPosition.x / 2; + textPosition.y = textPosition.y / 2; + sf::Font font; + font.loadFromFile("Arial.ttf"); + sf::Text gameOverText("Game Over\nPress 'Enter' to play again", font); + gameOverText.setPosition(textPosition); + gameWindow.draw(gameOverText); + gameWindow.display(); + return; +} + +void PlayerOutput::DisplayScore(int score) { + sf::Vector2f textPosition(gameBoundaries); + textPosition.x = textPosition.x / 2; + textPosition.y = textPosition.y / 2; + sf::Font font; + font.loadFromFile("Arial.ttf"); + std::string text = "Score: " + std::to_string(score); + sf::Text ScoreText(text, font); + ScoreText.setPosition(textPosition); + gameWindow.draw(ScoreText); + +} + +void PlayerOutput::DisplayGameState(std::vector< std::vector >& gameBoard, int score) +{ + CheckWindowEvents(); + if (delay == sf::milliseconds(0)) { return; } + char* letterOnBoard; + for (float y = 0; y < gameBoundaries.y; y++) + { + for (float x = 0; x < gameBoundaries.x; x++) + { + letterOnBoard = &gameBoard.at(y).at(x); + switch (*letterOnBoard) + { + case 'O': + DrawSnake(sf::Vector2f(x, y)); + break; + case 'X': + DrawFood(sf::Vector2f(x,y)); + break; + default: + DrawEmpty(sf::Vector2f(x,y)); + break; + } + } + } + DisplayScore(score); + gameWindow.display(); + sf::sleep(delay); + return; +} + +void PlayerOutput::StartGameWindow(void) +{ + gameWindow.create(gameVideoSettings, "SnakePlusPlus"); + isWindowAlive = true; + return; +} + +void PlayerOutput::SetShowGame(bool isShowing) { + if (isShowing) { delay = sf::milliseconds(2); } + else { delay = sf::milliseconds(0); } + return; +} + +void PlayerOutput::CheckWindowEvents(void) +{ + while (gameWindow.pollEvent(event)) + { + if ((event.type == sf::Event::Closed) + || (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))) + gameWindow.close(); + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Equal)) { + if (delay > sf::milliseconds(16)) { continue; } + delay += sf::milliseconds(1); + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Hyphen)) { + if (delay == sf::milliseconds(0)) { continue; } + delay -= sf::milliseconds(1); + } + } +} + +void PlayerOutput::DrawEmpty(sf::Vector2f location) +{ + location *= static_cast(kGridSize); + drawObject.setPosition(location); + drawObject.setFillColor(sf::Color::Black); + gameWindow.draw(drawObject); + return; +} + +void PlayerOutput::DrawFood(sf::Vector2f location) +{ + location *= static_cast(kGridSize); + drawObject.setPosition(location); + drawObject.setFillColor(sf::Color::Red); + gameWindow.draw(drawObject); + return; +} + +void PlayerOutput::DrawSnake(sf::Vector2f location) +{ + location *= static_cast(kGridSize); + drawObject.setPosition(location); + drawObject.setFillColor(sf::Color::Green); + gameWindow.draw(drawObject); + return; +} diff --git a/src/playerinterface.hpp b/src/playerinterface.hpp index 5f5fb3a..3fad189 100755 --- a/src/playerinterface.hpp +++ b/src/playerinterface.hpp @@ -6,34 +6,31 @@ const int kGridSize = 25; -namespace snakeplusplus -{ - PlayerDirection GetPlayerInput(void); +PlayerDirection GetPlayerInput(void); - class PlayerOutput - { - public: - sf::Vector2f gameBoundaries; - PlayerOutput(void); - bool IsOpen(void); - void CheckContinue(bool isBotControlled); - void DisplayGameState(std::vector< std::vector >& gameBoard, int score); - void DisplayScore(int score); - void StartGameWindow(void); - void SetShowGame(bool isShowing); - private: - void CheckWindowEvents(void); - void DisplayEndScreen(void); - void DrawEmpty(sf::Vector2f location); - void DrawFood(sf::Vector2f location); - void DrawSnake(sf::Vector2f location); - sf::RenderWindow gameWindow; - sf::VideoMode gameVideoSettings; - sf::RectangleShape drawObject; - sf::Event event; - bool isWindowAlive; - sf::Time delay = sf::milliseconds(1); - }; -} +class PlayerOutput +{ +public: + sf::Vector2f gameBoundaries; + PlayerOutput(void); + bool IsOpen(void); + void CheckContinue(bool isBotControlled); + void DisplayGameState(std::vector< std::vector >& gameBoard, int score); + void DisplayScore(int score); + void StartGameWindow(void); + void SetShowGame(bool isShowing); +private: + void CheckWindowEvents(void); + void DisplayEndScreen(void); + void DrawEmpty(sf::Vector2f location); + void DrawFood(sf::Vector2f location); + void DrawSnake(sf::Vector2f location); + sf::RenderWindow gameWindow; + sf::VideoMode gameVideoSettings; + sf::RectangleShape drawObject; + sf::Event event; + bool isWindowAlive; + sf::Time delay = sf::milliseconds(1); +}; #endif diff --git a/src/snake.cpp b/src/snake.cpp index c9602a5..65357a7 100755 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -4,28 +4,25 @@ #include "common.hpp" #include "snake.hpp" -namespace snakeplusplus +void Snake::Pop(void) { - void Snake::Pop(void) - { - *(body.front()) = ' '; - body.pop(); - return; - } - - void Snake::Reset(void) - { - while (!body.empty()) Pop(); - speed.x = 0; - speed.y = 0; - return; - } - - // Returns a new food object for the snakeFood - void Food::GenerateNewFood(sf::Vector2f boundaries) - { - location.x = GenerateRandomNumber(boundaries.x); - location.y = GenerateRandomNumber(boundaries.y); - return; - } + *(body.front()) = ' '; + body.pop(); + return; +} + +void Snake::Reset(void) +{ + while (!body.empty()) Pop(); + speed.x = 0; + speed.y = 0; + return; +} + +// Returns a new food object for the snakeFood +void Food::GenerateNewFood(sf::Vector2f boundaries) +{ + location.x = GenerateRandomNumber(boundaries.x); + location.y = GenerateRandomNumber(boundaries.y); + return; } diff --git a/src/snake.hpp b/src/snake.hpp index 80cec53..a2388e4 100755 --- a/src/snake.hpp +++ b/src/snake.hpp @@ -5,25 +5,22 @@ #include #include -namespace snakeplusplus +struct Snake { - struct Snake - { - public: - sf::Vector2f headLocation; - sf::Vector2f speed; - std::queue body; - void Pop(void); - void Reset(void); - }; +public: + sf::Vector2f headLocation; + sf::Vector2f speed; + std::queue body; + void Pop(void); + void Reset(void); +}; - struct Food - { - public: - sf::Vector2f location; - char* food; - void GenerateNewFood(sf::Vector2f boundaries); - }; -} +struct Food +{ +public: + sf::Vector2f location; + char* food; + void GenerateNewFood(sf::Vector2f boundaries); +}; #endif