예제 #1
0
        public PathFindingResult <PickingTravelStep> FindPath(PickingOrder order)
        {
            var result = new PathFindingResult <PickingTravelStep>
            {
                Success = true,
            };
            var currentPosition = new PickingTravelStep(_warehouseLayout.GetPickingStartPosition(), new Dictionary <long, int>(order.RequiredArticles));

            var possiblePickingSlots = order.RequiredArticles
                                       .SelectMany(x => _warehouseLayout.GetPickingSlotsWithSku(x.Key))
                                       .OrderBy(x => x.AlleyNumber).ThenBy(x => x.PositionNumber)
                                       .ToList();

            var precalculatedRoutes = GetRoutesBetweenSlots(possiblePickingSlots);
            var remainingInOrder    = new Dictionary <long, int>(order.RequiredArticles);

            foreach (var possiblePickingSlot in possiblePickingSlots)
            {
                var previousPosition = currentPosition;
                if (!remainingInOrder.TryGetValue(possiblePickingSlot.Sku, out int positionUnits) || remainingInOrder[possiblePickingSlot.Sku] < 1)
                {
                    continue;
                }

                if (positionUnits < 1)
                {
                    continue;
                }

                var unitsToTake = Math.Min(positionUnits, remainingInOrder[possiblePickingSlot.Sku]);

                _warehouseLayout.GetPickingSlots().FirstOrDefault(x => x == possiblePickingSlot).Units -= unitsToTake;
                remainingInOrder[possiblePickingSlot.Sku] -= unitsToTake;
                currentPosition        = new PickingTravelStep(possiblePickingSlot, unitsToTake, new Dictionary <long, int>(remainingInOrder));
                currentPosition.Parent = previousPosition;

                if (!remainingInOrder.Any(x => x.Value > 0))
                {
                    break;
                }
            }

            var endPosition = _warehouseLayout.GetPickingEndPosition();
            var finalStep   = new PickingTravelStep(endPosition, currentPosition.PendingSkus);

            finalStep.CostFromStart = currentPosition.CostFromStart + FindTravelCostBetween(precalculatedRoutes, finalStep.Position, currentPosition.Position);
            finalStep.Parent        = currentPosition;
            currentPosition         = finalStep;

            var steps = new List <ITravelStep>();

            while (currentPosition != null)
            {
                var nextPosition = currentPosition.Parent;
                currentPosition.Parent = null;
                steps.Add(currentPosition);
                if (nextPosition != null && currentPosition != (PickingTravelStep)nextPosition)
                {
                    var route = FindTravelRouteBetween(precalculatedRoutes, currentPosition.Position, nextPosition.Position).Route;
                    foreach (var coord in route)
                    {
                        result.PathCoordinates.Add(coord);
                    }
                }
                currentPosition = nextPosition as PickingTravelStep;
            }

            result.Steps = steps.ToArray();
            return(result);
        }
