Merge pull request 'add misc features to game' (#5) from iterative into master

Reviewed-on: #5
This commit is contained in:
Trianta 2024-08-02 19:36:14 -05:00
commit eefc2bf60b
7 changed files with 88 additions and 31 deletions

16
.gitignore vendored
View File

@ -33,7 +33,19 @@
*.json
*.ps1
# ---> CMake
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
build
# Extras
.vs*
build
bin

View File

@ -2,6 +2,7 @@
#include "common.hpp"
#include <array>
#include <cstdlib>
#include <iostream>
#include <queue>
#include <stdexcept>
#include <SFML/System/Vector2.hpp>
@ -42,6 +43,15 @@ namespace snakeplusplus
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<char> >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries, const int snakeSize)

View File

@ -15,8 +15,9 @@ namespace snakeplusplus
void GetNewPath(const std::vector< std::vector<char> >& 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 = 1.000;
double probabilityBFS = 0.500;
std::stack<sf::Vector2f> botPathUnsanitized;
void BFS(const std::vector< std::vector<char> >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries);
void DFS(const std::vector< std::vector<char> >& gameBoard, const sf::Vector2f& source, const sf::Vector2f& boundaries);

View File

@ -1,4 +1,5 @@
// GameState.cpp
#include <iostream>
#include <stdexcept>
#include <SFML/Graphics.hpp>
#include "botinterface.hpp"
@ -24,16 +25,30 @@ namespace snakeplusplus
void GameEngine::Reset()
{
graphics.CheckContinue(isBotControlled);
AddIteration();
player.Reset();
if (isBotControlled) {
while (!bot.path.empty()) { bot.path.pop(); }
}
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;
@ -44,7 +59,7 @@ namespace snakeplusplus
PlaceNewSnakePart(MovePlayer());
RegenerateFood();
currentScore = player.body.size() * 100;
bot.UpdateProbability(player.body.size());
//bot.UpdateProbability(player.body.size());
graphics.DisplayGameState(gameBoard, currentScore);
}
return;
@ -52,26 +67,22 @@ namespace snakeplusplus
sf::Vector2f GameEngine::MovePlayer(void)
{
sf::Vector2f newHeadPosition;
newHeadPosition.x = player.headLocation.x + player.speed.x;
newHeadPosition.y = player.headLocation.y + player.speed.y;
return newHeadPosition;
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)
{
void GameEngine::PlaceNewSnakePart(sf::Vector2f location) {
if (!player.speed.x && !player.speed.y) { return; }
try
{
char* locationState;
locationState = &gameBoard.at(location.y).at(location.x);
if (*locationState == 'O' && (player.body.size() > 1))
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;
@ -83,23 +94,20 @@ namespace snakeplusplus
return;
}
// Generates new food until not colliding with player
void GameEngine::RegenerateFood(void)
void GameEngine::RegenerateFood()
{
sf::Vector2f newLocation = playerFood.location;
bool isUpdated = false;
while (gameBoard.at(newLocation.y).at(newLocation.x) == 'O')
{
isUpdated = true;
// 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());
newLocation = playerFood.location;
}
if (isUpdated) {
gameBoard.at(newLocation.y).at(newLocation.x) = 'X';
}
return;
// 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();
@ -155,4 +163,9 @@ namespace snakeplusplus
}
return;
}
void GameEngine::UpdateAverage() {
totalLength += player.body.size();
amountPlayed += 1;
average = (double)totalLength / amountPlayed;
}
}

View File

@ -17,6 +17,7 @@ namespace snakeplusplus
GameEngine();
void Start(void);
void Reset(void);
void AddIteration(void);
sf::Vector2f GetGameBoundaries(void);
private:
std::vector< std::vector<char> > gameBoard;
@ -33,6 +34,10 @@ namespace snakeplusplus
void RegenerateFood(void);
void PrepareGameBoard(void);
void UpdatePlayerSpeed();
void UpdateAverage();
int totalLength = 0;
int amountPlayed = 0;
double average = 0;
};
}

View File

@ -87,6 +87,7 @@ namespace snakeplusplus
void PlayerOutput::DisplayGameState(std::vector< std::vector<char> >& gameBoard, int score)
{
CheckWindowEvents();
if (delay == sf::milliseconds(0)) { return; }
char* letterOnBoard;
for (float y = 0; y < gameBoundaries.y; y++)
{
@ -120,6 +121,12 @@ namespace snakeplusplus
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))
@ -127,6 +134,14 @@ namespace snakeplusplus
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);
}
}
}

View File

@ -20,6 +20,7 @@ namespace snakeplusplus
void DisplayGameState(std::vector< std::vector<char> >& gameBoard, int score);
void DisplayScore(int score);
void StartGameWindow(void);
void SetShowGame(bool isShowing);
private:
void CheckWindowEvents(void);
void DisplayEndScreen(void);
@ -31,7 +32,7 @@ namespace snakeplusplus
sf::RectangleShape drawObject;
sf::Event event;
bool isWindowAlive;
sf::Time delay = sf::milliseconds(10);
sf::Time delay = sf::milliseconds(1);
};
}