コード例 #1
0
 private bool IsBetterThan(TrialGroupConfiguration other)
 {
     if (m_groupsWithConflictingGenders < other.m_groupsWithConflictingGenders)
     {
         return(true);
     }
     if (m_groupsWithConflictingGenders > other.m_groupsWithConflictingGenders)
     {
         return(false);
     }
     return(MinimumProximity > other.MinimumProximity);
 }
コード例 #2
0
            internal static TrialGroupConfiguration Best(List <TrialGroupConfiguration> configurations, TrialGroupConfiguration previousBest)
            {
                foreach (var configuration in configurations)
                {
                    configuration.CalculateConflicts();
                }

                var best = previousBest ?? configurations.First();

                foreach (var config in configurations.Skip(previousBest == null ? 1 : 0).Where(config => config.IsBetterThan(best)))
                {
                    best = config;
                }
                return(best);
            }
コード例 #3
0
        private void AddCharacterToBestGroup(CharacterDetail characterDetail, TrialGroupConfiguration configuration)
        {
            List <CharacterGroup> groups;

            IEnumerable <CharacterGroup> availableGroups = configuration.Groups.Where(g => !g.Closed &&
                                                                                      !configuration.IsGroupReservedForNarratorOrExtraBiblical(g));

            if (!availableGroups.Any())
            {
                availableGroups = configuration.Groups.Where(g => !g.Closed);
            }

            var groupMatchQualityDictionary = new Dictionary <MatchQuality, List <CharacterGroup> >(configuration.Groups.Count);

            foreach (var characterGroup in availableGroups)
            {
                var voiceActor = characterGroup.VoiceActor;
                var quality    = new MatchQuality(voiceActor.GetGenderMatchQuality(characterDetail), voiceActor.GetAgeMatchQuality(characterDetail));
                if (!groupMatchQualityDictionary.TryGetValue(quality, out groups))
                {
                    groupMatchQualityDictionary[quality] = groups = new List <CharacterGroup>();
                }
                groups.Add(characterGroup);
            }

            var groupToProximityDict = new Dictionary <CharacterGroup, WeightedMinimumProximity>();

            if (groupMatchQualityDictionary.TryGetValue(new MatchQuality(GenderMatchQuality.Perfect, AgeMatchQuality.Perfect), out groups))
            {
                CalculateProximityForGroups(characterDetail, groups, groupToProximityDict);
            }
            if (!groupToProximityDict.Any(i => i.Value.WeightedNumberOfBlocks >= Proximity.kDefaultMinimumProximity) &&
                groupMatchQualityDictionary.TryGetValue(new MatchQuality(GenderMatchQuality.Perfect, AgeMatchQuality.CloseAdult), out groups))
            {
                CalculateProximityForGroups(characterDetail, groups, groupToProximityDict);
            }
            if (!groupToProximityDict.Any(i => i.Value.WeightedNumberOfBlocks >= Proximity.kDefaultMinimumProximity || i.Value.NumberOfBlocks >= configuration.MinimumProximity) &&
                groupMatchQualityDictionary.TryGetValue(new MatchQuality(GenderMatchQuality.Perfect, AgeMatchQuality.AdultVsChild), out groups))
            {
                CalculateProximityForGroups(characterDetail, groups, groupToProximityDict);
            }
            if (!groupToProximityDict.Any(i => i.Value.WeightedNumberOfBlocks >= Proximity.kDefaultMinimumProximity || i.Value.NumberOfBlocks >= configuration.MinimumProximity) &&
                groupMatchQualityDictionary.TryGetValue(new MatchQuality(GenderMatchQuality.Acceptable, AgeMatchQuality.Perfect), out groups))
            {
                CalculateProximityForGroups(characterDetail, groups, groupToProximityDict, 1.1);
            }
            if (!groupToProximityDict.Any(i => i.Value.WeightedNumberOfBlocks >= Proximity.kDefaultMinimumProximity || i.Value.NumberOfBlocks >= configuration.MinimumProximity) &&
                groupMatchQualityDictionary.TryGetValue(new MatchQuality(GenderMatchQuality.Acceptable, AgeMatchQuality.CloseAdult), out groups))
            {
                CalculateProximityForGroups(characterDetail, groups, groupToProximityDict, 1.1);
            }
            if (!groupToProximityDict.Any(i => i.Value.WeightedNumberOfBlocks >= Proximity.kDefaultMinimumProximity || i.Value.NumberOfBlocks >= configuration.MinimumProximity) &&
                groupMatchQualityDictionary.TryGetValue(new MatchQuality(GenderMatchQuality.Acceptable, AgeMatchQuality.AdultVsChild), out groups))
            {
                CalculateProximityForGroups(characterDetail, groups, groupToProximityDict, 1.1);
            }
            if (!groupToProximityDict.Any(i => i.Value.WeightedNumberOfBlocks >= Proximity.kDefaultMinimumProximity || i.Value.NumberOfBlocks >= configuration.MinimumProximity) &&
                groupMatchQualityDictionary.TryGetValue(new MatchQuality(GenderMatchQuality.Mismatch, AgeMatchQuality.Perfect), out groups))
            {
                CalculateProximityForGroups(characterDetail, groups, groupToProximityDict, 2.3);
            }
            if (!groupToProximityDict.Any(i => i.Value.WeightedNumberOfBlocks >= Proximity.kDefaultMinimumProximity || i.Value.NumberOfBlocks >= configuration.MinimumProximity) &&
                groupMatchQualityDictionary.TryGetValue(new MatchQuality(GenderMatchQuality.Mismatch, AgeMatchQuality.CloseAdult), out groups))
            {
                CalculateProximityForGroups(characterDetail, groups, groupToProximityDict, 2.4);
            }
            if (!groupToProximityDict.Any(i => i.Value.WeightedNumberOfBlocks >= Proximity.kDefaultMinimumProximity || i.Value.NumberOfBlocks >= configuration.MinimumProximity) &&
                groupMatchQualityDictionary.TryGetValue(new MatchQuality(GenderMatchQuality.Mismatch, AgeMatchQuality.AdultVsChild), out groups))
            {
                CalculateProximityForGroups(characterDetail, groups, groupToProximityDict, 2.5);
            }
            if (!groupToProximityDict.Any(i => i.Value.WeightedNumberOfBlocks >= Proximity.kDefaultMinimumProximity || i.Value.NumberOfBlocks >= configuration.MinimumProximity) &&
                groupMatchQualityDictionary.TryGetValue(new MatchQuality(GenderMatchQuality.Perfect, AgeMatchQuality.Mismatch), out groups))
            {
                CalculateProximityForGroups(characterDetail, groups, groupToProximityDict, 2.7);
            }
            if (!groupToProximityDict.Any(i => i.Value.WeightedNumberOfBlocks >= Proximity.kDefaultMinimumProximity || i.Value.NumberOfBlocks >= configuration.MinimumProximity) &&
                groupMatchQualityDictionary.TryGetValue(new MatchQuality(GenderMatchQuality.Acceptable, AgeMatchQuality.Mismatch), out groups))
            {
                CalculateProximityForGroups(characterDetail, groups, groupToProximityDict, 2.9);
            }
            if (!groupToProximityDict.Any(i => i.Value.WeightedNumberOfBlocks >= Proximity.kDefaultMinimumProximity || i.Value.NumberOfBlocks >= configuration.MinimumProximity) &&
                groupMatchQualityDictionary.TryGetValue(new MatchQuality(GenderMatchQuality.Mismatch, AgeMatchQuality.Mismatch), out groups))
            {
                CalculateProximityForGroups(characterDetail, groups, groupToProximityDict, 3.2);
            }
            var bestGroupEntry = groupToProximityDict.Aggregate((l, r) => l.Value.WeightedNumberOfBlocks > r.Value.WeightedNumberOfBlocks ? l : r);
            var bestGroup      = bestGroupEntry.Key;

            if (configuration.MinimumProximity > bestGroupEntry.Value.NumberOfBlocks)
            {
                // We're adding the character to the best group we could find, but it is now the *worst* group in the configuration.
                configuration.NoteGroupWithWorstProximity(bestGroupEntry.Key, bestGroupEntry.Value.NumberOfBlocks);
            }
            bestGroup.CharacterIds.Add(characterDetail.CharacterId);
            if (RelatedCharactersData.Singleton.GetCharacterIdsForType(CharacterRelationshipType.SameCharacterWithMultipleAges).Contains(characterDetail.CharacterId))
            {
                foreach (var relatedCharacters in RelatedCharactersData.Singleton.GetCharacterIdToRelatedCharactersDictionary()[characterDetail.CharacterId])
                {
                    bestGroup.CharacterIds.AddRange(relatedCharacters.CharacterIds);
                }
            }
        }
