示例#1
0
        private List <MiniGameData> selectMiniGames(int nMinigamesToSelect)
        {
            List <MiniGameData> newPlaySessionMiniGames = selectMiniGamesForCurrentPlaySession(nMinigamesToSelect);

            if (ConfigAI.VerboseTeacher)
            {
                var debugString = "";
                debugString += ConfigAI.FormatTeacherReportHeader("Minigames Selected");
                foreach (var minigame in newPlaySessionMiniGames)
                {
                    debugString += "\n" + minigame.Code;
                }
                Debug.Log(debugString);
            }

            return(newPlaySessionMiniGames);
        }
示例#2
0
        public void LoadCurrentPlaySessionData(string currentPlaySessionId)
        {
            var pos = new JourneyPosition(currentPlaySessionId);

            currentJourneyContents       = progressionContents.GetContentsUpToPlaySession(pos);
            currentPlaySessionContents   = progressionContents.GetContentsOfPlaySession(pos);
            currentLearningBlockContents = progressionContents.GetContentsOfLearningBlock(pos);
            currentStageContents         = progressionContents.GetContentsOfStage(pos);

            if (ConfigAI.VerbosePlaySessionInitialisation)
            {
                string debugString = "";
                debugString += ConfigAI.FormatTeacherReportHeader("Play Session Initalisation (" + currentPlaySessionId + ")");
                debugString += "\n Current PS:\n" + currentPlaySessionContents;
                debugString += "\n Current LB:\n" + currentLearningBlockContents;
                debugString += "\n Current ST:\n" + currentStageContents;
                debugString += "\n Current journey:\n" + currentJourneyContents;
                debugString += "\n Whole contents:\n" + progressionContents.AllContents;
                ConfigAI.AppendToTeacherReport(debugString);
            }
        }
示例#3
0
        private List <T> WeightedDataSelect <T>(List <T> source_data_list, int nToSelect, SelectionSeverity severity) where T : IData
        {
            VocabularyDataType dataType = VocabularyDataType.Letter;

            if (typeof(T) == typeof(LetterData))
            {
                dataType = VocabularyDataType.Letter;
            }
            else if (typeof(T) == typeof(WordData))
            {
                dataType = VocabularyDataType.Word;
            }
            else if (typeof(T) == typeof(PhraseData))
            {
                dataType = VocabularyDataType.Phrase;
            }

            // Given a (filtered) list of data, select some using weights
            var score_data_list = dbManager.Query <VocabularyScoreData>("SELECT * FROM " + typeof(VocabularyScoreData).Name + " WHERE VocabularyDataType = '" + (int)dataType + "'");

            if (ConfigAI.VerboseDataSelection)
            {
                weightedData_debugString += ConfigAI.FormatTeacherReportHeader("Selection Weights");
                weightedData_debugString  = "";
            }

            var weights_list = new List <float>();

            foreach (var sourceData in source_data_list)
            {
                float cumulativeWeight = 0;
                if (ConfigAI.VerboseDataSelection)
                {
                    weightedData_debugString += "\n" + sourceData.GetId() + " ---";
                }


                // Get score data
                var   score_data         = score_data_list.Find(x => x.ElementId == sourceData.GetId());
                float currentScore       = 0;
                int   daysSinceLastScore = 0;
                if (score_data != null)
                {
                    var timespanFromLastScoreToNow = GenericHelper.GetTimeSpanBetween(score_data.UpdateTimestamp, GenericHelper.GetTimestampForNow());
                    daysSinceLastScore = timespanFromLastScoreToNow.Days;
                    currentScore       = score_data.Score;
                }

                //UnityEngine.Debug.Log("Data " + id + " score: " + currentScore + " days " + daysSinceLastScore);

                // Score Weight [0,1]: higher the lower the score [-1,1] is
                var scoreWeight = 0.5f * (1 - currentScore);
                cumulativeWeight += scoreWeight * ConfigAI.Vocabulary_Score_Weight;
                if (ConfigAI.VerboseDataSelection)
                {
                    weightedData_debugString += " \tScore: " + scoreWeight * ConfigAI.Vocabulary_Score_Weight + "(" + scoreWeight + ")";
                }

                // RecentPlay Weight  [1,0]: higher the more in the past we saw that data
                const float dayLinerWeightDecrease = 1f / ConfigAI.DaysForMaximumRecentPlayMalus;
                float       weightMalus            = daysSinceLastScore * dayLinerWeightDecrease;
                float       recentPlayWeight       = 1f - UnityEngine.Mathf.Min(1, weightMalus);
                cumulativeWeight += recentPlayWeight * ConfigAI.Vocabulary_RecentPlay_Weight;
                if (ConfigAI.VerboseDataSelection)
                {
                    weightedData_debugString += " \tRecent: " + recentPlayWeight * ConfigAI.Vocabulary_RecentPlay_Weight + "(" + recentPlayWeight + ")";
                }

                // Current focus weight [1,0]: higher if the data is part of the current play session / learning block / stage
                float currentPlaySessionWeight = 0;
                if (currentPlaySessionContents.Contains(sourceData))
                {
                    currentPlaySessionWeight = 1;
                }
                else if (currentLearningBlockContents.Contains(sourceData))
                {
                    currentPlaySessionWeight = 0.5f;
                }
                else if (currentStageContents.Contains(sourceData))
                {
                    currentPlaySessionWeight = 0.2f;
                }
                cumulativeWeight += currentPlaySessionWeight * ConfigAI.Vocabulary_CurrentPlaySession_Weight;
                if (ConfigAI.VerboseDataSelection)
                {
                    weightedData_debugString += " \tFocus: " + currentPlaySessionWeight * ConfigAI.Vocabulary_CurrentPlaySession_Weight + "(" + currentPlaySessionWeight + ")";
                }

                // If the cumulative weight goes to the negatives, we give it a fixed weight
                // TODO check if we shound use if (cumulativeWeight <= ConfigAI.Vocabulary_MinTotal_Weight)
                // TODO check the "continue" because it wont' save the data
                if (cumulativeWeight <= 0)
                {
                    cumulativeWeight = ConfigAI.Vocabulary_MinTotal_Weight;
                    continue;
                }

                // Save cumulative weight
                weights_list.Add(cumulativeWeight);
                if (ConfigAI.VerboseDataSelection)
                {
                    weightedData_debugString += " TOTw: " + cumulativeWeight;
                }
            }

            //return source_data_list;

            if (ConfigAI.VerboseDataSelection)
            {
                ConfigAI.AppendToTeacherReport(weightedData_debugString);
            }

            // Select data from the list
            var selected_data_list = new List <T>();

            if (source_data_list.Count > 0)
            {
                int      nToSelectFromCurrentList = 0;
                List <T> chosenData = null;
                switch (severity)
                {
                case SelectionSeverity.AsManyAsPossible:
                case SelectionSeverity.AllRequired:
                    nToSelectFromCurrentList = UnityEngine.Mathf.Min(source_data_list.Count, nToSelect);
                    chosenData = RandomHelper.RouletteSelectNonRepeating(source_data_list, weights_list, nToSelectFromCurrentList);
                    selected_data_list.AddRange(chosenData);
                    break;

                case SelectionSeverity.MayRepeatIfNotEnough:
                    int nRemainingToSelect = nToSelect;
                    while (nRemainingToSelect > 0)
                    {
                        var listCopy = new List <T>(source_data_list);
                        nToSelectFromCurrentList = UnityEngine.Mathf.Min(source_data_list.Count, nRemainingToSelect);
                        chosenData = RandomHelper.RouletteSelectNonRepeating(listCopy, weights_list, nToSelectFromCurrentList);
                        selected_data_list.AddRange(chosenData);
                        nRemainingToSelect -= nToSelectFromCurrentList;
                    }
                    break;
                }
            }
            return(selected_data_list);
        }
