public void CalculateMinimumProximity_NarrationByAuthor_NonStrictAdherenceToNarratorPrefs_AllStandardCharactersAndBookAuthorResultsInMaxProximity() { var project = TestProject.CreateTestProject(TestProject.TestBook.GAL); project.UseDefaultForUnresolvedMultipleChoiceCharacters(); var idPaul = BiblicalAuthors.GetAuthorOfBook("GAL").Name; foreach (var block in project.IncludedBooks[0].GetBlocksForVerse(2, 15)) { block.CharacterId = idPaul; } project.CharacterGroupGenerationPreferences.NarratorsOption = NarratorsOption.NarrationByAuthor; // The following can be anything but omitted, but by making them all different, we prove that // non-strict adherence to the the narrator prefs is really happening. project.DramatizationPreferences.BookTitleAndChapterDramatization = ExtraBiblicalMaterialSpeakerOption.ActorOfEitherGender; project.DramatizationPreferences.BookIntroductionsDramatization = ExtraBiblicalMaterialSpeakerOption.FemaleActor; project.DramatizationPreferences.SectionHeadDramatization = ExtraBiblicalMaterialSpeakerOption.MaleActor; var proximity = new Proximity(project, false); var characterIds = new HashSet <string> { CharacterVerseData.GetStandardCharacterId("GAL", CharacterVerseData.StandardCharacter.Narrator), CharacterVerseData.GetStandardCharacterId("GAL", CharacterVerseData.StandardCharacter.ExtraBiblical), CharacterVerseData.GetStandardCharacterId("GAL", CharacterVerseData.StandardCharacter.Intro), // Not actually used in GAL test data CharacterVerseData.GetStandardCharacterId("GAL", CharacterVerseData.StandardCharacter.BookOrChapter), idPaul }; MinimumProximity minProximity = proximity.CalculateMinimumProximity(characterIds); Assert.AreEqual(Int32.MaxValue, minProximity.NumberOfBlocks); }
private void VerifyBasic(List <CharacterGroup> narratorGroups, int numberOfNarratorsExpectedToBeAssignedToASingleAuthor) { CharacterGroupGenerator.TrialGroupConfiguration.DistributeBooksAmongNarratorGroups(m_authorStats, narratorGroups); for (int i = 0; i < narratorGroups.Count; i++) { var group = narratorGroups[i]; var booksAssignedToNarrator = group.CharacterIds.Select(CharacterVerseData.GetBookCodeFromStandardCharacterId).ToList(); if (i < numberOfNarratorsExpectedToBeAssignedToASingleAuthor) { var author = BiblicalAuthors.GetAuthorOfBook(booksAssignedToNarrator[0]).Name; Assert.IsTrue(booksAssignedToNarrator.SetEquals(m_authorStats.Single(a => a.Author.Name == author).BookIds)); } else { // This is a narrator group that is expected to be assigned to multiple authors. For each author, // the set of books for this narrator MUST contain ALL the books for that author, plus at least one // other book. var set = new HashSet <string>(booksAssignedToNarrator); foreach (var bookId in booksAssignedToNarrator) { var author = BiblicalAuthors.GetAuthorOfBook(bookId).Name; Assert.IsTrue(set.IsProperSupersetOf(m_authorStats.Single(a => a.Author.Name == author).BookIds)); } } } }
public void Constructor_BooksWithSameAuthors_StatsCombinedForBooksWithSameAuthors() { var keyStrokesByBook = new Dictionary <string, int>(); keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("GEN", CharacterVerseData.StandardCharacter.Narrator)] = 50000; keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("ISA", CharacterVerseData.StandardCharacter.Narrator)] = 66000; keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JER", CharacterVerseData.StandardCharacter.Narrator)] = 52000; keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("EZK", CharacterVerseData.StandardCharacter.Narrator)] = 48000; keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("LUK", CharacterVerseData.StandardCharacter.Narrator)] = 24000; // 52000 combined keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("ACT", CharacterVerseData.StandardCharacter.Narrator)] = 28000; keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JHN", CharacterVerseData.StandardCharacter.Narrator)] = 20000; // 42000 combined keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("REV", CharacterVerseData.StandardCharacter.Narrator)] = 22000; var includedBooks = new List <string> { "GEN", "ISA", "JER", "EZK", "LUK", "ACT", "JHN", "REV" }; Assert.AreEqual(50000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("GEN"), includedBooks, keyStrokesByBook).KeyStrokeCount); Assert.AreEqual(66000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("ISA"), includedBooks, keyStrokesByBook).KeyStrokeCount); Assert.AreEqual(52000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("JER"), includedBooks, keyStrokesByBook).KeyStrokeCount); Assert.AreEqual(48000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("EZK"), includedBooks, keyStrokesByBook).KeyStrokeCount); Assert.AreEqual(52000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("LUK"), includedBooks, keyStrokesByBook).KeyStrokeCount); Assert.AreEqual(52000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("ACT"), includedBooks, keyStrokesByBook).KeyStrokeCount); Assert.AreEqual(42000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("JHN"), includedBooks, keyStrokesByBook).KeyStrokeCount); Assert.AreEqual(42000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("REV"), includedBooks, keyStrokesByBook).KeyStrokeCount); }
public void CalculateMinimumProximity_NarrationByAuthor_CharacterSpeakingInBookHeNarratesResultsInMaxProximity() { var project = TestProject.CreateTestProject(TestProject.TestBook.GAL); project.UseDefaultForUnresolvedMultipleChoiceCharacters(); var idPaul = BiblicalAuthors.GetAuthorOfBook("GAL").Name; foreach (var block in project.IncludedBooks[0].GetBlocksForVerse(2, 15)) { block.CharacterId = idPaul; } project.CharacterGroupGenerationPreferences.NarratorsOption = NarratorsOption.NarrationByAuthor; project.DramatizationPreferences.BookTitleAndChapterDramatization = ExtraBiblicalMaterialSpeakerOption.Narrator; project.CharacterGroupGenerationPreferences.NumberOfMaleNarrators = 1; var proximity = new Proximity(project); var characterIds = new HashSet <string> { CharacterVerseData.GetStandardCharacterId("GAL", CharacterVerseData.StandardCharacter.Narrator), CharacterVerseData.GetStandardCharacterId("GAL", CharacterVerseData.StandardCharacter.BookOrChapter), idPaul }; MinimumProximity minProximity = proximity.CalculateMinimumProximity(characterIds); Assert.AreEqual(Int32.MaxValue, minProximity.NumberOfBlocks); }
public void Constructor_AuthorHasNoIncludedBooks_KeyStrokeCountReturnsZero() { var keyStrokesByBook = new Dictionary <string, int>(); keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("LUK", CharacterVerseData.StandardCharacter.Narrator)] = 24000; // 52000 combined keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("ACT", CharacterVerseData.StandardCharacter.Narrator)] = 28000; var includedBooks = new List <string> { "GEN", "ISA", "JER", "JHN", "REV" }; Assert.AreEqual(0, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("LUK"), includedBooks, keyStrokesByBook).KeyStrokeCount); }
public void Constructor_BooksWithDifferentAuthors_NoStatsCombined() { var keyStrokesByBook = new Dictionary <string, int>(); keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JER", CharacterVerseData.StandardCharacter.Narrator)] = 52000; keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("EZK", CharacterVerseData.StandardCharacter.Narrator)] = 48000; keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("HOS", CharacterVerseData.StandardCharacter.Narrator)] = 12000; keyStrokesByBook[CharacterVerseData.GetStandardCharacterId("JUD", CharacterVerseData.StandardCharacter.Narrator)] = 1000; var includedBooks = new List <string> { "JER", "EZK", "HOS", "JUD" }; Assert.AreEqual(52000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("JER"), includedBooks, keyStrokesByBook).KeyStrokeCount); Assert.AreEqual(48000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("EZK"), includedBooks, keyStrokesByBook).KeyStrokeCount); Assert.AreEqual(12000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("HOS"), includedBooks, keyStrokesByBook).KeyStrokeCount); Assert.AreEqual(1000, new AuthorStats(BiblicalAuthors.GetAuthorOfBook("JUD"), includedBooks, keyStrokesByBook).KeyStrokeCount); }
private void AddToBestNarratorGroup(string characterId) { // Need tests (and code here) to handle the following scenarios: // 0) number of narrators > number of books -> This should never happen! // 1) DONE: number of narrators == number of books -> Add narrator to first empty narrator group // 2) TODO: number of narrators > number of authors -> break up most prolific authors into multiple narrator groups // 3) DONE: number of narrators == number of authors -> add narrator to group with other books by same other, if any; otherwise first empty group // 4) TODO: number of narrators < number of authors -> shorter books share narrators // 5) DONE: single narrator -> EASY: only one group! CharacterGroup bestNarratorGroup = null; if (m_narratorGroupsByAuthor != null) { var author = BiblicalAuthors.GetAuthorOfBook(CharacterVerseData.GetBookCodeFromStandardCharacterId(characterId)); bestNarratorGroup = m_narratorGroupsByAuthor[author]; } if (bestNarratorGroup == null) { bestNarratorGroup = NarratorGroups.FirstOrDefault(g => !g.CharacterIds.Any()); bestNarratorGroup = bestNarratorGroup ?? NarratorGroups.First(); } bestNarratorGroup.CharacterIds.Add(characterId); }
/// <summary>Calculate the minimum number of blocks between two character ids in given collection</summary> public MinimumProximity CalculateMinimumProximity(ISet <string> characterIdsToCalculate) { if (!characterIdsToCalculate.Any()) { return(new MinimumProximity(Int32.MaxValue, null, null, null, null)); } RelatedCharactersData relChar = RelatedCharactersData.Singleton; bool foundFirst = false; int currentBlockCount = 0; int minBlockProximity = Int32.MaxValue; string prevCharacterId = null; ISet <string> prevMatchingCharacterIds = null; BookScript firstBook = null; Block firstBlock = null; BookScript secondBook = null; Block secondBlock = null; BookScript prevBook = null; Block prevBlock = null; bool breakOutOfBothLoops = false; bool calculateAnyRelatedCharacters = characterIdsToCalculate.Any(c => relChar.HasMatchingCharacterIdsOfADifferentAge(c)); foreach (var book in m_booksToConsider) { if (breakOutOfBothLoops) { break; } var countVersesRatherThanBlocks = !m_referenceText.HasContentForBook(book.BookId); var treatAsSameCharacter = m_considerSameExtrabiblicalCharacter[book]; if (m_narrationByAuthor) { var author = BiblicalAuthors.GetAuthorOfBook(book.BookId); if (author.CombineAuthorAndNarrator && !treatAsSameCharacter.Any(set => set.Contains(author.Name))) { if (!m_strictlyAdhereToNarratorPreferences || (characterIdsToCalculate.Contains(book.NarratorCharacterId) && characterIdsToCalculate.Contains(author.Name))) { HashSet <string> charactersToTreatAsOneWithNarrator = treatAsSameCharacter.FirstOrDefault(set => set.Contains(book.NarratorCharacterId)); if (charactersToTreatAsOneWithNarrator == null) { charactersToTreatAsOneWithNarrator = new HashSet <string>(); treatAsSameCharacter.Add(charactersToTreatAsOneWithNarrator); charactersToTreatAsOneWithNarrator.Add(book.NarratorCharacterId); charactersToTreatAsOneWithNarrator.Add(author.Name); } else { charactersToTreatAsOneWithNarrator.Add(author.Name); } } } } // We don't want to treat book ends as being directly adjacent but not infinitely distant, either. currentBlockCount += kDefaultMinimumBlocks * 5 / 3; // The amount of padding is somewhat arbitrary. foreach (var block in book.Blocks) { var characterId = block.CharacterIdInScript; // The original logic here was NOT split out for the single character vs. multiple character scenarios. // This made the code much more readable, but the performance was atrocious since we were creating // extra hashsets and doing extra intersects. Please consider the performance implications of any // changes to this code. (I'm sure it could be optimized further, too...) ISet <string> matchingCharacterIds = null; if (calculateAnyRelatedCharacters && relChar.TryGetMatchingCharacterIdsOfADifferentAge(characterId, out matchingCharacterIds)) { if (matchingCharacterIds.Count == 1) { matchingCharacterIds = null; } } else { foreach (var set in treatAsSameCharacter) { if (set.Contains(characterId)) { matchingCharacterIds = set; break; } } } if (matchingCharacterIds == null) { if ((prevMatchingCharacterIds == null && prevCharacterId == characterId) || (prevMatchingCharacterIds != null && prevMatchingCharacterIds.Contains(characterId))) { currentBlockCount = 0; prevBook = book; prevBlock = block; } else if (characterIdsToCalculate.Contains(characterId) && (!CharacterVerseData.IsCharacterOfType(characterId, CharacterVerseData.StandardCharacter.Narrator) || prevCharacterId == null || !CharacterVerseData.IsCharacterOfType(prevCharacterId, CharacterVerseData.StandardCharacter.Narrator))) { if (ProcessDifferentCharacter(book, block, characterId, matchingCharacterIds, ref foundFirst, ref currentBlockCount, ref minBlockProximity, ref firstBook, ref prevBook, ref firstBlock, ref prevBlock, ref secondBook, ref secondBlock, ref breakOutOfBothLoops, ref prevCharacterId, ref prevMatchingCharacterIds)) { break; } } else { IncrementCount(countVersesRatherThanBlocks, block, ref currentBlockCount); } } else if (prevMatchingCharacterIds != null && matchingCharacterIds.Intersect(prevMatchingCharacterIds).Any()) { currentBlockCount = 0; prevBook = book; prevBlock = block; prevMatchingCharacterIds = matchingCharacterIds; } else if (characterIdsToCalculate.Intersect(matchingCharacterIds).Any()) { if (ProcessDifferentCharacter(book, block, characterId, matchingCharacterIds, ref foundFirst, ref currentBlockCount, ref minBlockProximity, ref firstBook, ref prevBook, ref firstBlock, ref prevBlock, ref secondBook, ref secondBlock, ref breakOutOfBothLoops, ref prevCharacterId, ref prevMatchingCharacterIds)) { break; } } else { IncrementCount(countVersesRatherThanBlocks, block, ref currentBlockCount); } } } return(new MinimumProximity(minBlockProximity, firstBook, secondBook, firstBlock, secondBlock)); }
public void DistributeBooksAmongNarratorGroups_FiftyNarrators_TwoNarratorsEachForPeterAndJohnThreeForPaul() { var narratorGroups = GetNarratorCharacterGroups(50); CharacterGroupGenerator.TrialGroupConfiguration.DistributeBooksAmongNarratorGroups(narratorGroups, 38, m_keyStrokesByBook.Keys.Select(CharacterVerseData.GetBookCodeFromStandardCharacterId), m_keyStrokesByBook); var narratorsWithMultipleBooks = new List <CharacterGroup>(); // John var narratorGroupForGospelOfJohn = GetNarratorGroupForBook(narratorGroups, "JHN"); var narratorGroupForRevelation = GetNarratorGroupForBook(narratorGroups, "REV"); narratorsWithMultipleBooks.Add(narratorGroupForGospelOfJohn); narratorsWithMultipleBooks.Add(narratorGroupForRevelation); Assert.AreNotEqual(narratorGroupForGospelOfJohn, narratorGroupForRevelation); Assert.AreEqual(narratorGroupForGospelOfJohn, GetNarratorGroupForBook(narratorGroups, "1JN")); Assert.AreEqual(narratorGroupForRevelation, GetNarratorGroupForBook(narratorGroups, "2JN")); Assert.AreEqual(narratorGroupForRevelation, GetNarratorGroupForBook(narratorGroups, "3JN")); // Peter var narratorGroupForFirstPeter = GetNarratorGroupForBook(narratorGroups, "2PE"); narratorsWithMultipleBooks.Add(narratorGroupForFirstPeter); Assert.AreEqual(narratorGroupForFirstPeter, GetNarratorGroupForBook(narratorGroups, "1PE")); // Paul var narratorGroupForRomans = GetNarratorGroupForBook(narratorGroups, "ROM"); var narratorGroupForFirstCorinthians = GetNarratorGroupForBook(narratorGroups, "1CO"); var narratorGroupForSecondCorinthians = GetNarratorGroupForBook(narratorGroups, "2CO"); narratorsWithMultipleBooks.Add(narratorGroupForRomans); narratorsWithMultipleBooks.Add(narratorGroupForFirstCorinthians); narratorsWithMultipleBooks.Add(narratorGroupForSecondCorinthians); Assert.AreNotEqual(narratorGroupForRomans, narratorGroupForFirstCorinthians); Assert.AreNotEqual(narratorGroupForFirstCorinthians, narratorGroupForSecondCorinthians); Assert.AreNotEqual(narratorGroupForRomans, narratorGroupForSecondCorinthians); // Jeremiah var narratorGroupForJeremiah = GetNarratorGroupForBook(narratorGroups, "JER"); narratorsWithMultipleBooks.Add(narratorGroupForJeremiah); Assert.AreEqual(narratorGroupForJeremiah, GetNarratorGroupForBook(narratorGroups, "LAM")); // Solomon var narratorGroupForEcclesiastes = GetNarratorGroupForBook(narratorGroups, "ECC"); narratorsWithMultipleBooks.Add(narratorGroupForEcclesiastes); Assert.AreNotEqual(narratorGroupForEcclesiastes, GetNarratorGroupForBook(narratorGroups, "PRO")); Assert.AreEqual(narratorGroupForEcclesiastes, GetNarratorGroupForBook(narratorGroups, "SNG")); var listOfBooksFoundSoFar = new HashSet <string>(); foreach (var group in narratorGroups) { var booksAssignedToNarrator = group.CharacterIds.Select(CharacterVerseData.GetBookCodeFromStandardCharacterId).ToList(); Assert.IsTrue(booksAssignedToNarrator.Any()); if (booksAssignedToNarrator.Count > 1) { var author = BiblicalAuthors.GetAuthorOfBook(booksAssignedToNarrator[0]); Assert.IsFalse(booksAssignedToNarrator.Any(b => author != BiblicalAuthors.GetAuthorOfBook(b))); Assert.IsTrue(narratorsWithMultipleBooks.Contains(group), author.Name); } Assert.IsFalse(listOfBooksFoundSoFar.Overlaps(booksAssignedToNarrator)); listOfBooksFoundSoFar.AddRange(booksAssignedToNarrator); } }
private TrialGroupConfiguration(IEnumerable <CharacterGroup> characterGroups, int numberOfMaleNarratorGroups, int numberOfFemaleNarratorGroups, int numberOfMaleExtraBiblicalGroups, int numberOfFemaleExtraBiblicalGroups, Project project, List <CharacterDetail> includedCharacterDetails) { m_groups = characterGroups.Select(g => g.Copy()).ToList(); Func <int, VoiceActor.VoiceActor> getVoiceActorById = id => project.VoiceActorList.GetVoiceActorById(id); MinimumProximity = Int32.MaxValue; if (Groups.Count == 1) { NarratorGroups = Groups.ToList(); ExtraBiblicalGroup = Groups[0]; } else { var availableAdultGroups = GetGroupsAvailableForNarratorOrExtraBiblical(Groups); if (availableAdultGroups.Count == 1) { NarratorGroups = availableAdultGroups.ToList(); ExtraBiblicalGroup = NarratorGroups[0]; } Debug.WriteLine("Male narrators desired = " + numberOfMaleNarratorGroups); Debug.WriteLine("Female narrators desired = " + numberOfFemaleNarratorGroups); NarratorGroups = new List <CharacterGroup>(numberOfMaleNarratorGroups + numberOfFemaleNarratorGroups); var idealAge = new List <ActorAge> { ActorAge.Adult }; int attempt = 0; while (attempt++ < 2 && (numberOfMaleNarratorGroups > 0 || numberOfFemaleNarratorGroups > 0 || numberOfMaleExtraBiblicalGroups > 0 || numberOfFemaleExtraBiblicalGroups > 0)) { foreach (var characterGroup in availableAdultGroups) { var actor = getVoiceActorById(characterGroup.VoiceActorId); if (!idealAge.Contains(actor.Age)) { continue; } Debug.WriteLine("Actor gender = " + actor.Gender); if (actor.Gender == ActorGender.Male) { if (numberOfMaleNarratorGroups > 0) { NarratorGroups.Add(characterGroup); numberOfMaleNarratorGroups--; } else if (numberOfMaleExtraBiblicalGroups > 0) { // TODO: Deal with numberOfMaleExtraBiblicalGroups > 1 (see above) ExtraBiblicalGroup = characterGroup; numberOfMaleExtraBiblicalGroups--; } } else { if (numberOfFemaleNarratorGroups > 0) { NarratorGroups.Add(characterGroup); numberOfFemaleNarratorGroups--; } else if (numberOfFemaleExtraBiblicalGroups > 0) { // TODO: Deal with numberOfFemaleExtraBiblicalGroups > 1 (see way above) ExtraBiblicalGroup = characterGroup; numberOfFemaleExtraBiblicalGroups--; } } if (numberOfMaleNarratorGroups == 0 && numberOfFemaleNarratorGroups == 0 && numberOfMaleExtraBiblicalGroups == 0 && numberOfFemaleExtraBiblicalGroups == 0) { break; } } idealAge = new List <ActorAge> { ActorAge.Elder, ActorAge.YoungAdult }; } if (numberOfMaleExtraBiblicalGroups == 1) { // TODO: Handle multiple extra-biblical groups ExtraBiblicalGroup = NarratorGroups.First(g => getVoiceActorById(g.VoiceActorId).Gender == ActorGender.Male); } else if (numberOfFemaleExtraBiblicalGroups == 1) { ExtraBiblicalGroup = NarratorGroups.First(g => getVoiceActorById(g.VoiceActorId).Gender == ActorGender.Female); } if (!NarratorGroups.Any()) { foreach (var characterGroup in Groups) { Debug.WriteLine("Cameo = " + characterGroup.AssignedToCameoActor); Debug.WriteLine("CharacterIds = " + characterGroup.CharacterIds.ToString()); } throw new Exception("None of the " + Groups.Count + " groups were suitable for narrator role."); } } var authors = new HashSet <BiblicalAuthors.Author>(project.IncludedBooks.Select(b => BiblicalAuthors.GetAuthorOfBook(b.BookId)).ToList()); if (NarratorGroups.Count == authors.Count) { m_narratorGroupsByAuthor = new Dictionary <BiblicalAuthors.Author, CharacterGroup>(); int i = 0; foreach (var author in authors) { m_narratorGroupsByAuthor[author] = NarratorGroups[i++]; } } else { m_narratorGroupsByAuthor = null; } AssignDeityCharacters(includedCharacterDetails, getVoiceActorById); }
public void GetAuthorCount_NewTestament_Returns9() { Assert.AreEqual(9, BiblicalAuthors.GetAuthorCount(BookSetUtils.NewTestament.SelectedBookIds)); }