Esempio n. 1
0
        /*
        ///<summary>Wave algorithm of building box move tree (x-start,y-start)</summary>
        public FunctionResult BuildBoxMoveTreeFull_OLD(int iXstart, int iYstart)
        {
            int x, y, z;
            int iStop;
            short iThisCheck, iNextCheck;
            short iLeftToDown, iLeftToRight, iLeftToUp, iRightToDown, iRightToUp, iUpToDown;
            int iCount = 0;

            iBoxMoveTree = new short[iXsize, iYsize, 5];
            SokobanLevel uTempLevel = new SokobanLevel(this);

            //remove box from it's source location and player from current location
            uTempLevel.bCells[iPlayerX, iPlayerY] ^= SokoCell.Player;
            uTempLevel.bCells[iXstart, iYstart] ^= SokoCell.Box;

            for (y = 0; y < iYsize; y++)
                for (x = 0; x < iXsize; x++)
                {
                    for (z = 0; z < 4; z++)
                        iBoxMoveTree[x, y, z] = MT_NOT_REACHED;
                    iBoxMoveTree[x, y, BMT_FLAGS] = 0;

                    if ((uTempLevel.bCells[x, y] & SokoCell.Obstacle) != 0 || x == 0 || y == 0 || x == (iXsize - 1) || y == (iYsize - 1))
                    {
                        for (z = 0; z < 4; z++)
                            iBoxMoveTree[x, y, z] = MT_BLOCKED;
                    }
                    else
                    {
                        if ((uTempLevel.bCells[x, y - 1] & SokoCell.Obstacle) != 0) iBoxMoveTree[x, y, PLAYER_TO_UP] = MT_BLOCKED;//blocked
                        if ((uTempLevel.bCells[x - 1, y] & SokoCell.Obstacle) != 0) iBoxMoveTree[x, y, PLAYER_TO_LEFT] = MT_BLOCKED;//blocked
                        if ((uTempLevel.bCells[x, y + 1] & SokoCell.Obstacle) != 0) iBoxMoveTree[x, y, PLAYER_TO_DOWN] = MT_BLOCKED;//blocked
                        if ((uTempLevel.bCells[x + 1, y] & SokoCell.Obstacle) != 0) iBoxMoveTree[x, y, PLAYER_TO_RIGHT] = MT_BLOCKED;//blocked
                    }

                }
            BuildPlayerMoveTree(iPlayerX, iPlayerY);
            z = 0;
            if (iMoveTree[iXstart - 1, iYstart] >= 0) { iBoxMoveTree[iXstart, iYstart, PLAYER_TO_LEFT] = iMoveTree[iXstart - 1, iYstart]; z = 1; }
            if (iMoveTree[iXstart + 1, iYstart] >= 0) { iBoxMoveTree[iXstart, iYstart, PLAYER_TO_RIGHT] = iMoveTree[iXstart + 1, iYstart]; z = 2; }
            if (iMoveTree[iXstart, iYstart - 1] >= 0) { iBoxMoveTree[iXstart, iYstart, PLAYER_TO_UP] = iMoveTree[iXstart, iYstart - 1]; z = 3; }
            if (iMoveTree[iXstart, iYstart + 1] >= 0) { iBoxMoveTree[iXstart, iYstart, PLAYER_TO_DOWN] = iMoveTree[iXstart, iYstart + 1]; z = 4; }
            if (z == 0)
            {
                //No way to selected box from current player location - exit
                return FunctionResult.StartIsBlocked;
            }

            iBoxMoveTree[iXstart, iYstart, BMT_FLAGS] = BMTF_ACHIVED | BMTF_TO_CHECK_EVEN;

            iThisCheck = BMTF_TO_CHECK_EVEN;
            iNextCheck = BMTF_TO_CHECK_ODD;

            iStop = 0;

            while (iStop == 0)
            {
                iStop = 1;
                for (y = 1; y < (iYsize - 1); y++)
                    for (x = 1; x < (iXsize - 1); x++)
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & iThisCheck) != 0)
                        {
                            iCount++;
                            //required to check

                            uTempLevel.bCells[x, y] ^= SokoCell.Box;                        //tempr. set box
                            uTempLevel.InvalidatePlayerMoveTree();//remove player move tree to not stumble with it, if it was calculate for current cell but for other box configuration

                            uTempLevel.BuildPlayerMoveTree(x - 1, y);//build player move tree from left to box
                            iLeftToRight = uTempLevel.iMoveTree[x + 1, y];
                            iLeftToUp = uTempLevel.iMoveTree[x, y - 1];
                            iLeftToDown = uTempLevel.iMoveTree[x, y + 1];

                            uTempLevel.BuildPlayerMoveTree(x + 1, y);//from right
                            iRightToDown = uTempLevel.iMoveTree[x, y + 1];
                            iRightToUp = uTempLevel.iMoveTree[x, y - 1];

                            uTempLevel.BuildPlayerMoveTree(x, y + 1); //from down
                            iUpToDown = uTempLevel.iMoveTree[x, y - 1];

                            uTempLevel.bCells[x, y] ^= SokoCell.Box; //remove box

                            if (iLeftToDown > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_DOWN_TO_LEFT;
                            if (iLeftToRight > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_LEFT_TO_RIGHT;
                            if (iLeftToUp > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_UP_TO_LEFT;
                            if (iRightToDown > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_DOWN_TO_RIGHT;
                            if (iRightToUp > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_UP_TO_RIGHT;
                            if (iUpToDown > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_UP_TO_DOWN;

                            //if (x == 6 && y == 7)
                            //{
                            //    x = x;
                            //}

                            if (iBoxMoveTree[x, y, PLAYER_TO_UP] >= 0)
                            {//Player-to-up is achived
                                if (iLeftToUp > 0 && iBoxMoveTree[x, y, PLAYER_TO_LEFT] == MT_NOT_REACHED)
                                { iBoxMoveTree[x, y, PLAYER_TO_LEFT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_UP] + iLeftToUp); iStop = 0; }
                                if (iUpToDown > 0 && iBoxMoveTree[x, y, PLAYER_TO_DOWN] == MT_NOT_REACHED)
                                { iBoxMoveTree[x, y, PLAYER_TO_DOWN] = (short)(iBoxMoveTree[x, y, PLAYER_TO_UP] + iUpToDown); iStop = 0; }
                                if (iRightToUp > 0 && iBoxMoveTree[x, y, PLAYER_TO_RIGHT] == MT_NOT_REACHED)
                                { iBoxMoveTree[x, y, PLAYER_TO_RIGHT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_UP] + iRightToUp); iStop = 0; }
                            }
                            if (iBoxMoveTree[x, y, PLAYER_TO_LEFT] >= 0)
                            {//Player-to-left is achived
                                if (iLeftToUp > 0 && iBoxMoveTree[x, y, PLAYER_TO_UP] == MT_NOT_REACHED)
                                { iBoxMoveTree[x, y, PLAYER_TO_UP] = (short)(iBoxMoveTree[x, y, PLAYER_TO_LEFT] + iLeftToUp); iStop = 0; }
                                if (iLeftToDown > 0 && iBoxMoveTree[x, y, PLAYER_TO_DOWN] == MT_NOT_REACHED)
                                { iBoxMoveTree[x, y, PLAYER_TO_DOWN] = (short)(iBoxMoveTree[x, y, PLAYER_TO_LEFT] + iLeftToDown); iStop = 0; }
                                if (iLeftToRight > 0 && iBoxMoveTree[x, y, PLAYER_TO_RIGHT] == MT_NOT_REACHED)
                                { iBoxMoveTree[x, y, PLAYER_TO_RIGHT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_LEFT] + iLeftToRight); iStop = 0; }
                            }
                            if (iBoxMoveTree[x, y, PLAYER_TO_RIGHT] >= 0)
                            {//Player-to-right is achived
                                if (iLeftToRight > 0 && iBoxMoveTree[x, y, PLAYER_TO_LEFT] == MT_NOT_REACHED)
                                { iBoxMoveTree[x, y, PLAYER_TO_LEFT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_RIGHT] + iLeftToRight); iStop = 0; }
                                if (iRightToDown > 0 && iBoxMoveTree[x, y, PLAYER_TO_DOWN] == MT_NOT_REACHED)
                                { iBoxMoveTree[x, y, PLAYER_TO_DOWN] = (short)(iBoxMoveTree[x, y, PLAYER_TO_RIGHT] + iRightToDown); iStop = 0; }
                                if (iRightToUp > 0 && iBoxMoveTree[x, y, PLAYER_TO_UP] == MT_NOT_REACHED)
                                { iBoxMoveTree[x, y, PLAYER_TO_UP] = (short)(iBoxMoveTree[x, y, PLAYER_TO_RIGHT] + iRightToUp); iStop = 0; }
                            }
                            if (iBoxMoveTree[x, y, PLAYER_TO_DOWN] >= 0)
                            {//Player-to-down is achived
                                if (iLeftToDown > 0 && iBoxMoveTree[x, y, PLAYER_TO_LEFT] == MT_NOT_REACHED)
                                { iBoxMoveTree[x, y, PLAYER_TO_LEFT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_DOWN] + iLeftToDown); iStop = 0; }
                                if (iUpToDown > 0 && iBoxMoveTree[x, y, PLAYER_TO_UP] == MT_NOT_REACHED)
                                { iBoxMoveTree[x, y, PLAYER_TO_UP] = (short)(iBoxMoveTree[x, y, PLAYER_TO_DOWN] + iUpToDown); iStop = 0; }
                                if (iRightToDown > 0 && iBoxMoveTree[x, y, PLAYER_TO_RIGHT] == MT_NOT_REACHED)
                                { iBoxMoveTree[x, y, PLAYER_TO_RIGHT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_DOWN] + iRightToDown); iStop = 0; }
                            }

                            if (iBoxMoveTree[x, y, PLAYER_TO_UP] >= 0)
                            {//Player-to-up is achived
                                if (iBoxMoveTree[x, y + 1, PLAYER_TO_UP] == MT_NOT_REACHED)
                                {
                                    iBoxMoveTree[x, y + 1, PLAYER_TO_UP] = (short)(iBoxMoveTree[x, y, PLAYER_TO_UP] + 1);
                                    iBoxMoveTree[x, y + 1, BMT_FLAGS] |= iNextCheck;//Set "to check" flag
                                    iStop = 0;
                                }
                            }
                            if (iBoxMoveTree[x, y, PLAYER_TO_LEFT] >= 0)
                            {//Player-to-left is achived
                                if (iBoxMoveTree[x + 1, y, PLAYER_TO_LEFT] == MT_NOT_REACHED)
                                {
                                    iBoxMoveTree[x + 1, y, PLAYER_TO_LEFT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_LEFT] + 1);
                                    iBoxMoveTree[x + 1, y, BMT_FLAGS] |= iNextCheck;
                                    iStop = 0;
                                }
                            }
                            if (iBoxMoveTree[x, y, PLAYER_TO_RIGHT] >= 0)
                            {//Player-to-right is achived
                                if (iBoxMoveTree[x - 1, y, PLAYER_TO_RIGHT] == MT_NOT_REACHED)
                                {
                                    iBoxMoveTree[x - 1, y, PLAYER_TO_RIGHT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_RIGHT] + 1);
                                    iBoxMoveTree[x - 1, y, BMT_FLAGS] |= iNextCheck;
                                    iStop = 0;
                                }
                            }
                            if (iBoxMoveTree[x, y, PLAYER_TO_DOWN] >= 0)
                            {//Player-to-down is achived
                                if (iBoxMoveTree[x, y - 1, PLAYER_TO_DOWN] == MT_NOT_REACHED)
                                {
                                    iBoxMoveTree[x, y - 1, PLAYER_TO_DOWN] = (short)(iBoxMoveTree[x, y, PLAYER_TO_DOWN] + 1);
                                    iBoxMoveTree[x, y - 1, BMT_FLAGS] |= iNextCheck;
                                    iStop = 0;
                                }
                            }

                            //Remove "to check" flag from this cell
                            iBoxMoveTree[x, y, BMT_FLAGS] &= BMTF_MASK_CLEAR_TOCHECK;
                            iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_ACHIVED;
                        }
                if (iThisCheck == BMTF_TO_CHECK_ODD)
                {
                    iThisCheck = BMTF_TO_CHECK_EVEN;
                    iNextCheck = BMTF_TO_CHECK_ODD;
                }
                else
                {
                    iThisCheck = BMTF_TO_CHECK_ODD;
                    iNextCheck = BMTF_TO_CHECK_EVEN;
                }
            }
            iBoxMoveTreeFromX = iXstart;
            iBoxMoveTreeFromY = iYstart;
            return FunctionResult.OK;
        }
        */
        //with XXYY - 100ms on aenigma-42, 62ms on aborelia-22
        //with UpTo only - 120ms on aenigma-42, 62ms on aborelia-22
        //without - 140ms on aenigma-42, 70ms on aborelia-22, 66 on aenigma-39, 54 on aenigma-36
        //UpTo + 6step - 85 on aenigma-42, 60 on aenigma-39, 50 on aenigma-36, 66 on aborelia-22
        ///<summary>Wave algorithm of building box move tree (x,y of box start, flag of stop on cell-deadlock or not)</summary>
        public FunctionResult BuildBoxMoveTreeFull(int iXstart, int iYstart, bool bStopOnDeadlocks)
        {
            /*
             * Function build box move tree by wave algorithm - from current location box moving propagated
             *   to all possible (by game rulse) directions with chosing minimal (by moves) actions to reach
             *   one box position by different ways.
             * Resulting tree can be used to quickly build moving-pushing sequence to push box into any location (only if location is achived)
             */
            int x, y, z;
            short iLeftToDown, iLeftToRight, iLeftToUp, iRightToDown, iRightToUp, iUpToDown;
            bool bLeft, bRight, bUp, bDown;

            iBoxMoveTree = new short[iXsize, iYsize, 5];//Alloc box move tree array
            SokobanGame uTempLevel = new SokobanGame(this);//Temprorary level as copy of current
            CoordQueue uQueue = new CoordQueue();//Queue for verifying cells

            SokoCell bObstacle = SokoCell.MaskObstacle;//Ordinary obstacle mask
            if (bStopOnDeadlocks)
                bObstacle |= SokoCell.CellDeadlock;//Add cell-deadlock as obstacle

            //Remove box from it's source location and player from current location
            uTempLevel.bCells[iPlayerX, iPlayerY] ^= SokoCell.Player;
            uTempLevel.bCells[iXstart, iYstart] ^= SokoCell.Box;

            //Mark forbidden branches of tree
            for (y = 0; y < iYsize; y++)
                for (x = 0; x < iXsize; x++)
                {
                    for (z = 0; z < 4; z++)
                        iBoxMoveTree[x, y, z] = MT_NOT_REACHED;//All - not yet reached
                    iBoxMoveTree[x, y, BMT_FLAGS] = 0;

                    if ((uTempLevel.bCells[x, y] & bObstacle) != 0 || x == 0 || y == 0 || x == (iXsize - 1) || y == (iYsize - 1))
                    {//Obstacle on cell or border cell (topmost, bottommost, leftmost and rightmost lines of level MUST contain ONLY walls or backgrounds, so box move tree should not reach them)
                        for (z = 0; z < 4; z++)
                            iBoxMoveTree[x, y, z] = MT_BLOCKED;
                    }
                    else
                    {//Check blocking by obstacle at player position
                        if ((uTempLevel.bCells[x, y - 1] & SokoCell.MaskObstacle) != 0) iBoxMoveTree[x, y, PLAYER_TO_UP] = MT_BLOCKED;//blocked
                        if ((uTempLevel.bCells[x - 1, y] & SokoCell.MaskObstacle) != 0) iBoxMoveTree[x, y, PLAYER_TO_LEFT] = MT_BLOCKED;//blocked
                        if ((uTempLevel.bCells[x, y + 1] & SokoCell.MaskObstacle) != 0) iBoxMoveTree[x, y, PLAYER_TO_DOWN] = MT_BLOCKED;//blocked
                        if ((uTempLevel.bCells[x + 1, y] & SokoCell.MaskObstacle) != 0) iBoxMoveTree[x, y, PLAYER_TO_RIGHT] = MT_BLOCKED;//blocked
                    }

                }

            //Check that box is reachable by player and set "seed"/root for box move tree
            BuildPlayerMoveTree(iPlayerX, iPlayerY);
            for (z = 0; z < 4; z++)
                bBoxMoveTreeRootDirections[z] = false;
            z = 0;
            if (iMoveTree[iXstart - 1, iYstart] >= 0) { iBoxMoveTree[iXstart, iYstart, PLAYER_TO_LEFT] = iMoveTree[iXstart - 1, iYstart]; z = 1; bBoxMoveTreeRootDirections[PLAYER_TO_LEFT] = true; }
            if (iMoveTree[iXstart + 1, iYstart] >= 0) { iBoxMoveTree[iXstart, iYstart, PLAYER_TO_RIGHT] = iMoveTree[iXstart + 1, iYstart]; z = 2; bBoxMoveTreeRootDirections[PLAYER_TO_RIGHT] = true; }
            if (iMoveTree[iXstart, iYstart - 1] >= 0) { iBoxMoveTree[iXstart, iYstart, PLAYER_TO_UP] = iMoveTree[iXstart, iYstart - 1]; z = 3; bBoxMoveTreeRootDirections[PLAYER_TO_UP] = true; }
            if (iMoveTree[iXstart, iYstart + 1] >= 0) { iBoxMoveTree[iXstart, iYstart, PLAYER_TO_DOWN] = iMoveTree[iXstart, iYstart + 1]; z = 4; bBoxMoveTreeRootDirections[PLAYER_TO_DOWN] = true; }
            if (z == 0)
            {
                //No way to specified box from current player location - exit
                return FunctionResult.StartIsBlocked;
            }

            //Root of tree - start location
            iBoxMoveTree[iXstart, iYstart, BMT_FLAGS] = BMTF_ACHIVED | BMTF_TO_CHECK;
            uQueue.AddNext(iXstart, iYstart);

            //Propagating tree to all cells - by checking cells, received from queue and adding new cells to this queue
            x = 0; y = 0;
            while (uQueue.Get(ref x, ref y))//Get next cell from queue
            {
                if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_TO_CHECK) != 0)
                {
                    //If cell is marked as required to check (i.e. was marked but not yet checked since that)

                    //Get blocking state of 4 possible player positions around box
                    bUp = (iBoxMoveTree[x, y, PLAYER_TO_UP] != MT_BLOCKED);
                    bLeft = (iBoxMoveTree[x, y, PLAYER_TO_LEFT] != MT_BLOCKED);
                    bRight = (iBoxMoveTree[x, y, PLAYER_TO_RIGHT] != MT_BLOCKED);
                    bDown = (iBoxMoveTree[x, y, PLAYER_TO_DOWN] != MT_BLOCKED);

                    //Paths between all this 4 positions - initially they are not known
                    iLeftToRight = MT_NOT_REACHED;
                    iLeftToUp = MT_NOT_REACHED;
                    iLeftToDown = MT_NOT_REACHED;
                    iRightToDown = MT_NOT_REACHED;
                    iRightToUp = MT_NOT_REACHED;
                    iUpToDown = MT_NOT_REACHED;

                    if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_ACHIVED) != 0)
                    {
                        //Not first pass of this cell
                        iCountDebug++;//Count all additional passes
                    }

                    uTempLevel.bCells[x, y] ^= SokoCell.Box;//Temprorary put box to this cell
                    uTempLevel.InvalidatePlayerMoveTree();//Flush player move tree to not stumble with it, if it was calculate for current cell but for other box configuration

                    //If some positions around box is blocked - block all corresponded paths
                    if (!bLeft) { iLeftToDown = MT_BLOCKED; iLeftToRight = MT_BLOCKED; iLeftToUp = MT_BLOCKED; }
                    if (!bRight) { iRightToDown = MT_BLOCKED; iLeftToRight = MT_BLOCKED; iRightToUp = MT_BLOCKED; }
                    if (!bUp) { iUpToDown = MT_BLOCKED; iRightToUp = MT_BLOCKED; iLeftToUp = MT_BLOCKED; }
                    if (!bDown) { iLeftToDown = MT_BLOCKED; iRightToDown = MT_BLOCKED; iUpToDown = MT_BLOCKED; }

                    /*
                    //Check simple "turn over box in two steps"
                    if (bLeft)
                    {
                        if (bUp)
                            if ((uTempLevel.bCells[x - 1, y - 1] & SokoCell.Obstacle) ==0) iLeftToUp =2;
                        if (bDown)
                            if ((uTempLevel.bCells[x - 1, y + 1] & SokoCell.Obstacle) == 0) iLeftToDown = 2;
                        if (iLeftToUp == 2 && iLeftToDown == 2)
                            iUpToDown = 4;//two turns - go box around in 4 steps
                    }
                    if (bRight )
                    {
                        if (bUp)
                            if ((uTempLevel.bCells[x + 1, y - 1] & SokoCell.Obstacle) == 0) iRightToUp = 2;
                        if (bDown)
                            if ((uTempLevel.bCells[x + 1, y + 1] & SokoCell.Obstacle) == 0) iRightToDown = 2;
                        if (iRightToUp == 2 && iRightToDown == 2)
                            iUpToDown = 4;//two turns - go box around in 4 steps
                    }/**/

                    //Check simple "turn over box" in two steps
                    if (bLeft)
                    {
                        if (bUp)
                            if ((uTempLevel.bCells[x - 1, y - 1] & SokoCell.MaskObstacle) == 0) iLeftToUp = 2;//Left, up and left-up cells are empty - so player can move from up to left in 2 steps
                        if (bDown)
                            if ((uTempLevel.bCells[x - 1, y + 1] & SokoCell.MaskObstacle) == 0) //Left, down and left-down cells are empty ...
                            {
                                iLeftToDown = 2;
                                if (iLeftToUp == 2)
                                    iUpToDown = 4;//Two turns - player can go around box in 4 steps
                            }
                    }
                    if (bRight)
                    {//By analogue...
                        if (bUp)
                            if ((uTempLevel.bCells[x + 1, y - 1] & SokoCell.MaskObstacle) == 0) iRightToUp = 2;
                        if (bDown)
                            if ((uTempLevel.bCells[x + 1, y + 1] & SokoCell.MaskObstacle) == 0)
                            {
                                iRightToDown = 2;
                                if (iRightToUp == 2)
                                    iUpToDown = 4;//Two turns - player can go around box in 4 steps
                            }
                    }

                    //Check left-to-right pass in two-turn-combo and three-turn-combo
                    if (iRightToUp == 2 && iLeftToUp == 2)
                    {//Can go right-to-up and from up-to-left -> can go right-to-left in 4 steps
                        iLeftToRight = 4;
                        if (iLeftToDown == MT_NOT_REACHED && iRightToDown == 2)
                            iLeftToDown = 6;//Also can go right-to-down -> can go left-to-down is 6 steps (if not yet)
                        else if (iLeftToDown == 2 && iRightToDown == MT_NOT_REACHED)
                            iRightToDown = 6;//Also can go left-to-down -> can go right-to-down in 6 steps (if not yet)
                    }
                    else if (iRightToDown == 2 && iLeftToDown == 2)
                    {//By analogue...
                        iLeftToRight = 4;
                        if (iLeftToUp == MT_NOT_REACHED && iRightToUp == 2)
                            iLeftToUp = 6;
                        else if (iLeftToUp == 2 && iRightToUp == MT_NOT_REACHED)
                            iRightToUp = 6;
                    }

                    if (iLeftToRight == MT_NOT_REACHED || iLeftToUp == MT_NOT_REACHED || iLeftToDown == MT_NOT_REACHED)
                    {//Some left-to is not yet calculated - can calculate them only by player move tree
                        uTempLevel.BuildPlayerMoveTree(x - 1, y);//Build player move tree from left to box
                        //uTempLevel.BuildPlayerMoveTree_UpTo(x - 1, y, x + 1, y);//from left to right
                        //uTempLevel.BuildPlayerMoveTree_XXYY(x - 1, y, x+1,x,y-1,y+1);//from left
                        iLeftToRight = uTempLevel.iMoveTree[x + 1, y];//And get reachability from player move tree
                        iLeftToUp = uTempLevel.iMoveTree[x, y - 1];
                        iLeftToDown = uTempLevel.iMoveTree[x, y + 1];

                        /*
                         * inefficient block
                        if (iLeftToRight > 0 && iLeftToUp <0)
                        {//there is way from left to right, but no way from left to up => no way from right to up
                            iRightToUp = MT_WILL_NOT_REACH;
                        }
                        if (iLeftToRight > 0 && iLeftToDown < 0)
                        {//there is way from left to right, but no way from left to down => no way from right to down
                            iRightToDown = MT_WILL_NOT_REACH;
                        }
                        if (iLeftToUp > 0 && iLeftToDown < 0)
                        {//there is way from left to up, but no way from left to down => no way from up to down
                            iUpToDown = MT_WILL_NOT_REACH;
                        }
                        if (iLeftToRight < 0 && iLeftToUp > 0)
                        {//there is way from left to right, but no way from left to up => no way from right to up
                            iRightToUp = MT_WILL_NOT_REACH;
                        }
                        if (iLeftToRight < 0 && iLeftToDown > 0)
                        {//there is way from left to right, but no way from left to down => no way from right to down
                            iRightToDown = MT_WILL_NOT_REACH;
                        }
                        if (iLeftToUp < 0 && iLeftToDown > 0)
                        {//there is way from left to up, but no way from left to down => no way from up to down
                            iUpToDown = MT_WILL_NOT_REACH;
                        }*/

                        /*
                        if (iLeftToRight * iLeftToUp < 0)
                        {//there is way from left to right, but no way from left to up => no way from right to up
                            iRightToUp = MT_WILL_NOT_REACH;
                        }
                        if (iLeftToRight * iLeftToDown < 0)
                        {//there is way from left to right, but no way from left to down => no way from right to down
                            iRightToDown = MT_WILL_NOT_REACH;
                        }
                        if (iLeftToUp * iLeftToDown < 0)
                        {//there is way from left to up, but no way from left to down => no way from up to down
                            iUpToDown = MT_WILL_NOT_REACH;
                        }/**/
                    }

                    if (iRightToDown == MT_NOT_REACHED || iRightToUp == MT_NOT_REACHED)
                    {//By analogue...
                        uTempLevel.BuildPlayerMoveTree(x + 1, y);//from right
                        //uTempLevel.BuildPlayerMoveTree_XYY(x + 1, y,x, y+1,y-1);//from right
                        iRightToDown = uTempLevel.iMoveTree[x, y + 1];
                        iRightToUp = uTempLevel.iMoveTree[x, y - 1];

                        /*
                        inefficient block
                        if (iRightToDown * iRightToUp < 0)
                        {//there is way from right to down, but no way from right to up or visa-versa => no way from up to down
                            iUpToDown = MT_WILL_NOT_REACH;
                        }/**/
                        /*
                        if (iRightToDown >0 && iRightToUp < 0)
                        {//there is way from right to down, but no way from right to up or visa-versa => no way from up to down
                            iUpToDown = MT_WILL_NOT_REACH;
                        }
                        if (iRightToDown <0 && iRightToUp > 0)
                        {//there is way from right to down, but no way from right to up or visa-versa => no way from up to down
                            iUpToDown = MT_WILL_NOT_REACH;
                        }*/
                    }

                    if (iUpToDown == MT_NOT_REACHED)
                    {//By analogue... up-to-down is still unknown
                        uTempLevel.BuildPlayerMoveTree(x, y + 1); //from down
                        //uTempLevel.BuildPlayerMoveTree_UpTo(x, y + 1,x,y-1); //from down
                        iUpToDown = uTempLevel.iMoveTree[x, y - 1];
                    }

                    uTempLevel.bCells[x, y] ^= SokoCell.Box; //Remove temp. box

                    //Set flags of possiblity to walk by paths around box
                    if (iLeftToDown > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_DOWN_TO_LEFT;
                    if (iLeftToRight > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_LEFT_TO_RIGHT;
                    if (iLeftToUp > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_UP_TO_LEFT;
                    if (iRightToDown > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_DOWN_TO_RIGHT;
                    if (iRightToUp > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_UP_TO_RIGHT;
                    if (iUpToDown > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_UP_TO_DOWN;

                    //Check propagating tree "around box"
                    if (iBoxMoveTree[x, y, PLAYER_TO_UP] >= 0)
                    {//Player-to-up is achived by tree
                        if (iLeftToUp > 0 && iBoxMoveTree[x, y, PLAYER_TO_LEFT] == MT_NOT_REACHED)//Can walk up-to-left and left is not yet achived
                        { iBoxMoveTree[x, y, PLAYER_TO_LEFT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_UP] + iLeftToUp); }//Achive left
                        if (iUpToDown > 0 && iBoxMoveTree[x, y, PLAYER_TO_DOWN] == MT_NOT_REACHED)//Can walk up-to-down and down is not yet achived
                        { iBoxMoveTree[x, y, PLAYER_TO_DOWN] = (short)(iBoxMoveTree[x, y, PLAYER_TO_UP] + iUpToDown); }//Achive down
                        if (iRightToUp > 0 && iBoxMoveTree[x, y, PLAYER_TO_RIGHT] == MT_NOT_REACHED)//By analogue...
                        { iBoxMoveTree[x, y, PLAYER_TO_RIGHT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_UP] + iRightToUp); }
                    }
                    if (iBoxMoveTree[x, y, PLAYER_TO_LEFT] >= 0)
                    {//Player-to-left is achived by tree ... by analogue...
                        if (iLeftToUp > 0 && iBoxMoveTree[x, y, PLAYER_TO_UP] == MT_NOT_REACHED)
                        { iBoxMoveTree[x, y, PLAYER_TO_UP] = (short)(iBoxMoveTree[x, y, PLAYER_TO_LEFT] + iLeftToUp); }
                        if (iLeftToDown > 0 && iBoxMoveTree[x, y, PLAYER_TO_DOWN] == MT_NOT_REACHED)
                        { iBoxMoveTree[x, y, PLAYER_TO_DOWN] = (short)(iBoxMoveTree[x, y, PLAYER_TO_LEFT] + iLeftToDown); }
                        if (iLeftToRight > 0 && iBoxMoveTree[x, y, PLAYER_TO_RIGHT] == MT_NOT_REACHED)
                        { iBoxMoveTree[x, y, PLAYER_TO_RIGHT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_LEFT] + iLeftToRight); }
                    }
                    if (iBoxMoveTree[x, y, PLAYER_TO_RIGHT] >= 0)
                    {//Player-to-right is achived by tree ... by analogue...
                        if (iLeftToRight > 0 && iBoxMoveTree[x, y, PLAYER_TO_LEFT] == MT_NOT_REACHED)
                        { iBoxMoveTree[x, y, PLAYER_TO_LEFT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_RIGHT] + iLeftToRight); }
                        if (iRightToDown > 0 && iBoxMoveTree[x, y, PLAYER_TO_DOWN] == MT_NOT_REACHED)
                        { iBoxMoveTree[x, y, PLAYER_TO_DOWN] = (short)(iBoxMoveTree[x, y, PLAYER_TO_RIGHT] + iRightToDown); }
                        if (iRightToUp > 0 && iBoxMoveTree[x, y, PLAYER_TO_UP] == MT_NOT_REACHED)
                        { iBoxMoveTree[x, y, PLAYER_TO_UP] = (short)(iBoxMoveTree[x, y, PLAYER_TO_RIGHT] + iRightToUp); }
                    }
                    if (iBoxMoveTree[x, y, PLAYER_TO_DOWN] >= 0)
                    {//Player-to-down is achived by tree ... by analogue...
                        if (iLeftToDown > 0 && iBoxMoveTree[x, y, PLAYER_TO_LEFT] == MT_NOT_REACHED)
                        { iBoxMoveTree[x, y, PLAYER_TO_LEFT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_DOWN] + iLeftToDown); }
                        if (iUpToDown > 0 && iBoxMoveTree[x, y, PLAYER_TO_UP] == MT_NOT_REACHED)
                        { iBoxMoveTree[x, y, PLAYER_TO_UP] = (short)(iBoxMoveTree[x, y, PLAYER_TO_DOWN] + iUpToDown); }
                        if (iRightToDown > 0 && iBoxMoveTree[x, y, PLAYER_TO_RIGHT] == MT_NOT_REACHED)
                        { iBoxMoveTree[x, y, PLAYER_TO_RIGHT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_DOWN] + iRightToDown); }
                    }

                    //Check propagating tree by pushing box
                    if (iBoxMoveTree[x, y, PLAYER_TO_UP] >= 0)
                    {//Player-to-up is achived by tree
                        if (iBoxMoveTree[x, y + 1, PLAYER_TO_UP] == MT_NOT_REACHED)
                        {//Player-to-up is not achived for cell to down (from currnet) - so box can be pushed to current cell from cell-to-down
                            iBoxMoveTree[x, y + 1, PLAYER_TO_UP] = (short)(iBoxMoveTree[x, y, PLAYER_TO_UP] + 1);//Achive player-to-up for cell-to-down
                            iBoxMoveTree[x, y + 1, BMT_FLAGS] |= BMTF_TO_CHECK;//Set "to check" flag for cell-to-down
                            uQueue.AddNext(x, y + 1);//Add cell-to-down into queue
                        }
                    }
                    if (iBoxMoveTree[x, y, PLAYER_TO_LEFT] >= 0)
                    {//Player-to-left is achived by tree
                        if (iBoxMoveTree[x + 1, y, PLAYER_TO_LEFT] == MT_NOT_REACHED) //By analogue...
                        {
                            iBoxMoveTree[x + 1, y, PLAYER_TO_LEFT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_LEFT] + 1);
                            iBoxMoveTree[x + 1, y, BMT_FLAGS] |= BMTF_TO_CHECK;
                            uQueue.AddNext(x + 1, y);
                        }
                    }
                    if (iBoxMoveTree[x, y, PLAYER_TO_RIGHT] >= 0)
                    {//Player-to-right is achived
                        if (iBoxMoveTree[x - 1, y, PLAYER_TO_RIGHT] == MT_NOT_REACHED) //By analogue...
                        {
                            iBoxMoveTree[x - 1, y, PLAYER_TO_RIGHT] = (short)(iBoxMoveTree[x, y, PLAYER_TO_RIGHT] + 1);
                            iBoxMoveTree[x - 1, y, BMT_FLAGS] |= BMTF_TO_CHECK;
                            uQueue.AddNext(x - 1, y);
                        }
                    }
                    if (iBoxMoveTree[x, y, PLAYER_TO_DOWN] >= 0)
                    {//Player-to-down is achived
                        if (iBoxMoveTree[x, y - 1, PLAYER_TO_DOWN] == MT_NOT_REACHED) //By analogue...
                        {
                            iBoxMoveTree[x, y - 1, PLAYER_TO_DOWN] = (short)(iBoxMoveTree[x, y, PLAYER_TO_DOWN] + 1);
                            iBoxMoveTree[x, y - 1, BMT_FLAGS] |= BMTF_TO_CHECK;
                            uQueue.AddNext(x, y - 1);
                        }
                    }

                    //Remove "to check" flag for this cell
                    iBoxMoveTree[x, y, BMT_FLAGS] &= BMTF_MASK_CLEAR_TOCHECK;
                    iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_ACHIVED;//Cell is achived by tree
                }
            }

            //Queue ends - tree builded

            //Remember position of root of tree
            iBoxMoveTreeFromX = iXstart;
            iBoxMoveTreeFromY = iYstart;
            return FunctionResult.OK;
        }
