game force closes with the error message Exception thrown at 0x0000000000410AB9 in app.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x0000000000613FD8).

  • narasimha
    Likes 0

    Problem 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 closes

    can 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 admin
    Likes 0

    For tic tac toe?

Login to reply