private bool CheckRequiredNumberReached <T>(List <T> dataList, SelectionParameters selectionParams, int nAfterBuilder) { return((!selectionParams.getMaxData && dataList.Count >= selectionParams.nRequired) || (selectionParams.getMaxData && dataList.Count >= nAfterBuilder)); }
private QuestionPackData CreateSingleQuestionPackData(int inRoundPackIndex) { var teacher = AppManager.I.Teacher; var vocabularyHelper = AppManager.I.VocabularyHelper; // Choose a single eligible word var selectionParams1 = new SelectionParameters(parameters.correctSeverity, 1, useJourney: parameters.useJourneyForCorrect, packListHistory: parameters.correctChoicesHistory, filteringIds: previousPacksIDs_words); selectionParams1.AssignJourney(parameters.insideJourney); var usableWords = teacher.VocabularyAi.SelectData( () => FindEligibleWords(maxWordLength: maximumWordLength), selectionParams1 ); var wordQuestion = usableWords[0]; currentRound_words.Add(wordQuestion); //UnityEngine.Debug.LogWarning("Chosen word: " + wordQuestion); // Get letters of that word var wordLetters = vocabularyHelper.GetLettersInWord(wordQuestion, removeAccents); //UnityEngine.Debug.LogWarning("Found letters: " + wordLetters.ToArray().ToDebugString()); bool useJourneyForLetters = parameters.useJourneyForCorrect; // @note: we force journey in this case to be off so that all letters can be found // @note: we also force the journey if the packs must be used together, as the data filters for journey clash with the new filter if (useAllCorrectLetters || packsUsedTogether) { useJourneyForLetters = false; } // Get some letters (from that word) var selectionParams2 = new SelectionParameters(parameters.correctSeverity, nCorrect, getMaxData: useAllCorrectLetters, useJourney: useJourneyForLetters, filteringIds: previousPacksIDs_letters); selectionParams2.AssignJourney(parameters.insideJourney); var correctLetters = teacher.VocabularyAi.SelectData( () => FindCorrectLetters(wordQuestion, wordLetters), selectionParams2); currentRound_letters.AddRange(correctLetters); // Get some wrong letters (not from that word, nor other words, nor previous letters) // Only for the first pack of the round var wrongLetters = new List <LetterData>(); if (inRoundPackIndex == 0) { wrongLetters = teacher.VocabularyAi.SelectData( () => FindWrongLetters(wordQuestion, wordLetters), new SelectionParameters( parameters.wrongSeverity, nWrong, useJourney: parameters.useJourneyForWrong, journeyFilter: SelectionParameters.JourneyFilter.CurrentJourney)); currentRound_letters.AddRange(wrongLetters); } if (ConfigAI.VerboseQuestionPacks) { string debugString = "--------- TEACHER: question pack result ---------"; debugString += "\nQuestion: " + wordQuestion; debugString += "\nCorrect Answers: " + correctLetters.Count; foreach (var l in correctLetters) { debugString += " " + l; } debugString += "\nWrong Answers: " + wrongLetters.Count; foreach (var l in wrongLetters) { debugString += " " + l; } ConfigAI.AppendToTeacherReport(debugString); } return(QuestionPackData.Create(wordQuestion, correctLetters, wrongLetters)); }
public List <T> SelectData <T>(System.Func <List <T> > builderSelectionFunction, SelectionParameters selectionParams, bool isTest = false, bool canReturnZero = false) where T : IVocabularyData { // skip if we require 0 values if (selectionParams.nRequired == 0 && !selectionParams.getMaxData) { return(new List <T>()); } if (ConfigAI.VerboseDataSelection) { debugString_selectData = ""; debugString_selectData += ConfigAI.FormatTeacherReportHeader("Data Selection: " + typeof(T).Name); } // (1) Filtering based on the builder's logic var dataList = builderSelectionFunction(); int nAfterBuilder = dataList.Count; if (ConfigAI.VerboseDataFiltering) { debugString_selectData += ("\n Builder: " + dataList.Count); } // (2) Filtering based on journey if (selectionParams.useJourney && !ConfigAI.ForceJourneyIgnore) { switch (selectionParams.journeyFilter) { case SelectionParameters.JourneyFilter.CurrentJourney: dataList = dataList.FindAll(x => currentJourneyContents.Contains(x)); break; case SelectionParameters.JourneyFilter.UpToFullCurrentStage: dataList = dataList.FindAll(x => currentJourneyContents.Contains(x) || currentStageContents.Contains(x)); break; } } if (selectionParams.severity == SelectionSeverity.AllRequired) { if (!CheckRequiredNumberReached(dataList, selectionParams, nAfterBuilder)) { throw new Exception("The teacher could not find " + selectionParams.nRequired + " data instances after applying the journey logic."); } } if (ConfigAI.VerboseDataFiltering) { debugString_selectData += ("\n Journey: " + dataList.Count); } //Debug.Log("Journey: " + dataList.ToDebugStringNewline()); // (3) Filtering based on pack-list history switch (selectionParams.packListHistory) { case PackListHistory.NoFilter: // we do not care which are picked, in this case break; case PackListHistory.ForceAllDifferent: // filter only by those that have not been found already in this pack, if possible dataList = dataList.FindAll(x => !selectionParams.filteringIds.Contains(x.GetId())); if (!CheckRequiredNumberReached(dataList, selectionParams, nAfterBuilder)) { UnityEngine.Debug.Log(debugString_selectData); throw new System.Exception("The teacher could not find " + selectionParams.nRequired + " data instances after applying the pack-history logic."); } break; case PackListHistory.RepeatWhenFull: // reset the previous pack list if needed var tmpDataList = dataList.FindAll(x => !selectionParams.filteringIds.Contains(x.GetId())); if (tmpDataList.Count < selectionParams.nRequired) { // reset and re-pick selectionParams.filteringIds.Clear(); dataList = dataList.FindAll(x => !selectionParams.filteringIds.Contains(x.GetId())); } else { dataList = tmpDataList; } break; } if (ConfigAI.VerboseDataFiltering) { debugString_selectData += ("\n History: " + dataList.Count); } //Debug.Log("History: " + dataList.ToDebugStringNewline()); //if(selectionParams.filteringIds != null) Debug.Log("Filtered ids:: " + selectionParams.filteringIds.ToDebugStringNewline()); // (4) Priority filtering based on current focus List <T> priorityFilteredList = null; if (!isTest && !selectionParams.getMaxData) { HashSet <T> priorityFilteredHash = new HashSet <T>(); string s = ConfigAI.FormatTeacherReportHeader("Priority Filtering"); int nBefore = selectionParams.nRequired; int nRemaining = selectionParams.nRequired; AddToHashSetFilteringByContents(currentPlaySessionContents, dataList, priorityFilteredHash, ref nRemaining); s += "\n Required: " + nRemaining + " " + typeof(T).Name.ToString(); s += "\n" + (nBefore - nRemaining) + " from PS"; if (nRemaining > 0) { nBefore = nRemaining; AddToHashSetFilteringByContents(currentLearningBlockContents, dataList, priorityFilteredHash, ref nRemaining); s += "\n" + (nBefore - nRemaining) + " from LB"; } if (nRemaining > 0) { nBefore = nRemaining; AddToHashSetFilteringByContents(currentStageContents, dataList, priorityFilteredHash, ref nRemaining); s += "\n" + (nBefore - nRemaining) + " from ST"; } if (nRemaining > 0) { nBefore = nRemaining; AddToHashSetFilteringByContents(currentJourneyContents, dataList, priorityFilteredHash, ref nRemaining); s += "\n" + (nBefore - nRemaining) + " from the current Journey"; } // @note: when journey filtering is disabled, we may still have to get some data from the rest of the journey if (nRemaining > 0 && !selectionParams.useJourney) { nBefore = nRemaining; AddToHashSetFilteringByContents(progressionContents.AllContents, dataList, priorityFilteredHash, ref nRemaining); s += "\n" + (nBefore - nRemaining) + " from the complete contents."; } if (ConfigAI.VerboseDataFiltering) { ConfigAI.AppendToTeacherReport(s); } priorityFilteredList = new List <T>(); priorityFilteredList.AddRange(priorityFilteredHash); if (ConfigAI.VerboseDataFiltering) { debugString_selectData += ("\n Priority: " + priorityFilteredList.Count); } } else { priorityFilteredList = dataList; } //Debug.Log("Priority: " + priorityFilteredList.ToDebugStringNewline()); // (5) Weighted selection on the remaining number List <T> selectedList = null; if (selectionParams.getMaxData) { selectedList = priorityFilteredList; } else { selectedList = WeightedDataSelect(priorityFilteredList, selectionParams.nRequired, selectionParams.severity); } if (ConfigAI.VerboseDataFiltering) { debugString_selectData += ("\n Selection: " + selectedList.Count); } //if (selectedList.Count > 0) Debug.Log("Selection: " + selectedList.ToDebugStringNewline()); if (ConfigAI.VerboseDataFiltering && !isTest) { foreach (var selectedEntry in selectedList) { debugString_selectData += " [" + selectedEntry + "]"; } ConfigAI.AppendToTeacherReport(debugString_selectData); } if (selectedList.Count == 0) { if (canReturnZero) { return(selectedList); } throw new System.Exception("The teacher could not find any data with the current filters. The game does not seem to be playable at the selected play session." + "\n" + debugString_selectData); } // Update the filtering ids if (selectionParams.packListHistory != PackListHistory.NoFilter) { selectionParams.filteringIds.AddRange(selectedList.ConvertAll <string>(x => x.GetId()).ToArray()); } // Reorder the selected data based on intrinsic difficulty if (selectionParams.sortDataByDifficulty) { selectedList.Sort((x, y) => (int)(x.GetIntrinsicDifficulty() - y.GetIntrinsicDifficulty())); } return(selectedList); }
private QuestionPackData CreateSingleQuestionPackData() { var teacher = AppManager.I.Teacher; var vocabularyHelper = AppManager.I.VocabularyHelper; // First, get all letters (only base letters, tho, due to forced letter filters) int nBaseLettersRequired = 1; if (letterAlterationFilters.differentBaseLetters) { nBaseLettersRequired = nCorrect + nWrong; } var selectionParams1 = new SelectionParameters(parameters.correctSeverity, nRequired: nBaseLettersRequired, useJourney: parameters.useJourneyForCorrect, packListHistory: parameters.correctChoicesHistory, filteringIds: previousPacksIDs); selectionParams1.AssignJourney(parameters.insideJourney); var chosenLetters = teacher.VocabularyAi.SelectData( () => vocabularyHelper.GetAllLetters(parameters.letterFilters), selectionParams1); var baseLetters = chosenLetters; // Then, find all the different variations and add them to a pool var letterPool = vocabularyHelper.GetAllLetterAlterations(baseLetters, letterAlterationFilters); // Choose randomly from that pool var correctAnswers = letterPool.RandomSelect(nCorrect); var wrongAnswers = letterPool; foreach (LetterData data in correctAnswers) { wrongAnswers.Remove(data); } if (avoidWrongLettersWithSameSound) { wrongAnswers.RemoveAll(wrongLetter => correctAnswers.Any(correctLetter => correctLetter.PhonemeSound.Equals(wrongLetter.PhonemeSound))); } wrongAnswers = wrongAnswers.RandomSelect(Mathf.Min(nWrong, wrongAnswers.Count)); var question = correctAnswers[0]; if (ConfigAI.VerboseQuestionPacks) { string debugString = "--------- TEACHER: question pack result ---------"; debugString += "\nQuestion: " + question; debugString += "\nCorrect Answers: " + correctAnswers.Count; foreach (var l in correctAnswers) { debugString += " " + l; } debugString += "\nWrong Answers: " + wrongAnswers.Count; foreach (var l in wrongAnswers) { debugString += " " + l; } ConfigAI.AppendToTeacherReport(debugString); } return(QuestionPackData.Create(question, correctAnswers, wrongAnswers)); }