game force closes with the error message Exception thrown at 0x0000000000410AB9 in app.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x0000000000613FD8).
-
narasimhaLikes 0Problem Description
edit: so, i checked my minimax algorithm seperately and realised it’s my’s aglorithm that is crashing, but still cant find where it is crashing
#include <algorithm> #include <iostream> #define X_piece_number 8 #define O_piece_number 0 #define Empty_piece_number -1 #define PLAYER_PIECE X_piece_number #define AI_piece O_piece_number namespace GameEngine{ class thinker{ public: thinker(int playerPiece); void checkForOptimalSolutionToPlace(int(*gridArray)[3][3]); int minMax(int board[3][3], int depth, bool isMax); int evaluate(int b[3][3]); bool isMovesLeft(int board[3][3]); private: int maxPlayer; int minPlayer; }; thinker::thinker(int playerPiece){ if (O_piece_number == playerPiece) { this->maxPlayer = X_piece_number; this->minPlayer = playerPiece; } else { this->maxPlayer = O_piece_number; this->minPlayer = playerPiece; } } void thinker::checkForOptimalSolutionToPlace(int(*gridArray)[3][3] ){ int board[3][3]; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ board[i][j] = (*gridArray)[i][j]; } } int bestVal = -1000; int row = 0; int col = 0; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(board[i][j] == Empty_piece_number){ board[i][j] = maxPlayer; int moveVal = minMax(board,0,false); board[i][j] = Empty_piece_number; if(moveVal > bestVal){ row = i; col = j; bestVal = moveVal; } } } } //here now best move is row,col (*gridArray)[row][col] = AI_piece; } int thinker::minMax(int board[3][3], int depth, bool isMax){ int score = evaluate(board); if(score == 10){ return score; } if(score == -10){ return score; } if(isMovesLeft(board) == false){ return 0; } if(isMax){ int best = -1000; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(board[i][j] == Empty_piece_number){ board[i][j] = maxPlayer; best = std::max(best,minMax(board,depth+1,!isMax)); } board[i][j] = Empty_piece_number; } } return best; } else{ int best = 1000; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(board[i][j] == Empty_piece_number){ board[i][j] = minPlayer; best = std::min(best, minMax(board, depth+1, !isMax)); board[i][j] = Empty_piece_number; } } } return best; } } int thinker::evaluate(int b[3][3]){ for(int row=0;row<3;row++) { if((b[row][0] == b[row][1]) && (b[row][1] == b[row][2])) { if(b[row][0] == maxPlayer) { return +10; }else if(b[row][0] == minPlayer) { return -10; } } } for(int col = 0; col<3 ; col++){ if(b[0][col] == b[1][col] && b[1][col] == b[2][col]){ if (b[0][col] == maxPlayer){ return +10; }else if(b[0][col] == minPlayer){ return -10; } } } if(b[0][0] == b[1][1] && b[1][1] == b[2][2]){ if (b[0][0] == maxPlayer) { return +10; } else if (b[0][0] == minPlayer){ { return -10; } } } if (b[0][2] == b[1][1] && b[1][1] == b[2][0]) { if (b[0][2] == maxPlayer){ return +10; } else if (b[0][2] == minPlayer){ return -10; } } return 0; } bool thinker::isMovesLeft(int board[3][3]){ for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(board[i][j] == Empty_piece_number){ return true; } } } return false; } } int main(){ GameEngine::thinker ai(PLAYER_PIECE); int ar[3][3] = { { 8,0,-1 } , { 8,0,-1 } , { -1,-1,-1 } } ; ai.checkForOptimalSolutionToPlace(&ar); for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ std::cout<<ar[i][j]<<" "; } std::cout<<std::endl<<"completed"; } }
at this point, my question is not even related t sfml/youtube video. but yet can someone help
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
i followed the tic-tac-toe tutorials and completed it(it worked perfectly), then I added a new state called unbeatable and added the minimax algorithm for AI, (the reference for the algo was taken from here https://www.geeksforgeeks.org/minimax-algorithm-in-game-theory-set-2-evaluation-function/ )
source code
unbeatable.hpp#pragma once #include #include "State.hpp" #include "Game.hpp" #include "unbeatableAi.hpp" namespace GameEngine { class unbeatable : public State { public: unbeatable(GameDataRef data); void Init(); void HandleInput(); void Update(float dt); void Draw(float dt); void InitGridPieces(); void CheckAndPlacePiece(); void CheckHasPlayerWon(int turn); void Check3PiecesForMatch(int x1, int y1, int x2, int y2, int x3, int y3, int pieceToCheck); private: GameDataRef _data; sf::Sprite _pauseButton; sf::Sprite _gridSprite; sf::Sprite _gridPieces[3][3]; sf::Sprite _homeButton; sf::Sprite _retryButton; int _gridArray[3][3]; int turn; int gameState; int temp; thinker *ai; sf::Clock _clock; sf::Text turnText; }; }
unbeatable.cpp
#include #include #include "unbeatable.hpp" #include "MainMenuState.hpp" #include "DEFINITIONS.hpp" #include "PauseState.hpp" #include "unbeatableAi.hpp" namespace GameEngine { unbeatable::unbeatable(GameDataRef data) : _data(data) { } void unbeatable::Init() { gameState = STATE_PLAYING; turn = PLAYER_PIECE; this->_retryButton.setTexture(this->_data->assets.GetTexture("Retry Button")); this->_homeButton.setTexture(this->_data->assets.GetTexture("Home Button")); this->_retryButton.setPosition((this->_data->window.getSize().x / 2) - (this->_retryButton.getLocalBounds().width / 2), (this->_data->window.getSize().y / 3) - (this->_retryButton.getLocalBounds().height / 2)); this->_homeButton.setPosition((this->_data->window.getSize().x / 2) - (this->_homeButton.getLocalBounds().width / 2), (this->_data->window.getSize().y / 3 * 2) - (this->_homeButton.getLocalBounds().height / 2)); this->turnText.setFont(this->_data->assets.GetFont("Felt")); this->turnText.setScale(2.5,2.5); this->ai = new thinker(turn, this->_data); _pauseButton.setTexture(this->_data->assets.GetTexture("Pause Button")); _gridSprite.setTexture(this->_data->assets.GetTexture("Grid Sprite")); _pauseButton.setPosition(this->_data->window.getSize().x - _pauseButton.getLocalBounds().width, _pauseButton.getPosition().y); _gridSprite.setPosition((SCREEN_WIDTH / 2) - (_gridSprite.getGlobalBounds().width / 2), (SCREEN_HEIGHT / 2) - (_gridSprite.getGlobalBounds().height / 2)); InitGridPieces(); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { _gridArray[x][y] = Empty_piece_number; } } } void unbeatable::HandleInput() { sf::Event event; while (this->_data->window.pollEvent(event)) { if (sf::Event::Closed == event.type) { this->_data->window.close(); } if(gameState == STATE_PLAYING) { if (this->_data->input.IsSpriteClicked(this->_pauseButton, sf::Mouse::Left, this->_data->window)) { // Switch To Game State this->_data->machine.AddState(StateRef(new PauseState(_data)), false); } else if (this->_data->input.IsSpriteClicked(this->_gridSprite, sf::Mouse::Left, this->_data->window)) { if (STATE_PLAYING == gameState) { this->CheckAndPlacePiece(); } } }else if(gameState != STATE_PLAYING && gameState != state_delay){ if(this->_data->input.IsSpriteClicked(this->_homeButton,sf::Mouse::Left,this->_data->window)){ this->_data->machine.AddState(StateRef(new MainMenuState(_data)),true); } else if(this->_data->input.IsSpriteClicked(this->_retryButton,sf::Mouse::Left,this->_data->window)){ this->_data->machine.AddState(StateRef(new unbeatable(_data)),true); } } } } void unbeatable::Update(float dt) { if(gameState == state_delay){ if(_clock.getElapsedTime().asSeconds() > TIME_BEFORE_SHOWING_GAME_OVER){ gameState = temp; } } if(gameState != state_delay && gameState != STATE_PLAYING){ this->turnText.setPosition(225, 90); if(gameState == State_won){ this->turnText.setString("YOU WON"); this->turnText.setPosition(175,90); } else if(gameState == State_lose ){ this->turnText.setString("YOU LOST"); this->turnText.setPosition(175,90); }else{ this->turnText.setString("DRAW"); } } } void unbeatable::Draw(float dt) { this->_data->window.clear(sf::Color(250,181,127)); if(gameState != STATE_PLAYING && gameState != state_delay){ this->_data->window.draw(this->_retryButton); this->_data->window.draw(this->_homeButton); this->_data->window.draw(this->turnText); } else if(gameState == STATE_PLAYING || gameState == state_delay){ this->_data->window.draw( this->_pauseButton ); this->_data->window.draw( this->_gridSprite ); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { this->_data->window.draw(this->_gridPieces[x][y]); } } } this->_data->window.display(); } void unbeatable::InitGridPieces() { sf::Vector2u tempSpriteSize = this->_data->assets.GetTexture("X Piece").getSize(); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { _gridPieces[x][y].setTexture(this->_data->assets.GetTexture("X Piece")); _gridPieces[x][y].setPosition(_gridSprite.getPosition().x + (tempSpriteSize.x * x) - 7, _gridSprite.getPosition().y + (tempSpriteSize.y * y) - 7); _gridPieces[x][y].setColor(sf::Color(255, 255, 255, 0)); } } } void unbeatable::CheckAndPlacePiece() { sf::Vector2i touchPoint = this->_data->input.GetMousePosition(this->_data->window); sf::FloatRect gridSize = _gridSprite.getGlobalBounds(); sf::Vector2f gapOutsideOfGrid = sf::Vector2f((SCREEN_WIDTH - gridSize.width) / 2, (SCREEN_HEIGHT - gridSize.height) / 2); sf::Vector2f gridLocalTouchPos = sf::Vector2f(touchPoint.x - gapOutsideOfGrid.x, touchPoint.y - gapOutsideOfGrid.y); //std::cout << gridLocalTouchPos.x << ", " << gridLocalTouchPos.y << std::endl; sf::Vector2f gridSectionSize = sf::Vector2f(gridSize.width / 3, gridSize.height / 3); int column, row; // Check which column the user has clicked if (gridLocalTouchPos.x < gridSectionSize.x) // First Column { column = 1; } else if (gridLocalTouchPos.x < gridSectionSize.x * 2) // Second Column { column = 2; } else if (gridLocalTouchPos.x < gridSize.width) // Third Column { column = 3; } // Check which row the user has clicked if (gridLocalTouchPos.y < gridSectionSize.y) // First Row { row = 1; } else if (gridLocalTouchPos.y < gridSectionSize.y * 2) // Second Row { row = 2; } else if (gridLocalTouchPos.y < gridSize.height) // Third Row { row = 3; } if (_gridArray[column - 1][row - 1] == Empty_piece_number) { _gridArray[column - 1][row - 1] = turn; if (PLAYER_PIECE == turn) { _gridPieces[column - 1][row - 1].setTexture(this->_data->assets.GetTexture("X Piece")); this->CheckHasPlayerWon(turn); } _gridPieces[column - 1][row - 1].setColor(sf::Color(255, 255, 255, 255)); } } void unbeatable::CheckHasPlayerWon(int player) { Check3PiecesForMatch(0, 0, 1, 0, 2, 0, player); Check3PiecesForMatch(0, 1, 1, 1, 2, 1, player); Check3PiecesForMatch(0, 2, 1, 2, 2, 2, player); Check3PiecesForMatch(0, 0, 0, 1, 0, 2, player); Check3PiecesForMatch(1, 0, 1, 1, 1, 2, player); Check3PiecesForMatch(2, 0, 2, 1, 2, 2, player); Check3PiecesForMatch(0, 0, 1, 1, 2, 2, player); Check3PiecesForMatch(0, 2, 1, 1, 2, 0, player); if (State_won != gameState) { gameState = State_AI_playing; int temp[2]; ai->checkForOptimalSolutionToPlace(&_gridArray, _gridPieces, &gameState); Check3PiecesForMatch(0, 0, 1, 0, 2, 0, AI_piece); Check3PiecesForMatch(0, 1, 1, 1, 2, 1, AI_piece); Check3PiecesForMatch(0, 2, 1, 2, 2, 2, AI_piece); Check3PiecesForMatch(0, 0, 0, 1, 0, 2, AI_piece); Check3PiecesForMatch(1, 0, 1, 1, 1, 2, AI_piece); Check3PiecesForMatch(2, 0, 2, 1, 2, 2, AI_piece); Check3PiecesForMatch(0, 0, 1, 1, 2, 2, AI_piece); Check3PiecesForMatch(0, 2, 1, 1, 2, 0, AI_piece); } int emptyNum = 9; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { if (Empty_piece_number != _gridArray[x][y]) { emptyNum--; } } } // check if the game is a draw if (0 == emptyNum && (State_won != gameState) && (State_lose != gameState)) { gameState = state_delay; temp=State_Draw; } // check if the game is over if (gameState == state_delay) { // show game over this->_clock.restart( ); } } void unbeatable::Check3PiecesForMatch(int x1, int y1, int x2, int y2, int x3, int y3, int pieceToCheck) { if (pieceToCheck == _gridArray[x1][y1] && pieceToCheck == _gridArray[x2][y2] && pieceToCheck == _gridArray[x3][y3]) { std::string winningPieceStr; if (O_piece_number == pieceToCheck) { winningPieceStr = "O Winning Piece"; } else { winningPieceStr = "X Winning Piece"; } _gridPieces[x1][y1].setTexture(this->_data->assets.GetTexture(winningPieceStr)); _gridPieces[x2][y2].setTexture(this->_data->assets.GetTexture(winningPieceStr)); _gridPieces[x3][y3].setTexture(this->_data->assets.GetTexture(winningPieceStr)); if(PLAYER_PIECE == pieceToCheck){ gameState = state_delay; this->temp = State_won; }else{ gameState = state_delay; this->temp = State_lose; } } } }
unbeatableAi.hpp
#pragma once #include #include #include "Game.hpp" namespace GameEngine{ class thinker{ public: thinker(int playerPiece,GameDataRef data); void checkForOptimalSolutionToPlace(int(*gridArray)[3][3], sf::Sprite gridPieces[3][3] , int *gameState); int minMax(int board[3][3], int depth, bool isMax); int evaluate(int board[3][3]); bool isMovesLeft(int board[3][3]); private: GameDataRef _data; int maxPlayer; int minPlayer; }; }
unbeatableAi.cpp
#include "unbeatableAi.hpp" #include "DEFINITIONS.hpp" #include #include namespace GameEngine{ thinker::thinker(int playerPiece,GameDataRef data){ std::cout<<"till here 2"; this->_data = data; if (O_piece_number == playerPiece) { this->maxPlayer = X_piece_number; this->minPlayer = playerPiece; } else { this->maxPlayer = O_piece_number; this->minPlayer = playerPiece; } } void thinker::checkForOptimalSolutionToPlace(int(*gridArray)[3][3], sf::Sprite gridPieces[3][3] , int *gameState){ int board[3][3]; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ board[i][j] = (*gridArray)[i][j]; } } int bestVal = -1000; int row = 0; int col = 0; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(board[i][j] == Empty_piece_number){ board[i][j] = maxPlayer; int moveVal = minMax(board,0,false); board[i][j] = Empty_piece_number; if(moveVal > bestVal){ row = i; col = j; bestVal = moveVal; } } } } //here now best move is row,col (*gridArray)[row][col] = AI_piece; gridPieces[row][col].setTexture(this->_data->assets.GetTexture("O Piece")); gridPieces[row][col].setColor(sf::Color(255, 255, 255, 255)); *gameState = STATE_PLAYING; } int thinker::minMax(int board[3][3], int depth, bool isMax){ int score = evaluate(board); if(score == 10){ return score; } if(score == -10){ return score; } if(isMovesLeft(board) == false){ return 0; } if(isMax){ int best = -1000; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(board[i][j] == Empty_piece_number){ board[i][j] = maxPlayer; best = std::max(best,minMax(board,depth+1,!isMax)); } board[i][j] = Empty_piece_number; } } return best; } else{ int best = 1000; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(board[i][j] == Empty_piece_number){ board[i][j] = minPlayer; best = std::min(best, minMax(board, depth+1, !isMax)); board[i][j] = Empty_piece_number; } } } return best; } } int thinker::evaluate(int b[3][3]){ for(int row=0;row<3;row++) { if((b[row][0] == b[row][1]) && (b[row][1] == b[row][2])) { if(b[row][0] == maxPlayer) { return +10; }else if(b[row][0] == minPlayer) { return -10; } } } for(int col = 0; col<3 ; col++){ if(b[0][col] == b[1][col] && b[1][col] == b[2][col]){ if (b[0][col] == maxPlayer){ return +10; }else if(b[0][col] == minPlayer){ return -10; } } } if(b[0][0] == b[1][1] && b[1][1] == b[2][2]){ if (b[0][0] == maxPlayer) { return +10; } else if (b[0][0] == minPlayer){ { return -10; } } } if (b[0][2] == b[1][1] && b[1][1] == b[2][0]) { if (b[0][2] == maxPlayer){ return +10; } else if (b[0][2] == minPlayer){ return -10; } } return 0; } bool thinker::isMovesLeft(int board[3][3]){ for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(board[i][j] == Empty_piece_number){ return true; } } } return false; } }
the game compiles with no errors,
when i run the exe file and go to unbeatable state and click on the grid the app force closescan someone point me where i did wrong
link for the full source code(github)
https://github.com/ILIVE0146/SEM.git
task.json
{ "version": "2.0.0", "tasks": [ { "type": "shell", "label": "release", "command": "E:\\mingw\\mingw64\\bin\\g++.exe", "args": [ "${workspaceFolder}\\*.cpp", "-o", "${workspaceFolder}\\build\\app.exe", "-DSFML_STATIC", "-I", "D:\\sfml\\build\\include", "-L", "D:\\sfml\\static\\lib", "-lsfml-graphics-s", "-lsfml-window-s", "-lsfml-audio-s", "-lsfml-system-s", "-lsfml-network-s", "-lwinmm", "-lopengl32", "-lopenal32", "-lflac", "-lvorbisenc", "-lvorbisfile", "-lvorbis", "-logg", "-lws2_32", "-lgdi32", "-lfreetype", "-static", "-static-libgcc", "-static-libstdc++" ], "options": { "cwd": "${workspaceFolder}\\build" }, "problemMatcher": [ "$gcc" ], "group": { "kind": "build", "isDefault": true } } ] }
-
Sonar Systems adminLikes 0
For tic tac toe?
Login to reply