public async Task <PlanElementCandidate> GenerateAsync(DecisionArray decisionArray, Plan plan, int whichMeal, PlanElementIteratorParams iterParams) { var test = true; //choose type based on preferences var type = (plan.PlanForm.FoodPreference == FoodPreference.OnlyRestaurant || (plan.PlanForm.FoodPreference == FoodPreference.Mixed && whichMeal == 2)) ? GooglePlaceTypeCategory.Restaurant : GooglePlaceTypeCategory.Food; var candidates = new List <PlanElementCandidate>(); var decisionRows = new List <DecisionRow>(); var googleNearbyFoodInput = _googlePlaceNearbySearchInputFactory.Create(iterParams.CurrentLocation, type); var nearbyFoodResults = await _googlePlaceNearbySearchApiClient.GetAsync(googleNearbyFoodInput); int counter = 1; foreach (var nr in nearbyFoodResults.results) { var details = await _googlePlaceDetailsApiClient.GetAsync(_googlePlaceDetailsInputFactory.CreateAllUseful(nr.place_id)); if (details.IsOk) { var candidate = new PlanElementCandidate(details.Result.name, details.Result.place_id, details.Result.formatted_address, details.Result.geometry.location, details.Result.opening_hours, details.Result.types, details.Result.rating, details.Result.price_level, details.Result.user_ratings_total); if (test) { return(candidate); } candidates.Add(candidate); } ++counter; if (counter > 10 && candidates.Count > 5) { break; } } var iter = 1; foreach (var candidate in candidates) { decisionRows.Add(_decisionRowFactory.Create(candidate, iter, iterParams.CurrentLocation)); ++iter; } var minVector = DecisionArray.GetMinVector(decisionRows); var maxVector = DecisionArray.GetMaxVector(decisionRows); foreach (var decisionRow in decisionRows) { decisionRow.NormalizedScore = _sawMethod.CalculateNormalizedScore(SawNormalizationMethod.LinearFirstType, decisionArray.WeightVector, decisionRow.DecisionValues, minVector, maxVector); } var result = decisionRows.OrderByDescending(x => x.NormalizedScore).FirstOrDefault(x => x.Candidate.IsOpen(iterParams.CurrentDateTime)); if (result == null) { throw new UserFriendlyException($"Nie udało się znaleźć żadnego miejsca, gdzie można zjeść w pobliżu o godz: {iterParams.CurrentDateTime}"); } return(result.Candidate); }
public async Task <IList <PlanElement> > GenerateAsync(DecisionArray decisionArray, Plan plan) { var elements = new List <PlanElement>(); var optimizedElementsOrder = await _optimizePlanElementsOrder.Optimize(decisionArray, plan, plan.Assumptions.AssumedNumberOfElement); //travel salesman problem optimization var optimizedPosition = 1; foreach (var optimizedIter in optimizedElementsOrder) { decisionArray.DecisionRows[optimizedIter].OptimizedPosition = optimizedPosition; ++optimizedPosition; } //Sort by optimized position decisionArray.DecisionRows = decisionArray.DecisionRows.OrderBy(x => x.OptimizedPosition).ToList(); var iterParams = new PlanElementIteratorParams(plan.StartLocation, plan.PlanForm.StartDateTime, plan.Assumptions); while (DateTime.Compare(iterParams.CurrentDateTime, plan.PlanForm.EndDateTime) <= 0 || iterParams.OrderNo >= decisionArray.DecisionRows.Count) { try { PlanElement planElement = null; //EATING if (iterParams.IsTimeForMeal()) { var elementEndTime = iterParams.CreateEndDateTime(plan.Assumptions.EatingDuration); var candidate = await _planElementEatingProvider.GenerateAsync(decisionArray, plan, iterParams.WhichMeal, iterParams); iterParams.CheckNextMeal(); planElement = new PlanElement(candidate.PlaceName, candidate.PlaceId, candidate.FormattedAddress, iterParams.CurrentDateTime, elementEndTime, candidate.Location.lat, candidate.Location.lng, iterParams.OrderNo, candidate.Rating, candidate.Price, candidate.Popularity, PlanElementType.Eating); } //SLEEPING else if (iterParams.IsTimeForSleep()) { iterParams.IsSleep = true; var elementEndTime = iterParams.CreateEndDateTime(plan.Assumptions.SleepDuration); if (plan.PlanForm.HasAccomodationBooked) { planElement = new PlanElement(plan.PlanAccomodation.PlaceName, plan.PlanAccomodation.PlaceId, plan.PlanAccomodation.FormattedAddress, iterParams.CurrentDateTime, elementEndTime, plan.PlanAccomodation.Lat, plan.PlanAccomodation.Lng, iterParams.OrderNo, plan.PlanAccomodation.Rating, null, null, PlanElementType.Sleeping); } else { planElement = new PlanElement(plan.PlanForm.PlaceName, plan.PlanForm.PlaceId, String.Empty, iterParams.CurrentDateTime, elementEndTime, plan.Latitude, plan.Longitude, iterParams.OrderNo, plan.Rating, null, null, PlanElementType.Sleeping); } } //OTHER PLAN ELEMENTS else { var foundRow = false; var elementEndTime = iterParams.CreateEndDateTime(plan.Assumptions.PlanElementDuration); while (!foundRow) { if (iterParams.LeftRows.Any(x => x.Candidate.IsOpen(iterParams.CurrentDateTime))) //first check lefted row which was temporary closed { var leftedRow = iterParams.LeftRows.First(x => x.Candidate.IsOpen(iterParams.CurrentDateTime)); if (!leftedRow.Candidate.IsOpen(elementEndTime)) //check close date { elementEndTime = leftedRow.Candidate.GetCloseDateTime(iterParams.CurrentDateTime, elementEndTime); } planElement = PlanElement.Create(leftedRow, iterParams.OrderNo, iterParams.CurrentDateTime, elementEndTime); iterParams.LeftRows.Remove(leftedRow); foundRow = true; } else if (decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex].Candidate.IsOpen(iterParams.CurrentDateTime)) //decision row is open { if (!decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex].Candidate.IsOpen(elementEndTime)) //check close date { elementEndTime = decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex].Candidate.GetCloseDateTime(iterParams.CurrentDateTime, elementEndTime); } planElement = PlanElement.Create(decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex], iterParams.OrderNo, iterParams.CurrentDateTime, elementEndTime); foundRow = true; iterParams.CurrentDecisionRowIndex += 1; } else //decision row is closed { iterParams.LeftRows.Add(decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex]); iterParams.CurrentDecisionRowIndex += 1; } } } if (iterParams.CurrentDecisionRowIndex == decisionArray.DecisionRows.Count()) { throw new UserFriendlyException($"Skończyły się dostępni kandydaci"); } if (planElement == null) { continue; } iterParams.NextLocation = Location.Create(planElement.Lat, planElement.Lng); //DIRECTIONS var directionsApiInput = _googleDirectionsInputFactory.Create(iterParams.CurrentLocation, iterParams.NextLocation, iterParams.travelMode, iterParams.CurrentDateTime); var directionsApiResult = await _googleDirectionsApiClient.GetAsync(directionsApiInput); if (directionsApiResult.IsOk) { if (directionsApiResult.routes.First().legs.Any()) { var route = directionsApiResult.routes.First().legs.First(); //only 1 leg if no waypoints var planRoute = new PlanRoute(route.distance.value, route.duration.value, iterParams.travelMode); foreach (var step in route.steps) //steps of route { planRoute.Steps.Add(new PlanRouteStep(step.distance.value, step.duration.value, step.start_location.lat, step.start_location.lng, step.end_location.lat, step.end_location.lng, InterpreteEnums.InterpreteTravelMode(step.travel_mode), step.html_instructions, step.maneuver)); } //update plan element times planElement.UpdateDateTimeWithRouteDuration(planRoute.TimeDuration); planElement.EndingRoute = planRoute; } } elements.Add(planElement); //add to plan list iterParams.SetCurrentLocation(planElement.Lat, planElement.Lng); // update currentLocation in iterParams iterParams.CurrentDateTime = planElement.End; //update current time in iterParams ++iterParams.OrderNo; //increase iter) iterParams.ClearIfEndOfCurrentDay(); } catch (Exception e) { var error = e.InnerException; break; } } return(elements); }