internal string[] GetGroupBinding(float intendedDifficulty, TrackedValue[] currentValues, int totalSelections) { if (!m_isGroupBinding) { CFLog.SendMessage("Trying to get group selection on individual selection. Returning null.", MessageType.ERROR); return(null); } StringBuilder sb = new StringBuilder(); sb.Append("Beginning Group Query:\n Individual Values:\n"); //Precalculate all of the output's results m_outputList.ForEach(o => o.CalculateDifficulty(currentValues, sb)); //Try combinations until we find one of size n with the closest value to intendedDifficulty m_recursiveBestValue = float.MaxValue; m_recursiveBestArray = new int[totalSelections]; GetBestGroupBinding(0, 0, totalSelections, new int[totalSelections], intendedDifficulty); string[] output = new string[totalSelections]; sb.Append("Group Query Returning:\n"); for (int j = 0; j < totalSelections; j++) { output[j] = m_outputList[m_recursiveBestArray[j]].returnString; sb.Append('\t'); sb.Append(m_recursiveBestArray[j]); sb.Append(':'); sb.Append(output[j]); sb.Append('\n'); } sb.Append("With total difficulty delta of "); sb.Append(m_recursiveBestValue); CFLog.SendMessage(sb.ToString(), MessageType.STATUS); return(output); }
private void GetBestGroupBinding(int listIndex, int arrIndex, int remainingSelections, int[] current, float diff) { remainingSelections--; if (remainingSelections == -1) { //Has reached the bottom (and current is filled with all values) //Sum the values float total = 0.0f; for (int j = 0; j < current.Length; j++) { total += m_outputList[current[j]].lastDifficulty; } float delta = Math.Abs(diff - total); CFLog.SendMessage(delta.ToString("G"), MessageType.DEBUG); if (delta < m_recursiveBestValue) { //Don't do the repeat checking math if the number is already too high //Technically this means that repeat mods of less than 1 won't work if (m_allowGroupDuplicates) { int dupeCount = current.Length - current.Distinct().Count(); if (dupeCount != 0) { delta *= (dupeCount * m_groupRepeatMultiplier); } if (delta > m_recursiveBestValue) { return; } } m_recursiveBestValue = delta; current.CopyTo(m_recursiveBestArray, 0); } } else { if (m_allowGroupDuplicates) { for (int j = listIndex; j < m_outputList.Count; j++) { //Recurses for every possible case this number can be //Since in a list of 5, 444 is valid output, top number *can* be 3 or 4 current[arrIndex] = j; GetBestGroupBinding(j, arrIndex + 1, remainingSelections, current, diff); } } else { for (int j = listIndex; j < m_outputList.Count - remainingSelections; j++) { //Recurses for every possible case this number can be //IE with an output count of 5 and a selection of 3, top number can never be 3 or 4 current[arrIndex] = j; GetBestGroupBinding(j + 1, arrIndex + 1, remainingSelections, current, diff); } } } }
internal void SetValue(string name, float value) { if (!m_profile.ContainsKey(name)) { CFLog.SendMessage(name + " is not a registered value.", MessageType.ERROR); return; } m_profile[name].SetValue(value); }
internal TrackedValue GetTrackedValue(string name) { if (!m_profile.ContainsKey(name)) { CFLog.SendMessage(name + " is not a registered value.", MessageType.ERROR); return(null); } return(m_profile[name]); }
public OutputQuery(string xmlString) { m_outputList = new List <Output>(); //Parses the file back into an object //TODO try catch XmlDocument doc = new XmlDocument(); doc.LoadXml(xmlString); m_name = doc.SelectSingleNode("/Query").Attributes["Name"].InnerText; //Do things on the settings node here var repeatNodes = doc.SelectSingleNode("/Query/Settings/RepeatSelection"); m_discourageRepeatSelection = repeatNodes.Attributes["Enabled"].InnerText == "True"; if (m_discourageRepeatSelection) { m_repeatSelectionWeight = float.Parse(repeatNodes["RepeatSelectionWeight"].InnerText); m_previousTrackedValues = int.Parse(repeatNodes["PreviousValuesTracked"].InnerText); m_diminishingWeight = bool.Parse(repeatNodes["DiminishingWeight"].InnerText); } var groupNodes = doc.SelectSingleNode("/Query/Settings/GroupBinding"); m_isGroupBinding = groupNodes.Attributes["Enabled"].InnerText == "True"; if (m_isGroupBinding) { m_allowGroupDuplicates = bool.Parse(groupNodes["AllowDuplicates"].InnerText); } //Load the outputs var outputNodes = doc.SelectNodes("/Query/Output"); foreach (XmlNode node in outputNodes) { Output outputObject = new Output(m_nextID, node["Name"].InnerText); m_nextID++; var skillNodes = node.SelectNodes("Skill"); foreach (XmlNode skillNode in skillNodes) { Weight weight = new Weight { value = float.Parse(skillNode["Value"].InnerText), multiplier = float.Parse(skillNode["Weight"].InnerText) }; outputObject.queryValues.Add(skillNode["Name"].InnerText, weight); } m_outputList.Add(outputObject); } var lockNodes = doc.SelectSingleNode("/Query/Settings/SelectionLock"); m_enableSelectionLock = lockNodes.Attributes["Enabled"].InnerText == "True"; CFLog.SendMessage("XML Successfully Loaded.", MessageType.STATUS); }
internal void AppendValue(float nextValue) { float oldValue = m_currentValue; switch (m_type) { case ValueType.ADDITIVE: SetCurrentValueInBounds(m_currentValue + nextValue); m_additionCount++; break; case ValueType.AVERAGE: m_currentValue = ((m_currentValue * m_additionCount) + nextValue) / (m_additionCount + 1); m_additionCount++; break; case ValueType.SET: //Log error CFLog.SendMessage("Tried to append to set only value: " + m_name, MessageType.ERROR); break; case ValueType.AVERAGEWEIGHTED: //Use addition count as a max. Count current value as additionCount - 1 then add new value/addition count m_currentValue = ((m_currentValue * (m_additionCount - 1)) + nextValue) / m_additionCount; break; } StringBuilder sb = new StringBuilder(); sb.Append(m_name); sb.Append(" Old Value: "); sb.Append(oldValue.ToString("G")); sb.Append(" New Value: "); sb.Append(m_currentValue); sb.Append(" Type: "); sb.Append(m_type); CFLog.SendMessage(sb.ToString(), MessageType.STATUS); }
internal string CalculateOptimalSelection(float intendedDifficulty, CFProfile profile) { if (m_isGroupBinding) { CFLog.SendMessage("Trying to calculate single selection on group binding. Continuing...", MessageType.ERROR); } StringBuilder sb = new StringBuilder(); TrackedValue[] currentValues = profile.GetAllValues(); float currentBestDelta = float.MaxValue; int currentBestIndex = -1; for (int j = 0; j < m_outputList.Count; j++) { if (m_enableSelectionLock && profile.IsOutputLocked(m_name, m_outputList[j].returnString)) { sb.Append("Selection Locked: "); sb.Append(m_outputList[j].returnString); sb.Append("\n"); continue; } float difficulty = m_outputList[j].CalculateDifficulty(currentValues, sb); float delta = Math.Abs(intendedDifficulty - difficulty); sb.Append("Delta: "); sb.Append(delta); sb.Append('\n'); //This needs to mod delta, not difficulty if (m_discourageRepeatSelection) { int position = m_previousValues.IndexOf(m_outputList[j].id); //If the ID is in the previous list if (position != -1) { if (m_diminishingWeight) { position = m_previousTrackedValues - position; delta += delta * m_repeatSelectionWeight * //Ie if this object is 3rd in a 3 object list, 3/3 weight applied (position + 1) / m_previousTrackedValues; } else { delta *= m_repeatSelectionWeight; } sb.Append("\tIn previous Selection at Index "); sb.Append(position); sb.Append(". Modded to "); sb.Append(delta); sb.Append("\n"); } } if (delta < currentBestDelta) { currentBestDelta = delta; currentBestIndex = j; } } if (m_discourageRepeatSelection) { //Removes the value if it has already been placed into the queue m_previousValues.Remove(m_outputList[currentBestIndex].id); m_previousValues.Insert(0, m_outputList[currentBestIndex].id); //If the queue has exceded its count if (m_previousValues.Count > m_previousTrackedValues) { m_previousValues.RemoveAt(m_previousTrackedValues); } } sb.Append("Query Returning "); sb.Append(m_outputList[currentBestIndex].returnString); sb.Append(" delta: "); sb.Append(currentBestDelta); CFLog.SendMessage(sb.ToString(), MessageType.STATUS); if (m_enableSelectionLock) { profile.LockOutput(m_name, m_outputList[currentBestIndex].returnString); } return(m_outputList[currentBestIndex].returnString); }
/// <summary> /// Sets up CurveFlow's logging system to a custom callback function /// </summary> /// <param name="log">The Callback function where the string will be pushed</param> /// <param name="messageTypeMask">Bitmask of the MessageTypes that will be sent</param> public void InitializeLog(LogCallback log, MessageType messageTypeMask) { CFLog.SetupLog(messageTypeMask, log); }