示例#4
0
        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;

                case SelectionParameters.JourneyFilter.CurrentLearningBlockOnly:
                    dataList = dataList.FindAll(x => currentLearningBlockContents.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 = dataList;

            if (!isTest && !selectionParams.getMaxData && selectionParams.priorityFilter != SelectionParameters.PriorityFilter.NoPriority)
            {
                HashSet <T> priorityFilteredHash = new HashSet <T>();
                string      s = ConfigAI.FormatTeacherReportHeader("Priority Filtering");

                switch (selectionParams.priorityFilter)
                {
                case SelectionParameters.PriorityFilter.CurrentThenExpand:
                {
                    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.";
                    }
                }
                break;

                case SelectionParameters.PriorityFilter.CurrentThenPast:
                {
                    int nBefore    = selectionParams.nRequired;
                    int nRemaining = selectionParams.nRequired;
                    var loopPos    = AppManager.I.Player.CurrentJourneyPosition;
                    s += "\n Required: " + nRemaining + " " + typeof(T).Name.ToString();
                    while (nRemaining > 0)
                    {
                        var loopContents = progressionContents.GetContentsOfPlaySession(loopPos);
                        AddToHashSetFilteringByContents(loopContents, dataList, priorityFilteredHash, ref nRemaining);
                        s += "\n" + (nBefore - nRemaining) + " from PS " + loopPos.ToDisplayedString(true);
                        if (loopPos.Equals(JourneyPosition.InitialJourneyPosition))
                        {
                            break;
                        }
                        loopPos = AppManager.I.JourneyHelper.FindPreviousJourneyPosition(loopPos);
                    }
                }
                break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                if (ConfigAI.VerboseDataFiltering)
                {
                    ConfigAI.AppendToTeacherReport(s);
                }
                priorityFilteredList = new List <T>();
                priorityFilteredList.AddRange(priorityFilteredHash);
                if (ConfigAI.VerboseDataFiltering)
                {
                    debugString_selectData += ("\n  Priority: " + priorityFilteredList.Count);
                }
            }
            //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);
        }
