private void CalculateAdConstraints(AdvertisementTask order, int position) { _currentAdPosition = position; _currentAdCount = 1; _currentAd = order; if (!_taksAssessments.TryGetValue(order.ID, out TaskScore assesedTask)) { assesedTask = new TaskScore() { AdConstraints = _currentAd, ScoringFunction = ScoringFunction, }; assesedTask.BreaksPositions.Add(_breakData.ID, new SortedSet <int>()); _taksAssessments.Add(order.ID, assesedTask); } assesedTask.BreaksPositions[_breakData.ID].Add(position); _currentlyAssessed = assesedTask; Instance.BrandIncompatibilityCost.TryGetValue(_currentAd.Brand.ID, out var currentAdWeights); _currentAdIncompatibilityCosts = currentAdWeights; UpdateSimpleStatsForCurrentAd(position); for (int i = 0; i < _schedule.Count; i++) { if (i != _currentAdPosition) { CheckAdToAdCompatibility(_schedule.Order[i], i); } } if (_currentAdCount > _currentAd.MaxPerBlock) { _currentlyAssessed.SelfIncompatibilityConflicts += 1; } }
private List<int> GetPossibleInserts(TaskScore taskScore, BreakSchedule breakSchedule) { List<int> added = new List<int>(); if(!taskScore.BreaksPositions.TryGetValue(breakSchedule.ID, out var breakPositions)) { breakPositions = new SortedSet<int>(); } //make it a list copy var positionsList = breakPositions.ToList(); int arrIndex = 0; for(int possiblePos = 0; possiblePos < breakSchedule.Order.Count + 1; ) { if (added.Count >= MaxInsertedPerBreak) break; if (breakPositions.Count >= taskScore.AdConstraints.MaxPerBlock) break; if (breakSchedule.UnitFill + (added.Count + 1) * taskScore.AdConstraints.AdSpanUnits > breakSchedule.BreakData.SpanUnits + MaxBreakExtensionUnits) break; int nextPos = breakPositions.Count > arrIndex ? positionsList[arrIndex] : 999999999; if (possiblePos + taskScore.AdConstraints.MinJobsBetweenSame <= nextPos) { added.Add(possiblePos); for(int j = arrIndex; j < breakPositions.Count; j++) { positionsList[j] += 1; } positionsList.Insert(arrIndex, possiblePos); possiblePos += taskScore.AdConstraints.MinJobsBetweenSame + 1; } else { possiblePos = nextPos + taskScore.AdConstraints.MinJobsBetweenSame + 1; } arrIndex += 1; } return added; }
private void TryToScheduleOrder(TaskScore orderData) { var schedules = Solution.AdvertisementsScheduledOnBreaks.Values.Where(s => { if (s.UnitFill > MaxBreakExtensionUnits + s.BreakData.SpanUnits) { return(false); } if (Instance.GetTypeToBreakIncompatibility(orderData, s) == 1) { return(false); } if (Instance.GetBulkBrandIncompatibilities(orderData.AdConstraints, s.Order).Contains(double.PositiveInfinity)) { return(false); } return(true); }).ToList(); schedules.Shuffle(Random); foreach (var schedule in schedules) { if (CheckForNoSelfConflicts(orderData, schedule)) { PerformIfTransformationImprovesScore(orderData, schedule); } if (orderData.EndsSatisfied || CurrentTime.Elapsed >= TimeLimit) { break; } } }
private bool InsertInRandomNonFilledBreak(TaskScore taskData) { List <BreakSchedule> breaksWithEnoughSpace = Solution.AdvertisementsScheduledOnBreaks.Values.Where ( b => b.BreakData.SpanUnits >= b.UnitFill + taskData.AdConstraints.AdSpanUnits ).ToList(); if (breaksWithEnoughSpace.Count == 0) { return(false); } int breakNum = Random.Next(breaksWithEnoughSpace.Count); BreakSchedule schedule = breaksWithEnoughSpace[breakNum]; int position = Random.Next(schedule.Count + 1); Insert insert = new Insert() { TvBreak = schedule.BreakData, AdvertisementOrder = taskData.AdConstraints, Position = position, Instance = Instance, Solution = Solution, }; insert.Asses(); insert.Execute(); Reporter.AddEntry(insert.GenerateReportEntry()); return(true); }
private bool ThirstBucket() { float score; int TaskIndex = 1; TaskScore newScore; m_Scores.Clear(); m_TBucketUI.ToggleTasks(true); // Drink from flask // Only score if we have water in flask if (m_Inventory.QueryFlask() > 0) { float Thirst = m_Stats.GetThirst(); score = Thirst / 100.0f; newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.Drinking); m_Scores.Add(newScore); m_TBucketText[TaskIndex].text = score.ToString("0.000"); } TaskIndex++; // Refill flask if (m_Inventory.QueryFlask() < 100) { float Thirst = m_Stats.GetThirst() / 100.0f; float Flask = 1.0f - (float)m_Inventory.QueryFlask() / m_Inventory.m_MaxWaterFlask; score = Mathf.Pow((Flask + Thirst) / 2.0f, REFILL_EXPONENT); newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.RefillingFlask); m_Scores.Add(newScore); m_TBucketText[TaskIndex].text = score.ToString("0.000"); } return(HandleScores(TaskIndex, m_TBucketText)); }
private void ChooseMoveToPerform(List<int> positions, TaskScore taskScore, BreakSchedule breakSchedule) { foreach(var position in positions) { Insert move = new Insert() { Solution = Solution, Position = position, TvBreak = breakSchedule.BreakData, AdvertisementOrder = taskScore.AdConstraints, }; move.Asses(); if(move.OverallDifference.HasScoreImproved() && !move.OverallDifference.AnyCompatibilityIssuesIncreased()) { move.Execute(); Reporter.AddEntry(move.GenerateReportEntry()); _numberOfMoves += 1; _movePerformed = true; } else { break; } if (CurrentTime.Elapsed >= TimeLimit) break; } }
private bool CampfireBucket() { float score; TaskScore newScore; int TaskIndex = 1; m_Scores.Clear(); m_CFBucketUI.ToggleTasks(true); // Light campfire // Only score it if the campfire isn't lit if (!m_Campfire.IsLit() && m_Inventory.QueryLog() + m_Woodstore.QueryAmount() + m_Campfire.GetLogsRemaining() > 0) { float TimeUnlit = m_Campfire.GetUnlitTime(); float MaxTime = m_Campfire.m_WolfThreatTime; score = Mathf.Min(Mathf.Pow(TimeUnlit / MaxTime, LIGHT_FIRE_EXPONENT) + LIGHT_FIRE_BASE, 1.0f); newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.Firelighting); m_Scores.Add(newScore); m_CFBucketText[TaskIndex].text = score.ToString("0.000"); } TaskIndex++; // Add logs to fire // Only if we have logs AND the campfire isn't full if (m_Inventory.QueryLog() + m_Woodstore.QueryAmount() > 0 && m_Campfire.GetLogsRemaining() < m_Campfire.m_MaxLogs) { float FireRatio = 1.0f - (m_Campfire.GetAccurateLogsRemaining() / m_Campfire.m_MaxLogs); score = Mathf.Max(FireRatio, 0.0f); newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.Firebuilding); m_Scores.Add(newScore); m_CFBucketText[TaskIndex].text = score.ToString("0.000"); } TaskIndex++; // Chop wood // Only if there's space in inventory AND if theres trees available AND if the characters stats aren't too high if (m_Inventory.QuerySpace((int)Resource.Log) > 0 && m_Forest.GetActiveCount() > 0 && AbleToWork()) { float CurrentWood = m_Woodstore.QueryAmount() + m_Inventory.QueryLog() + m_Campfire.GetLogsRemaining(); float MaxWood = m_Woodstore.m_StorageLimit + m_Campfire.m_MaxLogs; score = Mathf.Min(1.0f - (CurrentWood / MaxWood), 1.0f); newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.Chopping); m_Scores.Add(newScore); m_CFBucketText[TaskIndex].text = score.ToString("0.000"); } TaskIndex++; // Deposit logs // Only score if the character has logs and there is space in the store if (m_Inventory.QueryLog() > 0 && m_Woodstore.QuerySpace() > 0) { score = (m_Inventory.QueryLog() * m_Inventory.m_LogWeight) / m_Inventory.QueryWeight(); newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.Depositing, Resource.Log); m_Scores.Add(newScore); m_CFBucketText[TaskIndex].text = score.ToString("0.000"); } return(HandleScores(TaskIndex, m_CFBucketText)); }
private bool HandleScores(int numTasks, Text[] BucketText) { if (m_Scores.Count <= 0) { return(false); } m_Scores.Sort((v1, v2) => v1.score.CompareTo(v2.score)); m_Scores.Reverse(); float winningScore = m_Scores[0].score; float minScore = winningScore - (winningScore * TaskPercentile); Color red = new Color(0.9f, 0.5f, 0.5f, 1.0f); Color yel = new Color(0.9f, 0.9f, 0.4f, 1.0f); Color toSet; foreach (TaskScore task in m_Scores) { toSet = yel; if (task.score < minScore) { BucketText[task.index + numTasks].text = "Elim."; toSet = red; } BucketText[task.index + numTasks].color = toSet; BucketText[task.index].color = toSet; } m_Scores.RemoveAll(task => task.score < minScore); if (m_Scores.Count == 1) { m_NewTask = m_Scores[0]; BucketText[m_NewTask.index + numTasks].text = "100%"; BucketText[m_NewTask.index].color = BucketText[m_NewTask.index + numTasks].color = Color.green; return(true); } else if (m_Scores.Count > 1) { WeighScores(numTasks, BucketText); m_NewTask = SelectTask(); BucketText[m_NewTask.index].color = BucketText[m_NewTask.index + numTasks].color = Color.green; return(true); } else { return(false); } }
private void PerformIfTransformationImprovesScore(TaskScore taskScore, BreakSchedule breakSchedule) { Insert move = new Insert() { Solution = Solution, Position = breakSchedule.Count, TvBreak = breakSchedule.BreakData, AdvertisementOrder = taskScore.AdConstraints, }; move.Asses(); if (move.OverallDifference.HasScoreImproved() && !move.OverallDifference.AnyCompatibilityIssuesIncreased()) { move.Execute(); Reporter.AddEntry(move.GenerateReportEntry()); _numberOfMoves += 1; _movePerformed = true; } }
private void InsertInRandomBreak(TaskScore taskData) { int breakNum = Random.Next(Instance.Breaks.Count); TvBreak tvBreak = Instance.Breaks.Values.ToList()[breakNum]; BreakSchedule schedule = Solution.AdvertisementsScheduledOnBreaks[tvBreak.ID]; int position = Random.Next(schedule.Count + 1); Insert insert = new Insert() { TvBreak = schedule.BreakData, AdvertisementOrder = taskData.AdConstraints, Position = position, Instance = Instance, Solution = Solution, }; insert.Asses(); insert.Execute(); Reporter.AddEntry(insert.GenerateReportEntry()); }
private void TryToScheduleOrder(TaskScore orderData) { var schedules = Solution.AdvertisementsScheduledOnBreaks.Values.Where(s => { if (s.UnitFill > MaxBreakExtensionUnits + s.BreakData.SpanUnits) return false; if (Instance.GetTypeToBreakIncompatibility(orderData, s) == 1) return false; if (Instance.GetBulkBrandIncompatibilities(orderData.AdConstraints, s.Order).Contains(double.PositiveInfinity)) return false; return true; }).ToList(); schedules.Shuffle(Random); foreach(var schedule in schedules) { var possibilities = GetPossibleInserts(orderData, schedule); ChooseMoveToPerform(possibilities, orderData, schedule); if((orderData.ViewsSatisfied && orderData.TimesAiredSatisfied) || CurrentTime.Elapsed >= TimeLimit) { break; } } }
private bool CheckForNoSelfConflicts(TaskScore taskScore, BreakSchedule breakSchedule) { if (!taskScore.BreaksPositions.TryGetValue(breakSchedule.ID, out var breakPositions)) { breakPositions = new SortedSet <int>(); } if (breakPositions.Count >= taskScore.AdConstraints.MaxPerBlock) { return(false); } if (breakSchedule.UnitFill + taskScore.AdConstraints.AdSpanUnits > breakSchedule.BreakData.SpanUnits + MaxBreakExtensionUnits) { return(false); } int lastPos = breakPositions.Count > 0 ? breakPositions.Last() : 999999999; if (Math.Abs(lastPos - breakSchedule.Count) < taskScore.AdConstraints.MinJobsBetweenSame) { return(false); } return(true); }
private bool FatigueBucket() { float score; int TaskIndex = 1; TaskScore newScore; m_Scores.Clear(); m_FBucketUI.ToggleTasks(true); // Rest // Only score if hunger and thirst won't reach 90 or higher after completion if ((m_Stats.GetHunger() + (m_Stats.m_HungerRate / m_Stats.m_DrainTickTime) * m_TaskDeployer.GetTaskTime(CharacterTaskDeployer.Task.Resting)) < 90.0f && (m_Stats.GetThirst() + (m_Stats.m_ThirstRate / m_Stats.m_DrainTickTime) * m_TaskDeployer.GetTaskTime(CharacterTaskDeployer.Task.Resting)) < 90.0f) { score = Mathf.Pow(m_Stats.GetFatigue() / 100.0f, REST_EXPONENT); newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.Resting); m_Scores.Add(newScore); m_FBucketText[TaskIndex].text = score.ToString("0.000"); } TaskIndex++; // Sleep in tent // Only score above 50 fatigue and if hunger and thirst won't reach 90 or higher after completion if (m_Stats.GetFatigue() > 50.0f && (m_Stats.GetHunger() + (m_Stats.m_HungerRate / m_Stats.m_DrainTickTime) * m_TaskDeployer.GetTaskTime(CharacterTaskDeployer.Task.Sleeping)) < 90.0f && (m_Stats.GetThirst() + (m_Stats.m_ThirstRate / m_Stats.m_DrainTickTime) * m_TaskDeployer.GetTaskTime(CharacterTaskDeployer.Task.Sleeping)) < 90.0f) { float Fatigue = m_Stats.GetFatigue() / 100.0f; float TimeLeft = m_Campfire.GetTimeRemaining(); float CFScore = (TimeLeft - m_TaskDeployer.GetTaskTime(CharacterTaskDeployer.Task.Sleeping)) / 100.0f; score = ((Fatigue * 2.0f) + CFScore) / 3.0f; newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.Sleeping); m_Scores.Add(newScore); m_FBucketText[TaskIndex].text = score.ToString("0.000"); } return(HandleScores(TaskIndex, m_FBucketText)); }
private bool HungerBucket() { float score; int TaskIndex = 1; TaskScore newScore; m_Scores.Clear(); m_HBucketUI.ToggleTasks(true); float Hunger = m_Stats.GetHunger() / 100.0f; // Eat a fish // Only score if we have fish or space in inventory for fish from storage if (m_Inventory.QueryFish() > 0 || (m_Fishstore.QueryAmount() > 0 && m_Inventory.QuerySpace((int)Resource.Fish) > 0)) { float FishStored = ((float)m_Inventory.QueryFish() + m_Fishstore.QueryAmount()) / (float)m_Fishstore.m_StorageLimit; float Restore = m_Stats.m_FishRestore / 100.0f; float Efficiency = Mathf.Pow(1.0f - Mathf.Max(1.0f - Hunger - Restore, 0.0f), EAT_FISH_EXPONENT); score = Mathf.Min((Hunger * 2.0f + FishStored + Efficiency * 2.0f) / 5.0f, 1.0f); newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.Eating, Resource.Fish); m_Scores.Add(newScore); m_HBucketText[TaskIndex].text = score.ToString("0.000"); } TaskIndex++; // Eat berries // Only if there's some in inventory or store if (m_Inventory.QueryBerry() > 0 || (m_Berrystore.QueryAmount() > 0 && m_Inventory.QuerySpace((int)Resource.Berry) > 0)) { float Berries = ((float)m_Inventory.QueryBerry() + m_Berrystore.QueryAmount()) / (float)m_Berrystore.m_StorageLimit; float Restore = m_Stats.m_BerryRestore / 100.0f; float Efficiency = Mathf.Pow(1.0f - Mathf.Max(1.0f - Hunger - Restore, 0.0f), EAT_BERRY_EXPONENT); score = Mathf.Min((Hunger * 2.0f + Berries + Efficiency * 2.0f) / 5.0f, 1.0f); newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.Eating, Resource.Berry); m_Scores.Add(newScore); m_HBucketText[TaskIndex].text = score.ToString("0.000"); } TaskIndex++; // Go fishing // Only if there's space in inventory AND if there is fishing spots available if (m_Inventory.QuerySpace((int)Resource.Fish) > 0 && m_Pond.GetActiveCount() > 0) { float Fish = 1.0f - ((m_Fishstore.QueryAmount() + m_Inventory.QueryFish()) / m_Fishstore.m_StorageLimit); score = Mathf.Max((Fish + Hunger) / 2.0f, 0.0f); newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.Fishing); m_Scores.Add(newScore); m_HBucketText[TaskIndex].text = score.ToString("0.000"); } TaskIndex++; // Forage if (m_Inventory.QuerySpace((int)Resource.Berry) > 0 && m_Stats.GetThirst() < 70.0f && m_Bushes.GetActiveCount() > 0) { float Berries = 1.0f - (((float)m_Berrystore.QueryAmount() + m_Inventory.QueryBerry()) / m_Berrystore.m_StorageLimit); score = Mathf.Max(((Berries * 2.0f - FORAGE_BASE) + Hunger) / 3.0f, 0.0f); newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.Foraging); m_Scores.Add(newScore); m_HBucketText[TaskIndex].text = score.ToString("0.000"); } TaskIndex++; // Deposit fish if (m_Inventory.QueryFish() > 0) { float FishRatio = (m_Inventory.QueryFish() * m_Inventory.m_FishWeight) / m_Inventory.QueryWeight(); float InventoryRatio = (float)m_Inventory.QueryWeight() / m_Inventory.m_MaxWeight; score = (FishRatio + InventoryRatio) / 2.0f; newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.Depositing, Resource.Fish); m_Scores.Add(newScore); m_HBucketText[TaskIndex].text = score.ToString("0.000"); } TaskIndex++; // Deposit berry if (m_Inventory.QueryBerry() > 0) { float BerriesRatio = (m_Inventory.QueryBerry() * m_Inventory.m_BerryWeight) / m_Inventory.QueryWeight(); float InventoryRatio = (float)m_Inventory.QueryWeight() / m_Inventory.m_MaxWeight; score = (BerriesRatio + InventoryRatio) / 2.0f; newScore = new TaskScore(score, TaskIndex, CharacterTaskDeployer.Task.Depositing, Resource.Berry); m_Scores.Add(newScore); m_HBucketText[TaskIndex].text = score.ToString("0.000"); } return(HandleScores(TaskIndex, m_HBucketText)); }