private void FlipValidTriominoAndSetStep(ETriomino triomino, int x, int y, int depth)
 {
     Steps[depth].triomino = triomino;
     Steps[depth].x        = x;
     Steps[depth].y        = y;
     Steps[depth].placed   = !Steps[depth].placed;
     ++StepsTaken;
     FlipValidTriomino(triomino, x + y * Width);
 }
        private IEnumerator CalculateCoroutine(int x, int y, int depth)
        {
            if (m_UseMem && m_Dictionary.TryGetValue(m_State, out long permutations))
            {
                Permutations += permutations;
                //FlipValidTriominoAndSetStep(ETriomino.Mem, 0, 0, depth);
                yield return(null);
            }
            else
            {
                long prevPermutations = Permutations;
                int  index            = x + y * Width;

                //Find index for next piece to be placed
                while (!m_State[index])
                {
                    ++index;
                }

                //Find next piece to be placed at the index
                int       nextX     = index % Width;
                int       nextY     = index / Width;
                int       nextDepth = depth + 1;
                ETriomino next      = GetNextValidTriomino(ETriomino.None, nextX, nextY);

                while (next != ETriomino.None)
                {
                    FlipValidTriominoAndSetStep(next, nextX, nextY, depth);
                    yield return(null);

                    if (nextDepth == m_MaxPieces)
                    {
                        Permutations += 1L;
                    }
                    else
                    {
                        IEnumerator e = CalculateCoroutine(nextX, nextY, nextDepth);
                        while (e.MoveNext())
                        {
                            yield return(null);
                        }
                    }
                    FlipValidTriominoAndSetStep(next, nextX, nextY, depth);
                    yield return(null);

                    next = GetNextValidTriomino(next, nextX, nextY);
                }

                if (m_UseMem && (prevPermutations != Permutations))
                {
                    m_Dictionary.Add((DynamicBitset)m_State.Clone(), Permutations - prevPermutations);
                }
            }
        }
        /// <summary>
        /// Flips the bits corresponding the the specific triomino piece at the specified location
        /// Does not do any bounds checking for additional performance gains
        /// </summary>
        /// <param name="triomino">The piece being placed or removed</param>
        /// <param name="index">The location in the bitset the piece is being placed or removed/param>
        private void FlipValidTriomino(ETriomino triomino, int index)
        {
            switch (triomino)
            {
            case ETriomino.None:
                return;

            case ETriomino.VLine:
                m_State.Flip(index);
                m_State.Flip(index + Width);
                m_State.Flip(index + (Width << 1));
                return;

            case ETriomino.TopLeft:
                m_State.Flip(index);
                m_State.Flip(index + Width);
                m_State.Flip(index + 1);
                return;

            case ETriomino.TopRight:
                m_State.Flip(index);
                m_State.Flip(index + 1);
                m_State.Flip(index + 1 + Width);
                return;

            case ETriomino.BottomLeft:
                m_State.Flip(index);
                m_State.Flip(index + Width);
                m_State.Flip(index + 1 + Width);
                return;

            case ETriomino.BottomRight:
                m_State.Flip(index);
                m_State.Flip(index + Width);
                m_State.Flip(index + Width - 1);
                return;

            case ETriomino.HLine:
                m_State.Flip(index);
                m_State.Flip(index + 1);
                m_State.Flip(index + 2);
                return;

            default:
                return;
            }
        }
        private long Calculate(int index, int depth)
        {
            long total = 0;

            if (m_Dictionary.TryGetValue(m_State, out long prevPermutations))
            {
                total += prevPermutations;
            }
            else
            {
                //Find index for next piece to be placed
                while (!m_State[index])
                {
                    ++index;
                }

                //Find next piece to be placed at the index
                int       nextX     = index % Width;
                int       nextY     = index / Width;
                int       nextDepth = depth + 1;
                ETriomino next      = GetNextValidTriomino(ETriomino.None, nextX, nextY);

                while (next != ETriomino.None)
                {
                    if (nextDepth == m_MaxPieces)
                    {
                        total += 1;
                    }
                    else
                    {
                        FlipValidTriomino(next, index);
                        total += Calculate(index, nextDepth);
                        FlipValidTriomino(next, index);
                    }
                    next = GetNextValidTriomino(next, nextX, nextY);
                }

                if (total != 0)
                {
                    m_Dictionary.Add((DynamicBitset)m_State.Clone(), total);
                }
            }

            return(total);
        }
        private ETriomino GetNextValidTriomino(ETriomino triomino, int x, int y)
        {
            bool b01 = ((y + 1) < Height) && State(x, y + 1);
            bool b10 = ((x + 1) < Width) && State(x + 1, y);
            bool b11 = ((y + 1) < Height) && ((x + 1) < Width) && State(x + 1, y + 1);

            switch (triomino)
            {
            case ETriomino.None:
                if (b01 && ((y + 2) < Height) && State(x, y + 2))
                {
                    return(ETriomino.VLine);
                }
                else
                {
                    goto case ETriomino.VLine;
                }

            case ETriomino.VLine:
                if (b10 && b01)
                {
                    return(ETriomino.TopLeft);
                }
                else
                {
                    goto case ETriomino.TopLeft;
                }

            case ETriomino.TopLeft:
                if (b10 && b11)
                {
                    return(ETriomino.TopRight);
                }
                else
                {
                    goto case ETriomino.TopRight;
                }

            case ETriomino.TopRight:
                if (b01 && b11)
                {
                    return(ETriomino.BottomLeft);
                }
                else
                {
                    goto case ETriomino.BottomLeft;
                }

            case ETriomino.BottomLeft:
                if (b01 && (x > 0) && State(x - 1, y + 1))
                {
                    return(ETriomino.BottomRight);
                }
                else
                {
                    goto case ETriomino.BottomRight;
                }

            case ETriomino.BottomRight:
                if (b10 && ((x + 2) < Width) && State(x + 2, y))
                {
                    return(ETriomino.HLine);
                }
                else
                {
                    return(ETriomino.None);
                }

            case ETriomino.HLine:
                return(ETriomino.None);

            case ETriomino.Mem:
                return(ETriomino.None);

            default:
                return(ETriomino.None);
            }
        }