// GameState.cpp #include #include #include #include "botinterface.hpp" #include "common.hpp" #include "playerinterface.hpp" #include "gamestate.hpp" GameEngine::GameEngine() { InitializeGenerator(); return; } void GameEngine::Start() { PrepareGameBoard(); if (!state.m_bNoDisplay) graphics.StartGameWindow(); Loop(); return; } void GameEngine::Reset() { AddIteration(); player.Reset(); if (state.m_bIsBotControlled) { while (!bot.path.empty()) { bot.path.pop(); } } PrepareGameBoard(); 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(state.m_bIsBotControlled); 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() || state.m_bNoDisplay) { if (state.m_bIsGameOver) { Reset(); } UpdatePlayerSpeed(); PlaceNewSnakePart(MovePlayer()); RegenerateFood(); currentScore = player.body.size() * 100; //bot.UpdateProbability(player.body.size()); if (!state.m_bNoDisplay) 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 { 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->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) { state.m_bIsGameOver = 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[playerFood.location.y][playerFood.location.x].m_bSnake) { playerFood.GenerateNewFood(GetGameBoundaries()); } // Update the game board with the new food location gameBoard[playerFood.location.y][playerFood.location.x].m_bFood = 1; } 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); { GameSpace* locationState = &gameBoard[player.headLocation.y][player.headLocation.x]; player.body.push(locationState); locationState->m_bSnake = true; } // Food setup playerFood.GenerateNewFood(boardDimensions); gameBoard[playerFood.location.y][playerFood.location.x].m_bFood = true; return; } void GameEngine::UpdatePlayerSpeed(void) { PlayerDirection controller; if (state.m_bIsBotControlled) { 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; }