コード例 #4
0
        internal List <CharacterGroup> GenerateCharacterGroups()
        {
            List <CharacterGroup> characterGroups = CreateGroupsForActors(m_project.VoiceActorList.Actors).ToList();

            if (characterGroups.Count == 0)
            {
                return(characterGroups);                // REVIEW: Maybe we should throw an exception instead.
            }
            m_project.SetDefaultCharacterGroupGenerationPreferences();

            List <VoiceActor.VoiceActor> nonCameoActors = m_project.VoiceActorList.Actors.Where(a => !a.IsCameo).ToList();

            if (nonCameoActors.Count == 0)
            {
                return(characterGroups);                // All cameo actors! This should never happen.
            }
            var sortedDict = from entry in m_keyStrokesByCharacterId orderby entry.Value descending select entry;

            IReadOnlyDictionary <string, CharacterDetail> characterDetails = m_project.AllCharacterDetailDictionary;
            var includedCharacterDetails = characterDetails.Values.Where(c => sortedDict.Select(e => e.Key).Contains(c.CharacterId)).ToList();

            // In the first loop, we're looking for actors that could only possibly play one character role.
            // Since we're not doing strict age matching, this is most likely only to find any candidates in
            // the case of children (and then only if the project includes a limited selection of books)
            var characterDetailsUniquelyMatchedToActors = new Dictionary <CharacterDetail, List <VoiceActor.VoiceActor> >();

            foreach (var actor in nonCameoActors)
            {
                // After we find the second match, we can quit looking because we're only interested in unique matches.
                var matches = includedCharacterDetails.Where(c => !CharacterVerseData.IsCharacterStandard(c.CharacterId) && actor.Matches(c)).Take(2).ToList();
                if (matches.Any())
                {
                    if (matches.Count == 1)
                    {
                        var characterDetail = matches.First();
                        if (characterDetailsUniquelyMatchedToActors.ContainsKey(characterDetail))
                        {
                            characterDetailsUniquelyMatchedToActors[characterDetail].Add(actor);
                        }
                        else
                        {
                            characterDetailsUniquelyMatchedToActors[characterDetail] = new List <VoiceActor.VoiceActor> {
                                actor
                            }
                        };
                    }
                }
            }

            // This loop uses the results of the previous one to add the characters to a group, and to close that
            // group to further additions. If there's more than one candidate actor, we pick one arbitrarily,
            // since afterwards we'll be clearing actor names anyway.
            // Since all groups now have an actor assigned up-front, at the
            // end of the generation process, we'll need to clear all actor assignments except for the ones that
            // are pre-determined here.
            List <int> actorsWithRealAssignments = new List <int>();

            foreach (var characterDetailToActors in characterDetailsUniquelyMatchedToActors)
            {
                var matchingActors = characterDetailToActors.Value;

                var matchingGroups = characterGroups.Where(g => matchingActors.Any(a => a.Id == g.VoiceActorId)).ToList();

                matchingGroups.First().CharacterIds.Add(characterDetailToActors.Key.CharacterId);

                if (matchingGroups.Count == 1)
                {
                    actorsWithRealAssignments.Add(matchingGroups[0].VoiceActorId);
                }

                foreach (var characterGroup in matchingGroups)
                {
                    characterGroup.Closed = true;
                }
            }

            // TODO: Make sure we didn't close all the groups (unless we assigned all the character IDs

            foreach (var character in includedCharacterDetails)
            {
                var matchingActors = characterGroups.Where(g => !g.Closed).Select(g => g.VoiceActor).Where(a => a.Matches(character)).ToList();
                if (matchingActors.Count == 1)
                {
                    var            matchingActor = matchingActors.First();
                    CharacterGroup groupForActor = characterGroups.Single(g => g.VoiceActorId == matchingActor.Id);
                    groupForActor.CharacterIds.Add(character.CharacterId);
                    actorsWithRealAssignments.Add(matchingActor.Id);
                }
            }

            int maxMaleNarrators   = m_project.CharacterGroupGenerationPreferences.NumberOfMaleNarrators;
            int maxFemaleNarrators = m_project.CharacterGroupGenerationPreferences.NumberOfFemaleNarrators;

            TrialGroupConfiguration bestConfiguration = null;

            do
            {
                var trialConfigurationsForNarratorsAndExtras = TrialGroupConfiguration.GeneratePossibilities(characterGroups,
                                                                                                             ref maxMaleNarrators, ref maxFemaleNarrators, includedCharacterDetails, m_project);

                if (trialConfigurationsForNarratorsAndExtras.Any())
                {
                    foreach (var configuration in trialConfigurationsForNarratorsAndExtras)
                    {
                        foreach (var entry in sortedDict)
                        {
                            string characterId = entry.Key;

                            if (configuration.Groups.Any(g => g.CharacterIds.Contains(characterId)))
                            {
                                continue;
                            }

                            CharacterDetail characterDetail;
                            if (!characterDetails.TryGetValue(characterId, out characterDetail))
                            {
                                if (characterId == CharacterVerseData.AmbiguousCharacter || characterId == CharacterVerseData.UnknownCharacter)
                                {
                                    continue;                                     // This should never happen in production code!
                                }
                                //Debug.WriteLine("No character details for unexpected character ID (see PG-): " + characterId);
                                //continue;
                                throw new KeyNotFoundException("No character details for unexpected character ID (see PG-471): " + characterId);
                            }

                            if (!configuration.AddToReservedGroupIfAppropriate(characterId))
                            {
                                AddCharacterToBestGroup(characterDetail, configuration);
                            }
                        }
                    }
                    bestConfiguration = TrialGroupConfiguration.Best(trialConfigurationsForNarratorsAndExtras, bestConfiguration);
                    if (bestConfiguration.MinimumProximity >= Proximity.kDefaultMinimumProximity)
                    {
                        return(GetFinalizedGroups(bestConfiguration.Groups, actorsWithRealAssignments));
                    }
                }
                if (maxMaleNarrators == 0)
                {
                    maxFemaleNarrators--;
                }
                else if (maxFemaleNarrators == 0)
                {
                    maxMaleNarrators--;
                }
                else if (bestConfiguration != null && (bestConfiguration.GroupWithWorstProximity.ContainsCharacterWithGender(CharacterGender.Female) ||
                                                       bestConfiguration.GroupWithWorstProximity.ContainsCharacterWithGender(CharacterGender.PreferFemale)))
                {
                    maxFemaleNarrators--;
                }
                else if (bestConfiguration != null && (bestConfiguration.GroupWithWorstProximity.ContainsCharacterWithGender(CharacterGender.Male) ||
                                                       bestConfiguration.GroupWithWorstProximity.ContainsCharacterWithGender(CharacterGender.PreferMale)))
                {
                    maxMaleNarrators--;
                }
                else if (maxMaleNarrators > maxFemaleNarrators)
                {
                    maxMaleNarrators--;
                }
                else
                {
                    maxFemaleNarrators--;
                }
            } while (maxMaleNarrators + maxFemaleNarrators > 0);

            Debug.Assert(bestConfiguration != null);
            return(GetFinalizedGroups(bestConfiguration.Groups, actorsWithRealAssignments));
        }