public void Clean()
 {
     _native.Dispose();
 }
        public static NativeHashMap <Piece, Move> Generate(ref SimpleBoard board, Piece spawned,
                                                           NativeArray <int4x4> pieceShapes, bool holdUse)
        {
            var columns    = stackalloc int[10];
            var maxHeights = stackalloc byte[10];

            board.GetColumns(columns, maxHeights);

            var lookup     = new NativeHashMap <Piece, Move>(200, Allocator.Temp);
            var passed     = new NativeHashMap <Piece, bool>(200, Allocator.Temp);
            var checkQueue = new NativePriorityQueue <Move>(false, 100, Allocator.Temp);


            var maxHeight = 0;

            for (var i = 0; i < 10; i++)
            {
                if (maxHeights[i] > maxHeight)
                {
                    maxHeight = maxHeights[i];
                }
            }

            if (maxHeight < 16)
            {
                var starts = GenerateStarts(spawned.kind, holdUse);
                for (var i = 0; i < starts.Length; i++)
                {
                    var start   = starts[i];
                    var originY = start.piece.y;
                    var piece   = board.SonicDropFast(start.piece, pieceShapes);
                    start.piece = piece;
                    Confirm(ref board, ref lookup, start, pieceShapes);
                    var m2 = start;
                    var dY = originY - piece.y;
                    m2.instructions[m2.length++] = (byte)SonicDrop;
                    m2.time += dY * 2;
                    checkQueue.Enqueue(m2);
                }

                starts.Dispose();
            }
            else
            {
                var p = new Piece(spawned.kind);
                var d = board.SonicDropFast(p, pieceShapes);
                var m = new Move();
                m.hold            = holdUse;
                m.piece           = d;
                m.instructions[0] = (byte)SonicDrop;
                m.length          = 1;
                m.time            = 2 * (p.y - d.y);
                checkQueue.Enqueue(m);
            }

            while (checkQueue.TryDequeue(out var mv))
            {
                if (!mv.IsFull)
                {
                    Attempt(ref board, mv, ref passed, ref checkQueue, Left, maxHeight, pieceShapes);
                    Attempt(ref board, mv, ref passed, ref checkQueue, Right, maxHeight, pieceShapes);

                    if (mv.piece.kind != O)
                    {
                        Attempt(ref board, mv, ref passed, ref checkQueue, Cw, maxHeight, pieceShapes);
                        Attempt(ref board, mv, ref passed, ref checkQueue, Ccw, maxHeight, pieceShapes);
                    }

                    Attempt(ref board, mv, ref passed, ref checkQueue, Left, maxHeight, pieceShapes, true);
                    Attempt(ref board, mv, ref passed, ref checkQueue, Right, maxHeight, pieceShapes, true);

                    Attempt(ref board, mv, ref passed, ref checkQueue, SonicDrop, maxHeight, pieceShapes);
                }

                //Finally add this placement(harddropped) to return array
                var pl    = board.SonicDropFast(mv.piece, pieceShapes);
                var mHard = mv;
                mHard.piece = pl;
                Confirm(ref board, ref lookup, mHard, pieceShapes);
            }

            passed.Dispose();
            checkQueue.Dispose();
            return(lookup);
        }