/// <summary>
        /// Find Block Pair
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Tuple FindBlockPair(int id)
        {
            Tuple tuple = new Tuple(this);

            for (int j = 1; j < Model.TOT_BLOCK_CNT_Y - 1; ++j)
            {
                for (int i = 1; i < Model.TOT_BLOCK_CNT_X - 1; ++i)
                {
                    if (_map[i][j].GetImageId() == id)
                    {
                        tuple.Select(new Position(i, j));
                        if (tuple.IsTuple())
                        {
                            return(tuple);
                        }
                    }
                }
            }
            return(null);
        }
        /// <summary>
        /// Mouse Left Click Handler For Game Round
        /// </summary>
        /// <param name="xMouse"></param>
        /// <param name="yMouse"></param>
        public void GameRoundLeftClickHandler(int xMouse, int yMouse)
        {
            // Check the game state
            if (_gameState != GameState.PLAYING)
            {
                return;
            }

            // Select a block
            int      x             = xMouse / (Model.BLOCK_SIZE_X + Model.BLOCK_MARGIN);
            int      y             = yMouse / (Model.BLOCK_SIZE_Y + Model.BLOCK_MARGIN);
            Position blockPosition = new Position(x, y);

            // Check selected block is valid
            if (_grid.GetBlock(blockPosition).IsNull())
            {
                return;
            }
            // Check tuple is selectable
            if (!_tuple.Select(blockPosition))
            {
                return;
            }

            // Check is connected AND required to merge
            if (_tuple.IsTuple())
            {
                Position startPos = _tuple.GetFirst();
                Position endPos   = _tuple.GetSecond();
                _tuple.Clear(); // Clear tuple

                if (_isConnected(startPos, endPos, _grid))
                {
                    // Connected, need to be merged
                    _grid.Merge(startPos, endPos);

                    _score.Merged();
                    _sePlayer.Merged(); // Merged SE

                    // Goto check game end
                    if (_gameEnd())
                    {
                        return;
                    }

                    // Check is there any block can be merged
                    AcquireResourceMutex(MutexType.TIP);
                    _mergableTuple       = new Tip();
                    _mergableTuple.Tuple = _findMergableBlockPair();
                    while (_mergableTuple.Tuple == null)
                    {
                        _grid.Randomize();
                        _sePlayer.Refresh(); // Refresh SE
                        _mergableTuple.Tuple = _findMergableBlockPair();
                    }
                    ReleaseResourceMutex(MutexType.TIP);
                }
                else
                {
                    _score.ComboInterrupted();
                    _sePlayer.Failed(); // Failed SE
                }
            }
            else
            {
                _sePlayer.Clicked(); // Click SE
            }
        }
        /// <summary>
        /// Get binary tuple of start and end positions given current position by expanding vertically
        /// </summary>
        /// <param name="curPos">Current position</param>
        /// <param name="grid">Grid</param>
        /// <param name="curType">Current block type</param>
        /// <returns></returns>
        private Tuple _expandVertical(Position curPos, Grid grid, int curType)
        {
            int startPos, endPos;
            int i, j;

            i = curPos.X;
            Tuple tuple = new Tuple(grid);

            // From current to upmost
            startPos = curPos.Y;
            j        = startPos - 1;
            while (j >= 0)
            {
                Block curExploredBlock = grid.GetBlock(new Position(i, j));
                if (curExploredBlock.IsNull())
                {
                    // Null block can be passed
                    startPos = j;
                }
                else if (curExploredBlock.GetImageId() == curType)
                {
                    // Block with same type can be passed
                    startPos = j;
                }
                else
                {
                    // Cannot passed, terminated
                    break;
                }
                --j;
            }

            // From current to downmost
            endPos = curPos.Y;
            j      = endPos + 1;
            while (j < Model.TOT_BLOCK_CNT_Y)
            {
                Block curExploredBlock = grid.GetBlock(new Position(i, j));
                if (curExploredBlock.IsNull())
                {
                    // Null block can be passed
                    endPos = j;
                }
                else if (curExploredBlock.GetImageId() == curType)
                {
                    // Block with same type can be passed
                    endPos = j;
                }
                else
                {
                    // Cannot passed, terminated
                    break;
                }
                ++j;
            }

            bool ret = true;

            ret = ret && tuple.Select(new Position(i, startPos));
            ret = ret && tuple.Select(new Position(i, endPos));
            if (!ret)
            {
                throw new Exception();
            }
            return(tuple);
        }
        /// <summary>
        /// Check is there a path with 2 turning points
        /// </summary>
        /// <param name="hStartTuple"></param>
        /// <param name="vStartTuple"></param>
        /// <param name="hEndTuple"></param>
        /// <param name="vEndTuple"></param>
        /// <param name="grid"></param>
        /// <param name="intersections"></param>
        /// <returns></returns>
        private bool _isTuringTwice(
            Tuple hStartTuple,
            Tuple vStartTuple,
            Tuple hEndTuple,
            Tuple vEndTuple,
            Grid grid,
            out Position[] intersections)
        {
            Tuple lineSegment;

            intersections = null;

            // Both horizontal lines - Base: hStartTuple
            Position hStartA = hStartTuple.GetFirst();
            Position hStartB = hStartTuple.GetSecond();
            Position hEndA   = hEndTuple.GetFirst();
            Position hEndB   = hEndTuple.GetSecond();

            // Validation
            if (hStartA.X > hStartB.X)
            {
                throw new Exception();
            }
            if (hEndA.Y > hEndB.Y)
            {
                throw new Exception();
            }
            // Enumerate all possible line segments between lines: hStart and hEnd
            lineSegment = new Tuple(grid);
            for (int i = hStartA.X; i <= hStartB.X; ++i)
            {
                lineSegment.Clear();
                if (i >= hEndA.X && i <= hEndB.X)
                {
                    // Existed that path
                    if (hStartA.Y <= hEndA.Y)
                    {
                        // hStartA is upper line
                        lineSegment.Select(new Position(i, hStartA.Y));
                        lineSegment.Select(new Position(i, hEndA.Y));
                    }
                    else
                    {
                        // hEndA is upper line
                        lineSegment.Select(new Position(i, hEndA.Y));
                        lineSegment.Select(new Position(i, hStartA.Y));
                    }
                    // Check this line segment is a valid path
                    if (_isExistedPath(lineSegment, grid))
                    {
                        intersections    = new Position[2];
                        intersections[0] = lineSegment.GetFirst();
                        intersections[1] = lineSegment.GetSecond();
                        return(true);
                    }
                }
            }

            // Both vertical lines - Base: vStartTuple
            Position vStartA = vStartTuple.GetFirst();
            Position vStartB = vStartTuple.GetSecond();
            Position vEndA   = vEndTuple.GetFirst();
            Position vEndB   = vEndTuple.GetSecond();

            // Validation
            if (vStartA.X > vStartB.X)
            {
                throw new Exception();
            }
            if (vEndA.Y > vEndB.Y)
            {
                throw new Exception();
            }
            // Enumerate all possible line segments between lines: vStart and vEnd
            lineSegment = new Tuple(grid);
            for (int i = vStartA.Y; i <= vStartB.Y; ++i)
            {
                lineSegment.Clear();
                if (i >= vEndA.Y && i <= vEndB.Y)
                {
                    // Existed that path
                    if (vStartA.X <= vEndA.X)
                    {
                        // vStartA is left line
                        lineSegment.Select(new Position(vStartA.X, i));
                        lineSegment.Select(new Position(vEndA.X, i));
                    }
                    else
                    {
                        // vEndA is left line
                        lineSegment.Select(new Position(vEndA.X, i));
                        lineSegment.Select(new Position(vStartA.X, i));
                    }
                    // Check this line segment is a valid path
                    if (_isExistedPath(lineSegment, grid))
                    {
                        intersections    = new Position[2];
                        intersections[0] = lineSegment.GetFirst();
                        intersections[1] = lineSegment.GetSecond();
                        return(true);
                    }
                }
            }

            return(false);
        }
        // =================================================== Game Internal Logic Processing Functions ===================================================


        /// <summary>
        /// Get binary tuple of start and end positions given current position by expanding horizontally
        /// </summary>
        /// <param name="curPos">Current position</param>
        /// <param name="grid">Grid</param>
        /// <param name="curType">Current block type</param>
        /// <returns></returns>
        private Tuple _expandHorizontal(Position curPos, Grid grid, int curType)
        {
            int startPos, endPos;
            int i, j;

            j = curPos.Y;
            Tuple tuple = new Tuple(grid);

            // From current to leftmost
            startPos = curPos.X;
            i        = startPos - 1;
            while (i >= 0)
            {
                Block curExploredBlock = grid.GetBlock(new Position(i, j));
                if (curExploredBlock.IsNull())
                {
                    // Null block can be passed
                    startPos = i;
                }
                else if (curExploredBlock.GetImageId() == curType)
                {
                    // Block with same type can be passed
                    startPos = i;
                }
                else
                {
                    // Cannot passed, terminated
                    break;
                }
                --i;
            }

            // From current to rightmost
            endPos = curPos.X;
            i      = endPos + 1;
            while (i < Model.TOT_BLOCK_CNT_X)
            {
                Block curExploredBlock = grid.GetBlock(new Position(i, j));
                if (curExploredBlock.IsNull())
                {
                    // Null block can be passed
                    endPos = i;
                }
                else if (curExploredBlock.GetImageId() == curType)
                {
                    // Block with same type can be passed
                    endPos = i;
                }
                else
                {
                    // Cannot passed, terminated
                    break;
                }
                ++i;
            }

            bool ret = true;

            ret = ret && tuple.Select(new Position(startPos, j));
            ret = ret && tuple.Select(new Position(endPos, j));
            if (!ret)
            {
                throw new Exception();
            }
            return(tuple);
        }