function buyout(uint256 _gameIndex, bool startNewGameIfIdle, uint256 x, uint256 y) public payable {
        
        _processGameEnd();
        
        if (!gameStates[gameIndex].gameStarted) {
            
            require(!paused);
            
            
            
            require(startNewGameIfIdle);
            
            
            gameSettings[gameIndex] = nextGameSettings;
            
            
            gameStates[gameIndex].gameStarted = true;
            
            
            gameStates[gameIndex].gameStartTimestamp = block.timestamp;
            
            
            Start(gameIndex, msg.sender, block.timestamp, gameStates[gameIndex].prizePool, gameSettings[gameIndex].rows, gameSettings[gameIndex].cols, gameSettings[gameIndex].activityTimer, gameSettings[gameIndex].unclaimedTilePrice, gameSettings[gameIndex].buyoutReferralBonusPercentage, gameSettings[gameIndex].buyoutPrizePoolPercentage, gameSettings[gameIndex].buyoutDividendPercentage, gameSettings[gameIndex].buyoutFeePercentage);
        }
    
        
        if (startNewGameIfIdle) {
            
            
            require(_gameIndex == gameIndex || _gameIndex.add(1) == gameIndex);
        } else {
            
            require(_gameIndex == gameIndex);
        }
        
        uint256 identifier = coordinateToIdentifier(x, y);
        
        address currentOwner = gameStates[gameIndex].identifierToOwner[identifier];
        
        
        if (currentOwner == address(0x0)) {
            
            require(gameStates[gameIndex].gameStartTimestamp.add(gameSettings[gameIndex].activityTimer) >= block.timestamp);
        } else {
            
            require(gameStates[gameIndex].identifierToBuyoutTimestamp[identifier].add(gameSettings[gameIndex].activityTimer) >= block.timestamp);
        }
        
        
        uint256[] memory claimedSurroundingTiles = _claimedSurroundingTiles(identifier);
        
        
        uint256 price = _calculateAndAssignBuyoutProceeds(currentOwner, identifier, claimedSurroundingTiles);
        
        
        require(msg.value >= price);
        
        
        _transfer(currentOwner, msg.sender, identifier);
        
        
        gameStates[gameIndex].lastFlippedTile = identifier;
        
        
        gameStates[gameIndex].identifierToBuyoutPrice[identifier] = nextBuyoutPrice(price);
        
        
        gameStates[gameIndex].identifierToBuyoutTimestamp[identifier] = block.timestamp;
        
        
        Buyout(gameIndex, msg.sender, identifier, x, y, block.timestamp, block.timestamp + gameSettings[gameIndex].activityTimer, gameStates[gameIndex].identifierToBuyoutPrice[identifier], gameStates[gameIndex].prizePool);
        
        
        
        
        uint256 excess = msg.value - price;
        
        if (excess > 0) {
            
            
            msg.sender.transfer(excess);
        }
    }