예제 #2
0
        public PathFindingResult <PickingTravelStep> FindPath(PickingOrder order)
        {
            var result = new PathFindingResult <PickingTravelStep>
            {
                Success = true,
            };

            var openList = new Heap <PickingTravelStep>();

            var currentPosition = new PickingTravelStep(_warehouseLayout.GetPickingStartPosition(), new Dictionary <long, int>(order.RequiredArticles));

            var possiblePickingSlots = order.RequiredArticles
                                       .SelectMany(x => _warehouseLayout.GetPickingSlotsWithSku(x.Key))
                                       .ToList();

            var routesBetweenSlots = GetRoutesBetweenSlots(possiblePickingSlots);
            var endPosition        = _warehouseLayout.GetPickingEndPosition();

            while (currentPosition.PendingSkus.Any(x => x.Value > 0))
            {
                if (currentPosition.Sku > 0 && currentPosition.PickingSlot.Units > 0 && currentPosition.PendingSkus.ContainsKey(currentPosition.Sku))
                {
                    var requiredUnits = currentPosition.PendingSkus[currentPosition.Sku];
                    var unitsToTake   = Math.Min(requiredUnits, currentPosition.PickingSlot.AvailableUnits);
                    currentPosition.PendingSkus[currentPosition.Sku] -= unitsToTake;
                }

                if (currentPosition.PendingSkus.All(x => x.Value == 0))
                {
                    result.Success = true;
                    break;
                }

                var possibleNextSlots = possiblePickingSlots.Where(x => !currentPosition.VisitedSlots.Contains(x) &&
                                                                   currentPosition.PendingSkus.TryGetValue(x.Sku, out var value) &&
                                                                   value > 0)
                                        .ToList();
                if (!possibleNextSlots.Any())
                {
                    result.Success = false;
                    break;
                }


                foreach (var nextSlot in possibleNextSlots)
                {
                    var remainingRequiredUnits = currentPosition.PendingSkus[nextSlot.Sku];
                    var unitsToTake            = Math.Min(remainingRequiredUnits, nextSlot.Units - nextSlot.ReservedUnits);

                    var remainingSlots = possibleNextSlots.Where(x => x != nextSlot);
                    if (unitsToTake == remainingRequiredUnits)
                    {
                        remainingSlots = remainingSlots.Where(x => x.Sku != nextSlot.Sku);
                    }

                    var remainingSlotsList = remainingSlots.ToList();

                    var next = new PickingTravelStep(nextSlot, unitsToTake, new Dictionary <long, int>(currentPosition.PendingSkus))
                    {
                        Parent = currentPosition,
                    };
                    next.CostFromStart = currentPosition.CostFromStart + FindTravelCostBetween(routesBetweenSlots, next.Position, currentPosition.Position);
                    next.VisitedSlots  = new List <PickingSlot>(currentPosition.VisitedSlots)
                    {
                        nextSlot
                    };

                    var tentativeCost = FindTravelCostBetween(routesBetweenSlots, nextSlot.Position, endPosition);
                    tentativeCost += currentPosition.CostFromStart;
                    tentativeCost += remainingSlotsList.Sum(x => FindTravelCostBetween(routesBetweenSlots, nextSlot.Position, x.Position));


                    openList.Add(new HeapNode <PickingTravelStep>(next, tentativeCost));
                }

                currentPosition = openList.TakeHeapHeadPosition();
            }

            var finalStep = new PickingTravelStep(endPosition, currentPosition.PendingSkus);

            finalStep.CostFromStart = currentPosition.CostFromStart + FindTravelCostBetween(routesBetweenSlots, finalStep.Position, currentPosition.Position);
            finalStep.Parent        = currentPosition;
            currentPosition         = finalStep;

            // recreate found path and reserve items on stock
            var pickedArticles = order.RequiredArticles.Select(x => x.Key).ToDictionary(x => x, x => 0);
            var steps          = new List <ITravelStep>();

            while (currentPosition != null)
            {
                if (pickedArticles.ContainsKey(currentPosition.Sku))
                {
                    pickedArticles[currentPosition.Sku] += currentPosition.UnitsToTake;
                }

                if (currentPosition.PickingSlot != null)
                {
                    _warehouseLayout.ReserveArticles(currentPosition.PickingSlot.Address, currentPosition.Sku, currentPosition.UnitsToTake);
                }

                var nextPosition = currentPosition.Parent;
                currentPosition.Parent = null;
                steps.Add(currentPosition);
                if (nextPosition != null && currentPosition != (PickingTravelStep)nextPosition)
                {
                    var route = FindTravelRouteBetween(routesBetweenSlots, currentPosition.Position, nextPosition.Position).Route;
                    foreach (var coord in route)
                    {
                        result.PathCoordinates.Add(coord);
                    }
                }

                currentPosition = nextPosition as PickingTravelStep;
            }

            result.Steps = steps.ToArray();
            return(result);
        }