示例#5
0
        private List <MiniGameData> PerformSelection_Random(PlaySessionData playSessionData, int numberToSelect)
        {
            // Get all minigames ids for the given playsession (from PlaySessionData)
            // ... also, keep the weights around
            var minigame_id_list         = new List <string>();
            var playsession_weights_dict = new Dictionary <MiniGameCode, float>();

            foreach (var minigameInPlaySession in playSessionData.Minigames)
            {
                minigame_id_list.Add(minigameInPlaySession.MiniGameCode.ToString());
                playsession_weights_dict[minigameInPlaySession.MiniGameCode] = minigameInPlaySession.Weight;
            }

            // Get all minigame data, filter by availability (from the static DB)
            var minigame_data_list = dbManager.FindMiniGameData(x => x.Active && minigame_id_list.Contains(x.GetId()));

            // Create the weights list too
            var weights_list = new List <float>(minigame_data_list.Count);

            // Retrieve the current score data (state) for each minigame (from the dynamic DB)
            var minigame_score_list = dbManager.Query <MiniGameScoreData>("SELECT * FROM " + typeof(MiniGameScoreData).Name);

            //UnityEngine.Debug.Log("M GAME SCORE LIST: " + minigame_score_list.Count);
            //foreach(var l in minigame_score_list) UnityEngine.Debug.Log(l.ElementId);

            // Determine the final weight for each minigame
            var required_minigames = new List <MiniGameData>();

            string debugString = ConfigAI.FormatTeacherReportHeader("Minigame Selection");

            foreach (var minigame_data in minigame_data_list)
            {
                float cumulativeWeight   = 0;
                var   minigame_scoredata = minigame_score_list.Find(x => x.MiniGameCode == minigame_data.Code);
                int   daysSinceLastScore = 0;
                if (minigame_scoredata != null)
                {
                    var timespanFromLastScoreToNow = GenericHelper.GetTimeSpanBetween(minigame_scoredata.UpdateTimestamp, GenericHelper.GetTimestampForNow());
                    daysSinceLastScore = timespanFromLastScoreToNow.Days;
                }
                debugString += minigame_data.Code + " --- \t";

                // PlaySession Weight [0,1]
                float playSessionWeight = playsession_weights_dict[minigame_data.Code] / 100f; //  [0-100]
                cumulativeWeight += playSessionWeight * ConfigAI.MiniGame_PlaySession_Weight;
                debugString      += " PSw: " + playSessionWeight * ConfigAI.MiniGame_PlaySession_Weight + "(" + playSessionWeight + ")";

                // Some minigames are required to appear (weight 100+)
                if (playsession_weights_dict[minigame_data.Code] >= 100)
                {
                    required_minigames.Add(minigame_data);
                    debugString += " REQUIRED!\n";
                    continue;
                }

                // RecentPlay Weight  [1,0]
                const float dayLinerWeightDecrease = 1f / ConfigAI.DaysForMaximumRecentPlayMalus;
                float       weightMalus            = daysSinceLastScore * dayLinerWeightDecrease;
                float       recentPlayWeight       = 1f - UnityEngine.Mathf.Min(1, weightMalus);
                cumulativeWeight += recentPlayWeight * ConfigAI.MiniGame_RecentPlay_Weight;
                debugString      += " RPw: " + recentPlayWeight * ConfigAI.MiniGame_RecentPlay_Weight + "(" + recentPlayWeight + ")";

                // Save cumulative weight
                weights_list.Add(cumulativeWeight);
                debugString += " TOTw: " + cumulativeWeight + "\n";
            }
            if (ConfigAI.VerboseMinigameSelection)
            {
                ConfigAI.AppendToTeacherReport(debugString);
            }

            // Number checks
            int actualNumberToSelect = UnityEngine.Mathf.Min(numberToSelect, minigame_data_list.Count);

            // Remove the required ones
            actualNumberToSelect -= required_minigames.Count;
            foreach (var requiredMinigame in required_minigames)
            {
                minigame_data_list.Remove(requiredMinigame);
            }

            if (actualNumberToSelect > 0 && minigame_data_list.Count == 0)
            {
                throw new System.Exception("Cannot find even a single minigame for play session " + playSessionData.Id);
            }

            if (actualNumberToSelect > minigame_data_list.Count)
            {
                UnityEngine.Debug.LogWarning("Could not select the requested number of " + numberToSelect + " minigames for play session " + playSessionData.Id + " (only " + minigame_data_list.Count + " are available)");
            }

            // Choose N minigames based on these weights
            var selectedMiniGameData = RandomHelper.RouletteSelectNonRepeating(minigame_data_list, weights_list, actualNumberToSelect);

            // Output
            var finalList = new List <MiniGameData>();

            finalList.AddRange(required_minigames);
            finalList.AddRange(selectedMiniGameData);

            return(finalList);
        }