Пример #1
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;
        }
Пример #2
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;
        }