Пример #1
0
 ///<summary>Result retrieving</summary>
 public void GetResults(SokobanGame uDestinationGame)
 {
     uDestinationGame.DownloadDeadlocks(uTempGame);
     //uMainGame.Xdeadlocks
 }
Пример #2
0
 ///<summary>Provide info about game(source game - to copy)</summary>
 public void PleaseGetGame(SokobanGame uSourceGame)
 {
     uTempGame = new SokobanGame(uSourceGame);
 }
Пример #3
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;
        }
Пример #4
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;
        }
Пример #5
0
        ///<summary>Build reverted route of box pushing to specific cell (x,y of destination, route to add)</summary>
        private MoveResult BoxTravelRoute(int iXdest, int iYdest, SokobanGame uRoute)
        {
            //Box move tree must be build before calling

            int z;
            int iDir = -1, iDirPre;
            MoveResult uRv;

            //Matrix of paths
            short[,] iMatrix = new short[4, 4];
            iMatrix[PLAYER_TO_DOWN, PLAYER_TO_DOWN] = 0;
            iMatrix[PLAYER_TO_DOWN, PLAYER_TO_LEFT] = BMTF_DOWN_TO_LEFT;
            iMatrix[PLAYER_TO_DOWN, PLAYER_TO_RIGHT] = BMTF_DOWN_TO_RIGHT;
            iMatrix[PLAYER_TO_DOWN, PLAYER_TO_UP] = BMTF_UP_TO_DOWN;
            iMatrix[PLAYER_TO_LEFT, PLAYER_TO_DOWN] = BMTF_DOWN_TO_LEFT;
            iMatrix[PLAYER_TO_LEFT, PLAYER_TO_LEFT] = 0;
            iMatrix[PLAYER_TO_LEFT, PLAYER_TO_RIGHT] = BMTF_LEFT_TO_RIGHT;
            iMatrix[PLAYER_TO_LEFT, PLAYER_TO_UP] = BMTF_UP_TO_LEFT;
            iMatrix[PLAYER_TO_RIGHT, PLAYER_TO_DOWN] = BMTF_DOWN_TO_RIGHT;
            iMatrix[PLAYER_TO_RIGHT, PLAYER_TO_LEFT] = BMTF_LEFT_TO_RIGHT;
            iMatrix[PLAYER_TO_RIGHT, PLAYER_TO_RIGHT] = 0;
            iMatrix[PLAYER_TO_RIGHT, PLAYER_TO_UP] = BMTF_UP_TO_RIGHT;
            iMatrix[PLAYER_TO_UP, PLAYER_TO_DOWN] = BMTF_UP_TO_DOWN;
            iMatrix[PLAYER_TO_UP, PLAYER_TO_LEFT] = BMTF_UP_TO_LEFT;
            iMatrix[PLAYER_TO_UP, PLAYER_TO_RIGHT] = BMTF_UP_TO_RIGHT;
            iMatrix[PLAYER_TO_UP, PLAYER_TO_UP] = 0;

            int x = iXdest;
            int y = iYdest;
            if (!IsCellAchivedByBoxMoveTree(x, y))
                return MoveResult.WayBlocked; //Destination is unreachable for current box moving tree

            //Find cell around destination with minimum value - there player will stop after pushing box
            int iValue = short.MaxValue;
            for (z = 0; z < 4; z++)
                if (iBoxMoveTree[x, y, z] < iValue && iBoxMoveTree[x, y, z] >= 0)
                {
                    iDir = z;
                    iValue = iBoxMoveTree[x, y, z];
                }

            if (iValue == 0 || iDir == -1)
            {
                return MoveResult.WayBlocked; //If no cell found - destination is unreachable
            }

            //int iMoveLen = iValue;
            SokobanGame uTempLevel = new SokobanGame(this);//Create temprorary level for pathfinding

            //Remove from temp-level: player and box-beeing-moved
            uTempLevel.bCells[iPlayerX, iPlayerY] ^= SokoCell.Player;
            uTempLevel.bCells[iBoxMoveTreeFromX, iBoxMoveTreeFromY] ^= SokoCell.Box;

            //Build reverted route
            lLoop1:

            //Check pushing box
            switch (iDir)
            {
                case PLAYER_TO_DOWN:
                    y++;//Player to down, so he push box to up to reach this state
                    if (iBoxMoveTree[x, y, iDir] > iValue || iBoxMoveTree[x, y, iDir] < 0)
                    {//Player is on cell with incorrect value, something wrong or route is completed
                        y--;//Return player
                        goto lEnd;//Exit building route
                    }
                    uRoute.AddNextRevertedMove(SokoMove.Up | SokoMove.Push);//Add push-to-up to reverted route
                    break;
                case PLAYER_TO_UP://By analogue...
                    y--;
                    if (iBoxMoveTree[x, y, iDir] > iValue || iBoxMoveTree[x, y, iDir] < 0)
                    {
                        y++;
                        goto lEnd;
                    }
                    uRoute.AddNextRevertedMove(SokoMove.Down | SokoMove.Push);
                    break;
                case PLAYER_TO_LEFT:
                    x--;
                    if (iBoxMoveTree[x, y, iDir] > iValue || iBoxMoveTree[x, y, iDir] < 0)
                    {
                        x++;
                        goto lEnd;
                    }
                    uRoute.AddNextRevertedMove(SokoMove.Right | SokoMove.Push);
                    break;
                case PLAYER_TO_RIGHT:
                    x++;
                    if (iBoxMoveTree[x, y, iDir] > iValue || iBoxMoveTree[x, y, iDir] < 0)
                    {
                        x--;
                        goto lEnd;
                    }
                    uRoute.AddNextRevertedMove(SokoMove.Left | SokoMove.Push);
                    break;
                default://Unknown direction - something wrong
                    goto lEnd;
            }

            if (x == iBoxMoveTreeFromX && y == iBoxMoveTreeFromY)
            {//Box is in place - root of box move tree
                if (bBoxMoveTreeRootDirections[iDir])
                {   //This location of player is reachable from start
                    goto lEnd;
                }
            }

            iValue = iBoxMoveTree[x, y, iDir];//Update value to current box-move-tree cell (added 20.10.2008 to fix bug with additional moves after reaching box)
            iDirPre = iDir;//Store direction of pushing to compare later

            //Find cell around box with lesser value on box-move-tree than current - if found, player should move there (around box or by complex path) to proceed (reverted) pushing
            for (z = 0; z < 4; z++)//Loop on directions
                if (iBoxMoveTree[x, y, z] < iValue && iBoxMoveTree[x, y, z] >= 0)//Cell with better value (than current)
                    //if (z == iDirPre || (iMatrix[z, iDirPre] & iBoxMoveTree[x, y, BMT_FLAGS]) != 0)//This cell can be reached from current by moving around box (or this is current cell)
                    if ((iMatrix[z, iDirPre] & iBoxMoveTree[x, y, BMT_FLAGS]) != 0)//This cell can be reached from current by moving around box (current cell may not pass previous "if")
                    {
                        iDir = z;//Store new diection
                        iValue = iBoxMoveTree[x, y, z];//Store new value
                    }

            if (iDir != iDirPre)
            {//New direction is differ from previous - should build moving route around box (otherwise - go to pushing)

                //Set box to temp. level to use pathfinding around this box
                uTempLevel.bCells[x, y] ^= SokoCell.Box;
                uRv = MoveResult.WayBlocked;

                uTempLevel.InvalidatePlayerMoveTree();//Flush player move tree

                //Set player location for start of path finding - new cell near box
                uTempLevel.iPlayerX = x; uTempLevel.iPlayerY = y;
                switch (iDir)
                {
                    case PLAYER_TO_DOWN: uTempLevel.iPlayerY++; break;
                    case PLAYER_TO_UP: uTempLevel.iPlayerY--; break;
                    case PLAYER_TO_LEFT: uTempLevel.iPlayerX--; break;
                    case PLAYER_TO_RIGHT: uTempLevel.iPlayerX++; break;
                }

                //Find path from new cell to previous
                switch (iDirPre)
                {
                    case PLAYER_TO_DOWN: uRv = uTempLevel.PlayerTravelRoute(x, y + 1, uRoute, true); break;
                    case PLAYER_TO_UP: uRv = uTempLevel.PlayerTravelRoute(x, y - 1, uRoute, true); break;
                    case PLAYER_TO_LEFT: uRv = uTempLevel.PlayerTravelRoute(x - 1, y, uRoute, true); break;
                    case PLAYER_TO_RIGHT: uRv = uTempLevel.PlayerTravelRoute(x + 1, y, uRoute, true); break;
                }

                //If no path - something wrong
                if (uRv == MoveResult.WayBlocked)
                    return uRv;

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

            goto lLoop1;//Go to next push

            lEnd:
            if (x != iBoxMoveTreeFromX || y != iBoxMoveTreeFromY)
                return MoveResult.WayBlocked; //if box not reach root of tree - path not builded

            //Need to find path for player to box

            //Set box to temp. level to use pathfinding around this box
            uTempLevel.bCells[x, y] ^= SokoCell.Box;
            uRv = MoveResult.WayBlocked;

            uTempLevel.InvalidatePlayerMoveTree();//Flush player move tree
            uTempLevel.iPlayerX = iPlayerX; uTempLevel.iPlayerY = iPlayerY;//Set player start location - get it from actual level
            switch (iDir)//Find path
            {
                case PLAYER_TO_DOWN: uRv = uTempLevel.PlayerTravelRoute(x, y + 1, uRoute, true); break;
                case PLAYER_TO_UP: uRv = uTempLevel.PlayerTravelRoute(x, y - 1, uRoute, true); break;
                case PLAYER_TO_LEFT: uRv = uTempLevel.PlayerTravelRoute(x - 1, y, uRoute, true); break;
                case PLAYER_TO_RIGHT: uRv = uTempLevel.PlayerTravelRoute(x + 1, y, uRoute, true); break;
            }

            if (uRv == MoveResult.WayBlocked)
                return uRv;//No path - something wring

            //Reverted route builded
            return MoveResult.MovedAndPushBox;
        }
Пример #6
0
        ///<summary>Build reverted route of player moving to specific cell (x,y of destination, route to add, build short tree or full)</summary>
        private MoveResult PlayerTravelRoute(int iXdest, int iYdest, SokobanGame uRoute, bool bUseShortTree)
        {
            if (iPlayerX == iXdest && iPlayerY == iYdest)
                return MoveResult.Moved;//Player already there - nothing to do

            if (bUseShortTree)
            {//Using short tree - only to reach destination
                BuildPlayerMoveTree_UpTo(iPlayerX, iPlayerY, iXdest, iYdest);
            }
            else
            {//Using full tree - for all level
                BuildPlayerMoveTree(iPlayerX, iPlayerY);
            }
            int iMoveLen = iMoveTree[iXdest, iYdest];

            if (iMoveLen < 0)
                return MoveResult.WayBlocked;//Negative values - destination unreachable

            //Building reverted route from destination to start
            int x = iXdest; int y = iYdest;
            int iValue = iMoveLen;
            while (iValue > 0)
            {//Find nearest cell thet have value less then iValue and move player there
                if (iMoveTree[x - 1, y] >= 0 && iMoveTree[x - 1, y] < iValue) { iValue = iMoveTree[x - 1, y]; uRoute.AddNextRevertedMove(SokoMove.Right); x--; continue; }
                if (iMoveTree[x + 1, y] >= 0 && iMoveTree[x + 1, y] < iValue) { iValue = iMoveTree[x + 1, y]; uRoute.AddNextRevertedMove(SokoMove.Left); x++; continue; }
                if (iMoveTree[x, y - 1] >= 0 && iMoveTree[x, y - 1] < iValue) { iValue = iMoveTree[x, y - 1]; uRoute.AddNextRevertedMove(SokoMove.Down); y--; continue; }
                if (iMoveTree[x, y + 1] >= 0 && iMoveTree[x, y + 1] < iValue) { iValue = iMoveTree[x, y + 1]; uRoute.AddNextRevertedMove(SokoMove.Up); y++; continue; }
                return MoveResult.WayBlocked;//Failed to travel (something very wrong)
            }
            return MoveResult.Moved;
        }
Пример #7
0
        /*
        ///<summary>Load position from file (filename, levelset name, level number, force loading level/set)</summary>
        public FunctionResult LoadPosition(string sFileName, ref string sLevelSet, ref int iLevelNum, bool bForceLoadLevel)
        {
            IniHold.IniFile uIni = new IniHold.IniFile();//IniHold object - to treat position file as ini-file
            uIni.LoadIni(sFileName);//Load file as ini-file

            string sPos = uIni.GetItemValue("Position");//Get sequence of moves

            //If sequence is empty or not present - exit
            if (sPos.Length == 0)
                return FunctionResult.NothingToDo;

            string sQuestion;

            string sFileLevelSet = uIni.GetItemValue("LevelSet","<unknown>").ToLower();
            int iFileLevel = OQConvertTools.string2int(uIni.GetItemValue("Level", "0"));
            iLevelNum++;//Levels numbered from 1 in files

            if (bForceLoadLevel)
            {
            }
            else
            {
                if (sFileLevelSet != sLevelSet || iFileLevel != iLevelNum) //Position may be not for current level - warn user
                {
                    string sLevelNum;
                    if (iFileLevel == 0)
                        sLevelNum = "<unknown> level"; //Level number not specified in file
                    else
                        sLevelNum = "level " + iFileLevel.ToString();//Level number specified
                    if (sFileLevelSet != sLevelSet) //Levelset is different
                        sQuestion = "This position from " + sLevelNum + " of " + sFileLevelSet + " levelset\r\nAre you sure?";
                    else //Levelset is the same, but levelnumber is different
                        sQuestion = "This position from " + sLevelNum + "\r\nAre you sure?";
                    if (MessageBox.Show(sQuestion, "Loading position", MessageBoxButtons.OKCancel, MessageBoxIcon.None, MessageBoxDefaultButton.Button2) == DialogResult.Cancel) //Ask user
                        return FunctionResult.Canceled; //Exit, if user decide so
                }
            }

            sLevelSet = sFileLevelSet;
            iLevelNum = iFileLevel-1;

            int i;
            char[] cLurd = sPos.ToCharArray();

            iMovesNum = 0;//Flush undo stack
            for (i = 0; i < cLurd.Length; i++)//Iterate thru all loaded moves
            {
                //Decode characters into moves
                switch(cLurd[i])
                {
                    case 'l': bMoves[iMovesNum] = SokoMove.Left; break;
                    case 'r': bMoves[iMovesNum] = SokoMove.Right; break;
                    case 'u': bMoves[iMovesNum] = SokoMove.Up; break;
                    case 'd': bMoves[iMovesNum] = SokoMove.Down; break;
                    case 'L': bMoves[iMovesNum] = SokoMove.PushLeft; break;
                    case 'R': bMoves[iMovesNum] = SokoMove.PushRight; break;
                    case 'U': bMoves[iMovesNum] = SokoMove.PushUp; break;
                    case 'D': bMoves[iMovesNum] = SokoMove.PushDown; break;
                    default: continue;//Skip all other
                }

                iMovesNum++;
                if (iMovesNum >= iMovesAlloc)
                    EnlargeStack();//Realloc stack if needed
            }

            return FunctionResult.OK;

        }*/
        ///<summary>Copy deadlocks from other game - in case of background calc</summary>
        public void DownloadDeadlocks(SokobanGame uGameWithDeadlocks)
        {
            for (int i = 0; i < iXsize; i++)
                for (int j = 0; j < iYsize; j++)
                    if ((uGameWithDeadlocks.bCells[i, j] & SokoCell.CellDeadlock)!=0)
                    {
                        bCells[i, j] |= SokoCell.CellDeadlock;
                    }
        }
Пример #8
0
        ///<summary>Save new record into file</summary>
        public FunctionResult SaveNewRecord(SokobanGame uSolution)
        {
            /*
             * All solutions of level are sequentaly save into file (currently)
             * This is kinda log of solving levels
             * On loading all solutions are checked for best ones
             */
            uLevels[iCurrentLevel].CheckSolutionForRecord(uSolution.uStats);//Update records of current level

            //Prepare string for writing into file
            string sSolutionString = iCurrentLevel.ToString("00000");
            sSolutionString += ", ";
            sSolutionString += uSolution.uStats.iMoves.ToString("00000");
            sSolutionString += ", ";
            sSolutionString += uSolution.uStats.iPushes.ToString("00000");
            sSolutionString += ", ";
            sSolutionString += "'" + uSolution.uStats.sName+ "'";

            System.IO.StreamWriter hAppend;//For writing file
            try
            {
                hAppend = new System.IO.StreamWriter(sRecordFile, true);//Open file for append
                hAppend.WriteLine(sSolutionString);//Write string
                hAppend.Close();//Close file
            }
            catch
            {
                return FunctionResult.ErrorOnWritingFile;//Unable to open or write file
            }

            return FunctionResult.OK;//Successfully
        }
Пример #9
0
        ///<summary>Load level to play it (game, level number)</summary>
        public FunctionResult LoadLevel(SokobanGame uDstLevel, int iLevelNumber)
        {
            if (iLevelNumber < 0 || iLevelNumber >= iLevelsNum) return FunctionResult.OutOfLevelSet; //Incorrent number specified

            //if (!bKeepPosition)
            uDstLevel.FlushPosition();//Reset position (undo stack etc.)
            uDstLevel.InvalidateBoxMoveTree();//Reset BMT
            uDstLevel.CopyFrom(uLevels[iLevelNumber]);//Copy level content into game
            uDstLevel.ReAnalyze();//Update level info (box/target counters etc.)
            iCurrentLevel = iLevelNumber;//Store number of loaded level
            return FunctionResult.OK;//Successfully
        }
Пример #10
0
        //<summary>Lock level scrolling</summary>
        //private bool bScrollLock;
        //################################################################################################################
        //Constructor
        ///<summary>Top-level contructor for SokobanCompact</summary>
        public formMain()
        {
            FunctionResult uRV;

            InitializeComponent();

            hGameSkin = null;
            uBackBuffer = null;
            bDeadlockMessage = false;
            bHaveUnfinishedPosition = false;
            Cursor.Current = Cursors.WaitCursor;//Waiting cursor - while loading levelset and skin

            //Get handle of assembly
            hExecAssem = System.Reflection.Assembly.GetExecutingAssembly();
            //Get file name of assembly
            string sAppFilePath = hExecAssem.GetModules()[0].FullyQualifiedName;
            //Get path only
            sApplicationDirectory = System.IO.Path.GetDirectoryName(sAppFilePath);
            //Add delimiter at the end
            if (!sApplicationDirectory.EndsWith(@"\"))
                sApplicationDirectory += @"\";

            //Calc paths for folders
            //sSavesDirectory = sApplicationDirectory + @"Saves\";
            sLevelsDirectory = sApplicationDirectory + @"Levels\";
            sSolutionsDirectory = sApplicationDirectory + @"Solutions\";
            sSkinsDirectory = sApplicationDirectory + @"Skins\";
            sBackgroundsDirectory = sApplicationDirectory + @"Backgrounds\";

            //Try to create all required folders, to not bother in future
            try
            {
                //System.IO.Directory.CreateDirectory(sSavesDirectory);
                System.IO.Directory.CreateDirectory(sBackgroundsDirectory);
                System.IO.Directory.CreateDirectory(sSkinsDirectory);
                System.IO.Directory.CreateDirectory(sSolutionsDirectory);
                System.IO.Directory.CreateDirectory(sLevelsDirectory);
            }
            catch (System.IO.IOException)
            {}//Dont know that to do, if creation fails

            //Calc rectangles on statusbar
            int iX = 3;

            int iStatusHeight = pictureStatus.Height;//Height of status bar
            Graphics uGr1 = CreateGraphics();//Get graphics of current form
            SizeF uCounterSizes = uGr1.MeasureString(" 0000", Font);//Measure sample string for get actual font sizes
            int iCounterWidth = (int)uCounterSizes.Width;//Width of counter - with of sample string
            int iCounterY0 = (int)(iStatusHeight-uCounterSizes.Height)/2;//Text positions - valign center
            int iSpace = iCounterWidth/10;//Space between fields - 10% if counter width
            uGr1.Dispose();//Release graphics of form

            uRectIndic = new Rectangle(iX, (iStatusHeight-16)/2, 16, 16);//for solved/not-solved indicator
            iX += uRectIndic.Width + iSpace;
            uRectMoves = new Rectangle(iX, iCounterY0, iCounterWidth, 16);//for counter of moves
            iX += uRectMoves.Width + iSpace;
            uRectPushes = new Rectangle(iX, iCounterY0, iCounterWidth, 16);//for counter of pushes
            iX += uRectPushes.Width + iSpace;
            uRectMessage = new Rectangle(iX, iCounterY0, ClientRectangle.Width - iX, 16); //all rest space - for non-modal message

            //Font f1 = this.Font;
            //f1.me
            //this.gr
            //Graphic .MeasureString

            //bScrollLock = false;
            bResize = true;
            iBottomOfForm = pictureStatus.Top;//this done here for perform recenter of level before any redraws

            //Create and load settings
            uSetting = new Settings();
            if (uSetting.Load(sApplicationDirectory + sConfigFile) != FunctionResult.OK)
            {
                //Settings not loaded - first start or failure of file
                uSetting = new Settings();//reset to default, just in case...
            }
            menuScrollLock.Checked = uSetting.bScrollLock;

            if (uSetting.bLogActions)
            {
                uLog = new LogFile();
                uLog.Start(sApplicationDirectory + sLogFile);
                uLog.LogString(ActionID.Start, "Started SokobanCompact; v" + hExecAssem.GetName().Version);
            }

            //Load level set list
            uLevelSetList = new SokobanLevelSetList(sApplicationDirectory + sLevelSetList, sLevelsDirectory, sSolutionsDirectory);
            uLevelSetList.LoadList();

            iSkinSize = 0;

            //Load skinset
            uSkinSet = new SkinSet();
            //uSkinSet.Load(sSkinsDirectory + "\\" + "oq.sks");//TODO: move skinset name into Settings
            uSkinSet.Load(sSkinsDirectory + uSetting.sSkinSet);

            if (!uSetting.bAutosize)
            {   //No autosize? Load skin now
                uRV = LoadSkin(sSkinsDirectory + uSetting.sSkin);
                if (iSkinSize == 0)
                {
                    LogSimpleLine(ActionID.ShowDialog, "Error; Failed to load skin, null skin created; " + uSetting.sSkin+"; "+uRV.ToString());
                    MessageBox.Show("Failed to load skin '" + uSetting.sSkin + "' \r\nNull skin will be loaded, " + uRV.ToString(), "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                    GenNullSkin();
                }
            }

            UpdateBackground();//Create background according to settings

            //Create game
            uGame = new SokobanGame();

            //THREAD
            uBackgroundCalc = new BackgroundThread(BackgroundFinished);//Create thread for background

            iSelectorMode = 0;//Selector initialy in "play" mode
            SetToolBarMode();//Refresh selector

            //Load levelset
            uLevelSet = new SokobanLevelSet();
            uRV = uLevelSetList.LoadLevelSet(uLevelSet, uSetting.sLastLevelSet);
            if (uRV != FunctionResult.OK)
            {   //Something happens with levelset file
                LogSimpleLine(ActionID.ShowDialog, "Error; Failed to load levelset, random will be generated; " + uSetting.sLastLevelSet+"; "+uRV.ToString());
                MessageBox.Show("Unable to load LevelSet '" + uSetting.sLastLevelSet + "', result: " + uRV.ToString() + "\r\nRandom level will be loaded.", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                uLevelSetList.GenNullLevelSet(uLevelSet);//Generate levelset with 1 random level
                uSetting.iLastLevelPlayed = 0;//Res
            }

            //Start last played level
            uRV = LoadLevel(uGame, uSetting.iLastLevelPlayed);
            if (uRV == FunctionResult.OK)
            {   //Loaded successfully
                AfterLoadLevel();
            }
            else
            {   //Level not loaded (only variant - FunctionResult.OutOfLevelSet)
                LogSimpleLine(ActionID.ShowDialog, "Error; Failed to load level, random will be choosen; " + uSetting.iLastLevelPlayed.ToString() + "; " + uRV.ToString());
                MessageBox.Show("Unable to load level " + uSetting.iLastLevelPlayed.ToString() + ", result: " + uRV.ToString() + "\r\nRandom level will be selected.", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                ActionRandLevel();
            }

            if (iSkinSize < 1)
            {
                LogSimpleLine(ActionID.ShowDialog, "Error; No skin loaded, null skin created");
                MessageBox.Show("Failed to load skin\r\nNull skin will be loaded", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                GenNullSkin();
                RecenterLevel();
            }

            NonModalMessage(uLevelSet.sTitle + ", " + uGame.sTitle);

            Cursor.Current = Cursors.Default;//remove wait cursor
        }
Пример #11
0
 private FunctionResult LoadLevel(SokobanGame uDstLevel, int iLevelNumber)
 {
     AutosavePosition();
     return uLevelSet.LoadLevel(uDstLevel, iLevelNumber);
 }