Esempio n. 2
0
        ///<summary>Calculate cell-deadlocks for current level and mark all cell-deadlock.
        ///cell-Deadlock - is cell, from there you cannot push box to target</summary>
        public FunctionResult CalcDeadlocks()
        {
            /*
             * Function build simplified box move tree for only one box at level and player stand on current location
             * Then first wave is propagated thru this tree - from targets to other cells but backward by connections of box move tree
             * Second wave is propagated thru same tree - from boxes to other cells forward by connections of box move tree
             * All branches of tree, reached by both waves - create not cell-deadlock in corresponding cell (because you can push some box by connections to some target)
             * All cells, not reached by any of waves - is cell-deadlocks
             *
             * (estimated as better to previos version - CalcDeadlocks_old()
             */

            int x, y, z;
            short iLeftToDown, iLeftToRight, iLeftToUp, iRightToDown, iRightToUp, iUpToDown;
            int iLeft, iRight, iUp, iDown;
            int iToCheck;
            //int iNeiCells;
            //SokoCell bMask;

            iBoxMoveTree = new short[iXsize, iYsize, 5];//Alloc box move tree array
            SokobanGame uTempLevel = new SokobanGame(this);//Temprorary level as copy of current
            CoordQueue uQueue = new CoordQueue();//Queue for verifying cells

            //Remove boxes and player from level
            for (y = 0; y < iYsize; y++)
                for (x = 0; x < iXsize; x++)
                    uTempLevel.bCells[x, y] &= SokoCell.FilterForCalcCellDeadlocks;

            //Stage 1. Mark forbidden branches of tree

            for (y = 0; y < iYsize; y++)
                for (x = 0; x < iXsize; x++)
                {
                    iBoxMoveTree[x, y, BMT_FLAGS] = 0;

                    if ((uTempLevel.bCells[x, y] & SokoCell.MaskObstacle) != 0 || x == 0 || y == 0 || x == (iXsize - 1) || y == (iYsize - 1))
                    {//Obstacle on cell or border cell (topmost, bottommost, leftmost and rightmost lines of level MUST contain ONLY walls or backgrounds, so box move tree should not reach them)
                        for (z = 0; z < 4; z++)
                            iBoxMoveTree[x, y, z] = MT_BLOCKED;
                    }
                    else
                    {
                        iToCheck=0;//Call may not require deep checking
                        for (z = 0; z < 4; z++)
                            iBoxMoveTree[x, y, z] = MT_NOT_REACHED;//Not yet reached

                        uTempLevel.bCells[x, y] ^= SokoCell.Box;//Temprorary put box to this cell

                        uTempLevel.InvalidatePlayerMoveTree();//Flush player move tree to not stumble with it, if it was calculate for current cell but for other box configuration
                        uTempLevel.BuildPlayerMoveTree(iPlayerX, iPlayerY);//Build player move tree - to check reachability of box from all sides

                        if ((uTempLevel.bCells[x, y - 1] & SokoCell.MaskObstacle) != 0) //Obstacle from up
                            iBoxMoveTree[x, y, PLAYER_TO_UP] = MT_BLOCKED;//Player-to-up is blocked
                        else if (uTempLevel.iMoveTree[x,y-1]>=0)//No obstacle and move tree reach cell to up
                        { iBoxMoveTree[x, y, PLAYER_TO_UP] = 0; iToCheck = 1; }//Player-to-up is available and cell should be checked further

                        if ((uTempLevel.bCells[x - 1, y] & SokoCell.MaskObstacle) != 0) //By analogue...
                            iBoxMoveTree[x, y, PLAYER_TO_LEFT] = MT_BLOCKED;
                        else if (uTempLevel.iMoveTree[x-1, y] >= 0)
                        { iBoxMoveTree[x, y, PLAYER_TO_LEFT] = 0; iToCheck = 1; }

                        if ((uTempLevel.bCells[x, y + 1] & SokoCell.MaskObstacle) != 0) //By analogue...
                            iBoxMoveTree[x, y, PLAYER_TO_DOWN] = MT_BLOCKED;
                        else if (uTempLevel.iMoveTree[x, y+1] >= 0)
                        { iBoxMoveTree[x, y, PLAYER_TO_DOWN] = 0; iToCheck = 1; }

                        if ((uTempLevel.bCells[x + 1, y] & SokoCell.MaskObstacle) != 0) //By analogue...
                            iBoxMoveTree[x, y, PLAYER_TO_RIGHT] = MT_BLOCKED;
                        else if (uTempLevel.iMoveTree[x+1, y] >= 0)
                        { iBoxMoveTree[x, y, PLAYER_TO_RIGHT] = 0; iToCheck = 1; }

                        if (iToCheck>0) //Cell should be check deeply
                        {
                            uQueue.AddNext(x, y);//Add cell to queue
                            iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_TO_CHECK; //Mark cell as not cheked
                        }

                        /* //Old and unoptimized
                        uTempLevel.BuildPlayerMoveTree(x - 1, y);//build player move tree from left to box
                        iLeftToRight = uTempLevel.iMoveTree[x + 1, y];
                        iLeftToUp = uTempLevel.iMoveTree[x, y - 1];
                        iLeftToDown = uTempLevel.iMoveTree[x, y + 1];
                        uTempLevel.BuildPlayerMoveTree(x + 1, y);//from right
                        iRightToDown = uTempLevel.iMoveTree[x, y + 1];
                        iRightToUp = uTempLevel.iMoveTree[x, y - 1];
                        uTempLevel.BuildPlayerMoveTree(x, y + 1); //from down
                        //uTempLevel.BuildPlayerMoveTree_UpTo(x, y + 1,x,y-1); //from down
                        iUpToDown = uTempLevel.iMoveTree[x, y - 1];
                         /**/

                        //(more optimization?)

                        //Paths between all this 4 positions - initially they are not known
                        iLeftToRight = MT_NOT_REACHED;
                        iLeftToUp = MT_NOT_REACHED;
                        iLeftToDown = MT_NOT_REACHED;
                        iRightToDown = MT_NOT_REACHED;
                        iRightToUp = MT_NOT_REACHED;
                        iUpToDown = MT_NOT_REACHED;

                        /*  //Also old and unoptimized
                        // (sasq6, level50 - 5460 ms)
                        //0x01 - up, 0x02 - up-right, 0x04 - right, 0x08 - right-down, 0x10 - down, 0x20 - down-left, 0x40 - left, 0x80 - left-up
                        iNeiCells = 0;
                        if (uTempLevel.iMoveTree[x, y - 1] == MT_BLOCKED) iNeiCells |= 0x01;
                        if (uTempLevel.iMoveTree[x, y + 1] == MT_BLOCKED) iNeiCells |= 0x10;
                        if (uTempLevel.iMoveTree[x-1, y] == MT_BLOCKED) iNeiCells |= 0x40;
                        if (uTempLevel.iMoveTree[x+1, y] == MT_BLOCKED) iNeiCells |= 0x04;
                        if (uTempLevel.iMoveTree[x-1, y - 1] == MT_BLOCKED) iNeiCells |= 0x80;
                        if (uTempLevel.iMoveTree[x-1, y + 1] == MT_BLOCKED) iNeiCells |= 0x20;
                        if (uTempLevel.iMoveTree[x + 1, y-1] == MT_BLOCKED) iNeiCells |= 0x02;
                        if (uTempLevel.iMoveTree[x + 1, y+1] == MT_BLOCKED) iNeiCells |= 0x08;

                        if ((iNeiCells & 0x07) == 0 || (iNeiCells & 0xFD) == 0)
                            iRightToUp = 1;//iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_UP_TO_RIGHT;
                        if ((iNeiCells & 0xC1) == 0 || (iNeiCells & 0x7F) == 0)
                            iLeftToUp = 1;//iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_UP_TO_LEFT;
                        if ((iNeiCells & 0x1F) == 0 || (iNeiCells & 0xF1) == 0)
                            iUpToDown = 1;//iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_UP_TO_DOWN;
                        if ((iNeiCells & 0x70) == 0 || (iNeiCells & 0xDF) == 0)
                            iLeftToDown = 1;//iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_DOWN_TO_LEFT;
                        if ((iNeiCells & 0x1C) == 0 || (iNeiCells & 0xF7) == 0)
                            iRightToDown = 1;//iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_DOWN_TO_RIGHT;
                        if ((iNeiCells & 0x7C) == 0 || (iNeiCells & 0xC7) == 0)
                            iLeftToRight = 1;//iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_LEFT_TO_RIGHT;
                        /**/

                        //Last optimized:  (sasq6, level50 - 3280 ms)

                        //Get number of moves to reach each side of box
                        iUp = uTempLevel.iMoveTree[x, y - 1];
                        iLeft = uTempLevel.iMoveTree[x - 1, y];
                        iRight = uTempLevel.iMoveTree[x + 1, y];
                        iDown = uTempLevel.iMoveTree[x, y + 1];

                        uTempLevel.InvalidatePlayerMoveTree();//Flush player move tree to not stumble with it, if it was calculate for current cell but for other box configuration

                        //If some positions around box is blocked - block all corresponded paths
                        if (iLeft == MT_BLOCKED) { iLeftToDown = MT_BLOCKED; iLeftToRight = MT_BLOCKED; iLeftToUp = MT_BLOCKED; }
                        if (iRight == MT_BLOCKED) { iRightToDown = MT_BLOCKED; iLeftToRight = MT_BLOCKED; iRightToUp = MT_BLOCKED; }
                        if (iUp == MT_BLOCKED) { iUpToDown = MT_BLOCKED; iRightToUp = MT_BLOCKED; iLeftToUp = MT_BLOCKED; }
                        if (iDown == MT_BLOCKED) { iLeftToDown = MT_BLOCKED; iRightToDown = MT_BLOCKED; iUpToDown = MT_BLOCKED; }

                        if (iUp >= 0)
                        {
                            if (iLeft >= 0)
                                iLeftToUp = 1; //Left and Up is reachable from player start, so path between then exist
                            if (iRight >= 0)
                                iRightToUp = 1; //By analogue...
                            if (iDown >= 0)
                                iUpToDown = 1; //By analogue...
                        }
                        if (iLeft >= 0)
                        {
                            if (iRight >= 0)
                                iLeftToRight = 1; //By analogue...
                            if (iDown >= 0)
                                iLeftToDown = 1; //By analogue...
                        }
                        if (iRight >= 0)
                        {
                            if (iDown >= 0)
                                iRightToDown = 1; //By analogue...
                        }

                        //Check simple "turn over box in two steps"
                        if (iLeft != MT_BLOCKED)
                        {
                            if (iUp != MT_BLOCKED)
                                if ((uTempLevel.bCells[x - 1, y - 1] & SokoCell.MaskObstacle) == 0) iLeftToUp = 2; //Left, up and left-up cells are empty - so player can move from up to left in 2 steps
                            if (iDown != MT_BLOCKED)
                                if ((uTempLevel.bCells[x - 1, y + 1] & SokoCell.MaskObstacle) == 0) //Left, down and left-down cells are empty ...
                                {
                                    iLeftToDown = 2;
                                    if (iLeftToUp > 0)
                                        iUpToDown = 4;//Two turns - player can go around box in 4 steps
                                }
                        }
                        if (iRight != MT_BLOCKED)
                        {//By analogue...
                            if (iUp != MT_BLOCKED)
                                if ((uTempLevel.bCells[x + 1, y - 1] & SokoCell.MaskObstacle) == 0) iRightToUp = 2;
                            if (iDown != MT_BLOCKED)
                                if ((uTempLevel.bCells[x + 1, y + 1] & SokoCell.MaskObstacle) == 0)
                                {
                                    iRightToDown = 2;
                                    if (iRightToUp > 0)
                                        iUpToDown = 4;//Two turns - player can go around box in 4 steps
                                }
                        }

                        //Check left-to-right pass in two-turn-combo and three-turn-combo
                        if (iRightToUp > 0 && iLeftToUp > 0)
                        {//Can go right-to-up and from up-to-left -> can go right-to-left in 4 steps
                            iLeftToRight = 4;
                            if (iRightToDown > 0)
                                iLeftToDown = 6;//Also can go right-to-down -> can go left-to-down is 6 steps (if not yet)
                            else if (iLeftToDown > 0)
                                iRightToDown = 6;//Also can go left-to-down -> can go right-to-down in 6 steps (if not yet)
                        }
                        else if (iRightToDown == 2 && iLeftToDown == 2)
                        {//By analogue...
                            iLeftToRight = 4;
                            if (iRightToUp > 0)
                                iLeftToUp = 6;
                            else if (iLeftToUp > 0)
                                iRightToUp = 6;
                        }

                        if (iLeftToRight == MT_NOT_REACHED || iLeftToUp == MT_NOT_REACHED || iLeftToDown == MT_NOT_REACHED)
                        {//Some left-to is not yet calculated - can calculate them only by player move tree
                            uTempLevel.BuildPlayerMoveTree(x - 1, y);//Build player move tree from left to box
                            iLeftToRight = uTempLevel.iMoveTree[x + 1, y];//And get reachability from player move tree
                            iLeftToUp = uTempLevel.iMoveTree[x, y - 1];
                            iLeftToDown = uTempLevel.iMoveTree[x, y + 1];
                        }

                        if (iRightToDown == MT_NOT_REACHED || iRightToUp == MT_NOT_REACHED)
                        {//By analogue...
                            uTempLevel.BuildPlayerMoveTree(x + 1, y);//from right
                            iRightToDown = uTempLevel.iMoveTree[x, y + 1];
                            iRightToUp = uTempLevel.iMoveTree[x, y - 1];
                        }

                        if (iUpToDown == MT_NOT_REACHED)
                        {//By analogue... up-to-down is still unknown
                            uTempLevel.BuildPlayerMoveTree_UpTo(x, y + 1, x, y - 1);//from up only to down
                            iUpToDown = uTempLevel.iMoveTree[x, y - 1];
                        }

                        //Set flags of possiblity to walk by paths around box
                        if (iLeftToDown > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_DOWN_TO_LEFT;
                        if (iLeftToRight > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_LEFT_TO_RIGHT;
                        if (iLeftToUp > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_UP_TO_LEFT;
                        if (iRightToDown > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_DOWN_TO_RIGHT;
                        if (iRightToUp > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_UP_TO_RIGHT;
                        if (iUpToDown > 0) iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_UP_TO_DOWN;

                        //Remove box
                        uTempLevel.bCells[x, y] ^= SokoCell.Box;
                    }
                }

            //Stage 2. Build box move tree

            //Propagating tree to all cells - by checking cells, received from queue and adding new cells to this queue
            x = 0; y = 0;
            while (uQueue.Get(ref x, ref y))//Get next cell from queue
            {
                if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_TO_CHECK) != 0)
                {
                    //If cell is marked as required to check (i.e. was marked but not yet checked since that)

                    if (iBoxMoveTree[x, y, PLAYER_TO_RIGHT] >= 0)
                    {//To-right is achived
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_DOWN_TO_RIGHT) != 0 && iBoxMoveTree[x, y, PLAYER_TO_DOWN] == MT_NOT_REACHED)
                        {//Right-to-down is possible and to-down is not achived - we can go around box and achive to-down
                            iBoxMoveTree[x, y, PLAYER_TO_DOWN] = 0;//To-down now achived
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_LEFT_TO_RIGHT) != 0 && iBoxMoveTree[x, y, PLAYER_TO_LEFT] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_LEFT] = 0;//By analogue...
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_RIGHT) != 0 && iBoxMoveTree[x, y, PLAYER_TO_UP] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_UP] = 0;//By analogue...
                        }
                    }
                    if (iBoxMoveTree[x, y, PLAYER_TO_LEFT] >= 0)
                    {//By analogue...
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_DOWN_TO_LEFT) != 0 && iBoxMoveTree[x, y, PLAYER_TO_DOWN] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_DOWN] = 0;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_LEFT_TO_RIGHT) != 0 && iBoxMoveTree[x, y, PLAYER_TO_RIGHT] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_RIGHT] = 0;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_LEFT) != 0 && iBoxMoveTree[x, y, PLAYER_TO_UP] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_UP] = 0;
                        }
                    }
                    if (iBoxMoveTree[x, y, PLAYER_TO_UP] >= 0)
                    {//By analogue...
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_DOWN) != 0 && iBoxMoveTree[x, y, PLAYER_TO_DOWN] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_DOWN] = 0;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_LEFT) != 0 && iBoxMoveTree[x, y, PLAYER_TO_LEFT] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_LEFT] = 0;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_RIGHT) != 0 && iBoxMoveTree[x, y, PLAYER_TO_RIGHT] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_RIGHT] = 0;
                        }
                    }
                    if (iBoxMoveTree[x, y, PLAYER_TO_DOWN] >= 0)
                    {//By analogue...
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_DOWN_TO_LEFT) != 0 && iBoxMoveTree[x, y, PLAYER_TO_LEFT] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_LEFT] = 0;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_DOWN_TO_RIGHT) != 0 && iBoxMoveTree[x, y, PLAYER_TO_RIGHT] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_RIGHT] = 0;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_DOWN) != 0 && iBoxMoveTree[x, y, PLAYER_TO_UP] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_UP] = 0;
                        }
                    }

                    if (iBoxMoveTree[x, y, PLAYER_TO_RIGHT] >= 0)
                    {//To-right is achived
                        if (iBoxMoveTree[x - 1, y, PLAYER_TO_RIGHT] == MT_NOT_REACHED) //To-right for cell to left is not achived - we can push box to left there
                        {
                            iBoxMoveTree[x - 1, y, PLAYER_TO_RIGHT] = 0; //To-right for cell to left is now achived
                            iBoxMoveTree[x - 1, y, BMT_FLAGS] |= BMTF_TO_CHECK;//Mark cell to left for further checking
                            uQueue.AddNext(x - 1, y);//Add cell to left into queue
                        }
                    }
                    if (iBoxMoveTree[x, y, PLAYER_TO_LEFT] >= 0)
                    {//By analogue...
                        if (iBoxMoveTree[x + 1, y, PLAYER_TO_LEFT] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x + 1, y, PLAYER_TO_LEFT] = 0;
                            iBoxMoveTree[x + 1, y, BMT_FLAGS] |= BMTF_TO_CHECK;
                            uQueue.AddNext(x + 1, y);
                        }
                    }
                    if (iBoxMoveTree[x, y, PLAYER_TO_UP] >= 0)
                    {//By analogue...
                        if (iBoxMoveTree[x , y+1, PLAYER_TO_UP] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x , y+1, PLAYER_TO_UP] = 0;
                            iBoxMoveTree[x , y+1, BMT_FLAGS] |= BMTF_TO_CHECK;
                            uQueue.AddNext(x , y+1);
                        }
                    }
                    if (iBoxMoveTree[x, y, PLAYER_TO_DOWN] >= 0)
                    {//By analogue...
                        if (iBoxMoveTree[x , y-1, PLAYER_TO_DOWN] == MT_NOT_REACHED)
                        {
                            iBoxMoveTree[x , y-1, PLAYER_TO_DOWN] = 0;
                            iBoxMoveTree[x , y-1, BMT_FLAGS] |= BMTF_TO_CHECK;
                            uQueue.AddNext(x , y-1);
                        }
                    }
                    iBoxMoveTree[x, y, BMT_FLAGS] &= BMTF_MASK_CLEAR_TOCHECK;//This cell is checked - it should not be checked again, until not marked again
                }
            }

            uQueue.Reset();//Clean queue

            //Stage 3. Mark all targets on level as non-cell-deadlocks

            //For all cells of level
            for (y = 1; y < (iYsize-1); y++)
                for (x = 1; x < (iXsize-1); x++)
                {
                    if ((bCells[x, y] & SokoCell.Target)!=0)
                    {//If cell contain target

                        uQueue.AddNext(x, y);//Add cell to queue for checking
                        iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_TO_CHECK;//Mark cell for further checking
                        for (z = 0; z < 4; z++)
                            if (iBoxMoveTree[x, y, z] >= 0)//If branch is achived by tree
                                iBoxMoveTree[x, y, z] |= MT_BACKWAVE_REACH;//Mark cell for backwave

                    }
                    if ((bCells[x, y] & SokoCell.Box) != 0)
                    {//If cell contain box

                        uQueue.AddNext(x, y);//Add cell to queue for checking
                        iBoxMoveTree[x, y, BMT_FLAGS] |= BMTF_TO_CHECK;//Mark cell for further checking
                        for (z = 0; z < 4; z++)
                            if (iBoxMoveTree[x, y, z] >= 0)//If branch is achived by tree
                                iBoxMoveTree[x, y, z] |= MT_FRONTWAVE_REACH;//Mark cell for frontwave

                    }
                }

            //Stage 4. Propagate backward and forward waves by box move tree connections

            //Propagating - by checking cells, received from queue and adding new cells to this queue
            x = 0; y = 0;
            while (uQueue.Get(ref x, ref y))//Get next cell from queue
            {
                if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_TO_CHECK) != 0)
                {
                    //If cell is marked as required to check (i.e. was marked but not yet checked since that)

                    //4.1 - backwave
                    if ((iBoxMoveTree[x, y, PLAYER_TO_RIGHT] & MT_CHECK_BACKWAVE) == MT_BACKWAVE_REACH)
                    {//To-right is non-cell-deadlock
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_DOWN_TO_RIGHT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_DOWN] & MT_CHECK_BACKWAVE) == 0)
                        {//Right-to-down is possible and to-down is achived - we can go around box and achive to-down
                            iBoxMoveTree[x, y, PLAYER_TO_DOWN] |= MT_BACKWAVE_REACH;//To-down now non-cell-deadlock
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_LEFT_TO_RIGHT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_LEFT] & MT_CHECK_BACKWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_LEFT] |= MT_BACKWAVE_REACH;//By analogue...
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_RIGHT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_UP] & MT_CHECK_BACKWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_UP] |= MT_BACKWAVE_REACH;//By analogue...
                        }
                    }
                    if ((iBoxMoveTree[x, y, PLAYER_TO_LEFT] & MT_CHECK_BACKWAVE) == MT_BACKWAVE_REACH)
                    {//By analogue...
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_DOWN_TO_LEFT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_DOWN] & MT_CHECK_BACKWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_DOWN] |= MT_BACKWAVE_REACH;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_LEFT_TO_RIGHT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_RIGHT] & MT_CHECK_BACKWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_RIGHT] |= MT_BACKWAVE_REACH;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_LEFT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_UP] & MT_CHECK_BACKWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_UP] |= MT_BACKWAVE_REACH;
                        }
                    }
                    if ((iBoxMoveTree[x, y, PLAYER_TO_UP] & MT_CHECK_BACKWAVE) == MT_BACKWAVE_REACH)
                    {//By analogue...
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_DOWN) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_DOWN] & MT_CHECK_BACKWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_DOWN] |= MT_BACKWAVE_REACH;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_LEFT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_LEFT] & MT_CHECK_BACKWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_LEFT] |= MT_BACKWAVE_REACH;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_RIGHT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_RIGHT] & MT_CHECK_BACKWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_RIGHT] |= MT_BACKWAVE_REACH;
                        }
                    }
                    if ((iBoxMoveTree[x, y, PLAYER_TO_DOWN] & MT_CHECK_BACKWAVE) == MT_BACKWAVE_REACH)
                    {//By analogue...
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_DOWN_TO_LEFT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_LEFT] & MT_CHECK_BACKWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_LEFT] |= MT_BACKWAVE_REACH;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_DOWN_TO_RIGHT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_RIGHT] & MT_CHECK_BACKWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_RIGHT] |= MT_BACKWAVE_REACH;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_DOWN) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_UP] & MT_CHECK_BACKWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_UP] |= MT_BACKWAVE_REACH;
                        }
                    }

                    if ((iBoxMoveTree[x, y, PLAYER_TO_RIGHT] & MT_CHECK_BACKWAVE) == MT_BACKWAVE_REACH)
                    {//To-right is non-cell-deadlock
                        if ((iBoxMoveTree[x + 1, y, PLAYER_TO_RIGHT] & MT_CHECK_BACKWAVE) == 0) //To-right for cell to right is achived - we can push box from there to here (to left), so cell to right is also non-cell-deadlock
                        {
                            iBoxMoveTree[x + 1, y, PLAYER_TO_RIGHT] |= MT_BACKWAVE_REACH;//To-right for cell to right is non-cell-deadlock now
                            iBoxMoveTree[x + 1, y, BMT_FLAGS] |= BMTF_TO_CHECK;//Mark cell to right for further checking
                            uQueue.AddNext(x + 1, y);//Add cell to right into queue
                        }
                    }
                    if ((iBoxMoveTree[x, y, PLAYER_TO_LEFT] & MT_CHECK_BACKWAVE) == MT_BACKWAVE_REACH)
                    {//By analogue...
                        if ((iBoxMoveTree[x - 1, y, PLAYER_TO_LEFT] & MT_CHECK_BACKWAVE) == 0)
                        {
                            iBoxMoveTree[x - 1, y, PLAYER_TO_LEFT] |= MT_BACKWAVE_REACH;
                            iBoxMoveTree[x - 1, y, BMT_FLAGS] |= BMTF_TO_CHECK;
                            uQueue.AddNext(x - 1, y);
                        }
                    }
                    if ((iBoxMoveTree[x, y, PLAYER_TO_UP] & MT_CHECK_BACKWAVE) == MT_BACKWAVE_REACH)
                    {//By analogue...
                        if ((iBoxMoveTree[x, y - 1, PLAYER_TO_UP] & MT_CHECK_BACKWAVE) == 0)
                        {
                            iBoxMoveTree[x, y - 1, PLAYER_TO_UP] |= MT_BACKWAVE_REACH;
                            iBoxMoveTree[x, y - 1, BMT_FLAGS] |= BMTF_TO_CHECK;
                            uQueue.AddNext(x, y - 1);
                        }
                    }
                    if ((iBoxMoveTree[x, y, PLAYER_TO_DOWN] & MT_CHECK_BACKWAVE) == MT_BACKWAVE_REACH)
                    {//By analogue...
                        if ((iBoxMoveTree[x, y + 1, PLAYER_TO_DOWN] & MT_BACKWAVE_REACH) == 0)
                        {
                            iBoxMoveTree[x, y + 1, PLAYER_TO_DOWN] |= MT_BACKWAVE_REACH;
                            iBoxMoveTree[x, y + 1, BMT_FLAGS] |= BMTF_TO_CHECK;
                            uQueue.AddNext(x, y + 1);
                        }
                    }

                    //4.2 - frontwave
                    if ((iBoxMoveTree[x, y, PLAYER_TO_RIGHT] & MT_CHECK_FRONTWAVE) == MT_FRONTWAVE_REACH)
                    {//To-right is non-cell-deadlock
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_DOWN_TO_RIGHT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_DOWN] & MT_CHECK_FRONTWAVE) == 0)
                        {//Right-to-down is possible and to-down is achived - we can go around box and achive to-down
                            iBoxMoveTree[x, y, PLAYER_TO_DOWN] |= MT_FRONTWAVE_REACH;//To-down now non-cell-deadlock
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_LEFT_TO_RIGHT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_LEFT] & MT_CHECK_FRONTWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_LEFT] |= MT_FRONTWAVE_REACH;//By analogue...
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_RIGHT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_UP] & MT_CHECK_FRONTWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_UP] |= MT_FRONTWAVE_REACH;//By analogue...
                        }
                    }
                    if ((iBoxMoveTree[x, y, PLAYER_TO_LEFT] & MT_CHECK_FRONTWAVE) == MT_FRONTWAVE_REACH)
                    {//By analogue...
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_DOWN_TO_LEFT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_DOWN] & MT_CHECK_FRONTWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_DOWN] |= MT_FRONTWAVE_REACH;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_LEFT_TO_RIGHT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_RIGHT] & MT_CHECK_FRONTWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_RIGHT] |= MT_FRONTWAVE_REACH;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_LEFT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_UP] & MT_CHECK_FRONTWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_UP] |= MT_FRONTWAVE_REACH;
                        }
                    }
                    if ((iBoxMoveTree[x, y, PLAYER_TO_UP] & MT_CHECK_FRONTWAVE) == MT_FRONTWAVE_REACH)
                    {//By analogue...
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_DOWN) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_DOWN] & MT_CHECK_FRONTWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_DOWN] |= MT_FRONTWAVE_REACH;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_LEFT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_LEFT] & MT_CHECK_FRONTWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_LEFT] |= MT_FRONTWAVE_REACH;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_RIGHT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_RIGHT] & MT_CHECK_FRONTWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_RIGHT] |= MT_FRONTWAVE_REACH;
                        }
                    }
                    if ((iBoxMoveTree[x, y, PLAYER_TO_DOWN] & MT_CHECK_FRONTWAVE) == MT_FRONTWAVE_REACH)
                    {//By analogue...
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_DOWN_TO_LEFT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_LEFT] & MT_CHECK_FRONTWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_LEFT] |= MT_FRONTWAVE_REACH;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_DOWN_TO_RIGHT) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_RIGHT] & MT_CHECK_FRONTWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_RIGHT] |= MT_FRONTWAVE_REACH;
                        }
                        if ((iBoxMoveTree[x, y, BMT_FLAGS] & BMTF_UP_TO_DOWN) != 0 && (iBoxMoveTree[x, y, PLAYER_TO_UP] & MT_CHECK_FRONTWAVE) == 0)
                        {
                            iBoxMoveTree[x, y, PLAYER_TO_UP] |= MT_FRONTWAVE_REACH;
                        }
                    }

                    if ((iBoxMoveTree[x, y, PLAYER_TO_RIGHT] & MT_CHECK_FRONTWAVE) == MT_FRONTWAVE_REACH)
                    {//To-right is non-cell-deadlock
                        if ((iBoxMoveTree[x - 1, y, PLAYER_TO_RIGHT] & MT_CHECK_FRONTWAVE) == 0) //To-right for cell to right is achived - we can push box from here to there (to right)
                        {
                            iBoxMoveTree[x - 1, y, PLAYER_TO_RIGHT] |= MT_FRONTWAVE_REACH;//To-right for cell to right is non-cell-deadlock now
                            iBoxMoveTree[x - 1, y, BMT_FLAGS] |= BMTF_TO_CHECK;//Mark cell to right for further checking
                            uQueue.AddNext(x - 1, y);//Add cell to right into queue
                        }
                    }
                    if ((iBoxMoveTree[x, y, PLAYER_TO_LEFT] & MT_CHECK_FRONTWAVE) == MT_FRONTWAVE_REACH)
                    {//By analogue...
                        if ((iBoxMoveTree[x + 1, y, PLAYER_TO_LEFT] & MT_CHECK_FRONTWAVE) == 0)
                        {
                            iBoxMoveTree[x + 1, y, PLAYER_TO_LEFT] |= MT_FRONTWAVE_REACH;
                            iBoxMoveTree[x + 1, y, BMT_FLAGS] |= BMTF_TO_CHECK;
                            uQueue.AddNext(x + 1, y);
                        }
                    }
                    if ((iBoxMoveTree[x, y, PLAYER_TO_UP] & MT_CHECK_FRONTWAVE) == MT_FRONTWAVE_REACH)
                    {//By analogue...
                        if ((iBoxMoveTree[x, y + 1, PLAYER_TO_UP] & MT_CHECK_FRONTWAVE) == 0)
                        {
                            iBoxMoveTree[x, y + 1, PLAYER_TO_UP] |= MT_FRONTWAVE_REACH;
                            iBoxMoveTree[x, y + 1, BMT_FLAGS] |= BMTF_TO_CHECK;
                            uQueue.AddNext(x, y + 1);
                        }
                    }
                    if ((iBoxMoveTree[x, y, PLAYER_TO_DOWN] & MT_CHECK_FRONTWAVE) == MT_FRONTWAVE_REACH)
                    {//By analogue...
                        if ((iBoxMoveTree[x, y - 1, PLAYER_TO_DOWN] & MT_FRONTWAVE_REACH) == 0)
                        {
                            iBoxMoveTree[x, y - 1, PLAYER_TO_DOWN] |= MT_FRONTWAVE_REACH;
                            iBoxMoveTree[x, y - 1, BMT_FLAGS] |= BMTF_TO_CHECK;
                            uQueue.AddNext(x, y - 1);
                        }
                    }

                    iBoxMoveTree[x, y, BMT_FLAGS] &= BMTF_MASK_CLEAR_TOCHECK;//This cell is checked - it should not be checked again, until not marked again
                }
            }

            //Stage 5. Convert all non-cell-deadlocks from box move tree into cell markers

            //For all cells of level
            for (y = 0; y < iYsize; y++)
                for (x = 0; x < iXsize; x++)
                {
                    for (z = 0; z < 4; z++)//For all positions of player around box on this cell
                        if (iBoxMoveTree[x, y, z] == MT_BOTHWAVE_REACH)//If at least one direction is reached by both waves, then whole cell is not cell-deadlock
                        //if ((iBoxMoveTree[x, y, z] & MT_CHECK_BACKWAVE) == MT_BACKWAVE_REACH)
                            goto lSkip;//Skip marking cell
                    bCells[x, y] |= SokoCell.CellDeadlock;//All cells, that was not reached by both waves - is cell-deadlocks
                lSkip: ;
                }

            return FunctionResult.OK;
        }
