function placeBet(bytes32 betTypes, bytes32 first16, bytes32 second16) external payable {
        
        if (shouldGateGuard == true) {
            emit GameError(msg.sender, "Entrance not allowed!");
            revert();
        }

        
        uint betAmount = rouletteRules.getTotalBetAmount(first16, second16) * BET_UNIT;
        
        if (betAmount == 0 || msg.value != betAmount || msg.value > MAX_BET) {
            emit GameError(msg.sender, "Wrong bet amount!");
            revert();
        }

        
        
        uint targetBlock = block.number + BLOCK_TARGET_DELAY;

        
        uint historyLength = gameHistory.length;
        if (historyLength > 0) {
            uint counter;
            for (uint i = historyLength - 1; i >= 0; i--) {
                if (gameHistory[i].targetBlock == targetBlock) {
                    counter++;
                    if (counter > MAX_GAME_PER_BLOCK) {
                        emit GameError(msg.sender, "Reached max game per block!");
                        revert();
                    }
                } else break;
            }
        }

        
        
        Game memory newGame = Game(uint8(GameStatus.PENDING), 100, msg.sender, targetBlock, betTypes, first16, second16);
        uint gameId = gameHistory.push(newGame) - 1;
        emit GameStarted(msg.sender, gameId, targetBlock);
    }