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); }
public static Dictionary <int, LocationGroup> GetLocationGroups(INavigator navigator) { var locationGroups = new Dictionary <int, LocationGroup>(); navigator.Foreach(new[] { Sokoban.LOCATION, Sokoban.KEEPER_ON_LOCATION, Sokoban.BOX_ON_LOCATION }, (areaId, position) => { if (!locationGroups.ContainsKey(areaId)) { locationGroups.Add(areaId, new LocationGroup(areaId) { }); } locationGroups[areaId].Positions.Add(position); foreach (var key in Sokoban.SupportedKeys) { var neighbor1 = navigator.GetPosition(key, position); if (neighbor1.HasValue && (navigator[neighbor1.Value] == Sokoban.EMPTY || navigator[neighbor1.Value] == Sokoban.KEEPER || navigator[neighbor1.Value] == Sokoban.BOX)) { var neighbor2 = navigator.GetPosition(key, neighbor1.Value); if (neighbor2.HasValue && (navigator[neighbor2.Value] == Sokoban.EMPTY || navigator[neighbor2.Value] == Sokoban.KEEPER || navigator[neighbor2.Value] == Sokoban.BOX)) { var oppositeKey = key == Key.Up ? Key.Down : key == Key.Down ? Key.Up : key == Key.Left ? Key.Right : Key.Left; locationGroups[areaId].EntryPoints.Add(new SokobanPathItem() { Position = neighbor1.Value, Key = oppositeKey, StepsToTarget = 1 }); } } } }); return(locationGroups); }
private static List <int> GetBoxesToExit(INavigator navigator, SokobanPathItem entryPoint) { var boxes = new List <int>(); //var areasToBoxTouchPoints = GetAreasToBoxesTouchPoints(navigator); //var keeperPos = navigator.GetKeeperPosition(); //var keeperArea = areasToBoxTouchPoints.Where(x => x.Value.Positions.Contains(keeperPos)).First(); navigator.Foreach(new[] { Sokoban.BOX_ON_LOCATION }, (box) => { var keeperPos = navigator.GetKeeperPosition(); var keeperTarget = navigator.GetPosition(navigator.GetOppositeKey(entryPoint.Key), keeperPos); var targetBoxPos = entryPoint.Position; if (navigator.CanDrag(keeperPos, box, keeperTarget.Value, targetBoxPos)) { boxes.Add(box); } //var keeperToBoxTouchPoints = keeperArea.Value.EntryPoints.Where(ep => navigator.GetPosition(ep.Key, ep.Position).Value == box).ToList(); //var isKeeperCanTouchBox = keeperToBoxTouchPoints.Count > 0; //if (isKeeperCanTouchBox && CanDrag(box, navigator, entryPoint, keeperToBoxTouchPoints)) //{ // boxes.Add(box); //} }); return(boxes); }
//public static bool CanDrag(int box, INavigator navigator, SokobanPathItem toExitPoint, List<SokobanPathItem> fromKeeperToBoxTouchPoints) //{ // foreach (var fromKeeperToBoxTouchPoint in fromKeeperToBoxTouchPoints) // { // if (fromKeeperToBoxTouchPoint.Position == toExitPoint.Position) // { // return true; // } // else // { // var processedStates = new HashSet<INavigator>(); // var scope = new Queue<INavigator>(); // scope.Enqueue(navigator); // while (scope.Count > 0) // { // var currentNavigator = scope.Dequeue(); // var keeperPos = fromKeeperToBoxTouchPoint.Position; // var boxTarget = keeperPos; // var keeperTarget = currentNavigator.GetPosition(currentNavigator.GetOppositeKey(fromKeeperToBoxTouchPoint.Key), boxTarget); // if (keeperTarget.HasValue && // (currentNavigator[keeperTarget.Value] == Sokoban.EMPTY || // currentNavigator[keeperTarget.Value] == Sokoban.LOCATION)) // { // var newNavigator = currentNavigator.Drag(keeperPos, keeperTarget.Value, box); // if (processedStates.Add(newNavigator)) // { // scope.Enqueue(newNavigator); // } // } // } // } // } // return true; //} public static IEnumerable <LocationItem> GetFillingOrder(INavigator navigator, IEnumerable <LocationGroup> locationGroups) { var items = new List <LocationItem>(); int currentRound = 1; foreach (var entryPoint in locationGroups.SelectMany(g => g.EntryPoints)) { var key = entryPoint.Key; int?neighbor = entryPoint.Position; int currentStep = 1; bool canContinue = false; do { var keeperPos = neighbor; neighbor = navigator.GetPosition(key, keeperPos); if (neighbor.HasValue && (navigator[neighbor.Value] == Sokoban.EMPTY || navigator[neighbor.Value] == Sokoban.KEEPER || navigator[neighbor.Value] == Sokoban.LOCATION || navigator[neighbor.Value] == Sokoban.KEEPER_ON_LOCATION || navigator[neighbor.Value] == Sokoban.BOX_ON_LOCATION)) { if (navigator[neighbor.Value] == Sokoban.LOCATION || navigator[neighbor.Value] == Sokoban.KEEPER_ON_LOCATION || navigator[neighbor.Value] == Sokoban.BOX_ON_LOCATION) { items.Add(new LocationItem() { KeeperPos = keeperPos.Value, Round = currentRound, Step = currentStep, Position = neighbor.Value }); currentStep++; } canContinue = true; } else { canContinue = false; } }while (canContinue); } //items.Add(new LocationItem() { Round = 1, Step = 1, Position = 53 }); //items.Add(new LocationItem() { Round = 1, Step = 2, Position = 54 }); //items.Add(new LocationItem() { Round = 1, Step = 3, Position = 55 }); //items.Add(new LocationItem() { Round = 2, Step = 1, Position = 64 }); //items.Add(new LocationItem() { Round = 2, Step = 1, Position = 65 }); //items.Add(new LocationItem() { Round = 2, Step = 2, Position = 75 }); //items.Add(new LocationItem() { Round = 2, Step = 3, Position = 85 }); //items.Add(new LocationItem() { Round = 3, Step = 1, Position = 63 }); return(items.OrderByDescending(l => l.Round).ThenByDescending(l => l.Step).ToList()); }