private bool CanDragContinuosly(INavigator navigator, int keeperStartPos, int boxStartPos, int keeperEndPos, int boxEndPos, Queue <Tuple <INavigator, int, int, int, int> > scope, HashSet <INavigator> drags) { if (!drags.Add(navigator)) { return(false); } var touchPoints = new List <SokobanPathItem>(); navigator.ForeachNeighborsRecursively(keeperStartPos, (currentPos, key, neighbor, cellType) => { if (neighbor == boxStartPos) { var targetKeeperPos = navigator.GetPosition(navigator.GetOppositeKey(key), currentPos); if (navigator.CanHoldKeeper(targetKeeperPos)) { touchPoints.Add(new SokobanPathItem() { Position = currentPos, Key = key, StepsToTarget = 1 }); } } return(navigator.CanHoldKeeper(neighbor)); }); if (touchPoints.Count == 0) { // keeper doesn`t even touch the box return(false); } foreach (var touchPoint in touchPoints) { var keeperPos = touchPoint.Position; var keeperTarget = navigator.GetPosition(navigator.GetOppositeKey(touchPoint.Key), keeperPos); var boxPos = navigator.GetPosition(touchPoint.Key, keeperPos); if (keeperTarget == keeperEndPos && keeperPos == boxEndPos) { return(true); } else { var newNavigator = (Navigator)Drag(keeperPos, keeperTarget.Value, boxPos.Value); scope.Enqueue(new Tuple <INavigator, int, int, int, int>(newNavigator, keeperTarget.Value, keeperPos, keeperEndPos, boxEndPos)); } } return(false); }