Esempio n. 3
0
        ///<summary>Wave algorithm of building player moving tree till specific cell is reached (x, y of start, x, y of target)</summary>
        private FunctionResult BuildPlayerMoveTree_UpTo(int iXstart, int iYstart, int iXend, int iYend)
        {
            short iDepth;
            int x, y;

            if (iMoveTreeFromX == iXstart && iMoveTreeFromY == iYstart)
                return FunctionResult.NothingToDo;//Tree is already build from exact the same location

            InvalidatePlayerMoveTree();//Flush old tree root
            iMoveTree = new short[iXsize, iYsize];//(Re)create array for tree
            CoordQueue uQueue = new CoordQueue();

            //Initiate array
            for (int i = 0; i < iXsize; i++)
                for (int j = 0; j < iYsize; j++)
                {
                    /*
                    if ((bCells[i, j] & SokoCell.Obstacle) == 0)
                    {
                        iMoveTree[i, j] = MT_NOT_REACHED;
                    }
                    else
                    {
                        iMoveTree[i, j] = MT_BLOCKED;
                    }*/

                    if ((bCells[i, j] & SokoCell.MaskObstacle) != 0 || i == 0 || i == (iXsize - 1) || j == 0 || j == (iYsize - 1))
                    {//Obstacle on cell or border cell (topmost, bottommost, leftmost and rightmost lines of level MUST contain ONLY walls or backgrounds, so box move tree should not reach them)
                        iMoveTree[i, j] = MT_BLOCKED;
                    }
                    else
                    {//Other cells - could be reached
                        iMoveTree[i, j] = MT_NOT_REACHED;
                    }
                }
            if (iMoveTree[iXstart, iYstart] == MT_BLOCKED)
                return FunctionResult.StartIsBlocked;//Start is blocked, so no tree

            iMoveTree[iXstart, iYstart] = 0;//Start pos

            uQueue.AddNext(iXstart, iYstart);//Add root of tree to queue
            x = 0; y = 0; //Initiate x and y, otherwise not compiled

            //Propagating tree to all cells - by checking cells, received from queue and adding new cells to this queue
            while (uQueue.Get(ref x, ref y))
            {
                if (x == iXend)
                {
                    if (y == iYend)
                    {//Specified cell is reached - can exit
                        return FunctionResult.PathFound;
                    }
                }
                iDepth = iMoveTree[x, y]; iDepth++;//Get depth from cell and increment
                if (iMoveTree[x - 1, y] == MT_NOT_REACHED) { iMoveTree[x - 1, y] = iDepth; uQueue.AddNext(x - 1, y); }//Propagate tree for nearest cells if tree is not yet reached this cells
                if (iMoveTree[x + 1, y] == MT_NOT_REACHED) { iMoveTree[x + 1, y] = iDepth; uQueue.AddNext(x + 1, y); }
                if (iMoveTree[x, y - 1] == MT_NOT_REACHED) { iMoveTree[x, y - 1] = iDepth; uQueue.AddNext(x, y - 1); }
                if (iMoveTree[x, y + 1] == MT_NOT_REACHED) { iMoveTree[x, y + 1] = iDepth; uQueue.AddNext(x, y + 1); }
            }

            //Tree Builded

            //Root location is not stored

            return FunctionResult.OK;
        }