/* ///<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; }
///<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; }
///<summary>Wave algorithm of building player moving tree till specific cell is reached (x, y of start, x, y of target)</summary> private FunctionResult BuildPlayerMoveTree_UpTo(int iXstart, int iYstart, int iXend, int iYend) { short iDepth; int x, y; if (iMoveTreeFromX == iXstart && iMoveTreeFromY == iYstart) return FunctionResult.NothingToDo;//Tree is already build from exact the same location InvalidatePlayerMoveTree();//Flush old tree root iMoveTree = new short[iXsize, iYsize];//(Re)create array for tree CoordQueue uQueue = new CoordQueue(); //Initiate array for (int i = 0; i < iXsize; i++) for (int j = 0; j < iYsize; j++) { /* if ((bCells[i, j] & SokoCell.Obstacle) == 0) { iMoveTree[i, j] = MT_NOT_REACHED; } else { iMoveTree[i, j] = MT_BLOCKED; }*/ if ((bCells[i, j] & SokoCell.MaskObstacle) != 0 || i == 0 || i == (iXsize - 1) || j == 0 || j == (iYsize - 1)) {//Obstacle on cell or border cell (topmost, bottommost, leftmost and rightmost lines of level MUST contain ONLY walls or backgrounds, so box move tree should not reach them) iMoveTree[i, j] = MT_BLOCKED; } else {//Other cells - could be reached iMoveTree[i, j] = MT_NOT_REACHED; } } if (iMoveTree[iXstart, iYstart] == MT_BLOCKED) return FunctionResult.StartIsBlocked;//Start is blocked, so no tree iMoveTree[iXstart, iYstart] = 0;//Start pos uQueue.AddNext(iXstart, iYstart);//Add root of tree to queue x = 0; y = 0; //Initiate x and y, otherwise not compiled //Propagating tree to all cells - by checking cells, received from queue and adding new cells to this queue while (uQueue.Get(ref x, ref y)) { if (x == iXend) { if (y == iYend) {//Specified cell is reached - can exit return FunctionResult.PathFound; } } iDepth = iMoveTree[x, y]; iDepth++;//Get depth from cell and increment if (iMoveTree[x - 1, y] == MT_NOT_REACHED) { iMoveTree[x - 1, y] = iDepth; uQueue.AddNext(x - 1, y); }//Propagate tree for nearest cells if tree is not yet reached this cells if (iMoveTree[x + 1, y] == MT_NOT_REACHED) { iMoveTree[x + 1, y] = iDepth; uQueue.AddNext(x + 1, y); } if (iMoveTree[x, y - 1] == MT_NOT_REACHED) { iMoveTree[x, y - 1] = iDepth; uQueue.AddNext(x, y - 1); } if (iMoveTree[x, y + 1] == MT_NOT_REACHED) { iMoveTree[x, y + 1] = iDepth; uQueue.AddNext(x, y + 1); } } //Tree Builded //Root location is not stored return FunctionResult.OK; }