using Figgle; namespace VocabularyTrainer; /// /// Vocabulary trainer. /// Based on a supplied vocabulary training cycles are performed. /// public sealed class Trainer { private const int WordIdx = 0; private const int TranslationIdx = 1; private const int CycleCount = 3; private readonly VocabularyItem[] _vocabularyItems; /// /// Constructs a new instance based on the given vocabulary. /// /// Raw vocabulary read from a file public Trainer(string[][] wordsAndTranslations) { _vocabularyItems = CreateVocabularyItems(wordsAndTranslations); } /// /// Performs a training cycle for words. /// public void PerformTrainingCycle() { Console.Clear(); Console.ForegroundColor = ConsoleColor.DarkCyan; Console.WriteLine(FiggleFonts.Standard.Render("Vocabulary Trainer")); Console.WriteLine($"Starting a new training cycle with {CycleCount} tries ..."); var alreadyAsked = new bool[_vocabularyItems.Length]; for (var i = 0; i < CycleCount; i++) { Console.ForegroundColor = ConsoleColor.Yellow; int nextWord = PickNextWord(alreadyAsked); Console.Write($"{i + 1}: {_vocabularyItems[nextWord].NativeWord, -10} = "); Console.ResetColor(); string translationInput = Console.ReadLine()!; alreadyAsked[nextWord] = true; bool isTranslationCorrect = _vocabularyItems[nextWord].TestTranslation(translationInput); if (isTranslationCorrect) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("OK!"); } else { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"No, {_vocabularyItems[nextWord].NativeWord} = {_vocabularyItems[nextWord].Translation}"); } Console.ResetColor(); } Console.WriteLine(); } /// /// Prints training statistics to the terminal. /// public void PrintStatistics() { Sort(); Console.Clear(); Console.ForegroundColor = ConsoleColor.DarkCyan; Console.WriteLine(FiggleFonts.Standard.Render("Training Statistics")); Console.WriteLine($"{"English",-10} {"German",-10} {"Asked",-5} {"Correct",-7}"); Console.WriteLine(new string('-', 35)); Console.ForegroundColor = ConsoleColor.DarkYellow; foreach (var vocabularyItem in _vocabularyItems) { Console.WriteLine(vocabularyItem); } Console.WriteLine(); Console.ResetColor(); } /// /// Picks the next word by random. /// If all words have already been used any one is chosen. /// /// An array of flags indicating which words have already been used /// Index of next word to use private int PickNextWord(bool[] alreadyAsked) { //Instead of a while loop trying every combination, we randomize only between the useAble words int useAbleWords = UseAbleWords(alreadyAsked, out int[] indexOfUseAbleWords); int randomIndex = RandomProvider.Random.Next(0, useAbleWords - 1); return indexOfUseAbleWords[randomIndex]; int UseAbleWords(bool[] alreadyAsked, out int[] indexOfUseAbleWords) { int count = CountUseAbleWords(alreadyAsked); indexOfUseAbleWords = new int[count]; int j = 0; for (int i = 0; i < alreadyAsked.Length; i++) { if (!alreadyAsked[i]) { indexOfUseAbleWords[j] = i; j++; } } return count; } int CountUseAbleWords(bool[] alreadyAsked) { int count = 0; for (int i = 0; i < alreadyAsked.Length; i++) { if (!alreadyAsked[i]) { count++; } } return count; } } /// /// Sorts the vocabulary items using the CompareTo method of the class. /// private void Sort() { for (int i = 0; i < _vocabularyItems.Length - 1; i++) { int result = _vocabularyItems[i].CompareTo(_vocabularyItems[i + 1]); if (result > 0) { Swap(i, i + 1); } } void Swap(int i, int j) { (_vocabularyItems[i], _vocabularyItems[j]) = (_vocabularyItems[j], _vocabularyItems[i]); } } /// /// Creates a array from the raw words. /// /// Raw vocabulary read from a file /// A for each (valid) word private static VocabularyItem[] CreateVocabularyItems(string[][] wordsAndTranslations) { VocabularyItem[] vocabularyItemsTemp = new VocabularyItem[wordsAndTranslations.Length]; bool[] definedItems = new bool[wordsAndTranslations.Length]; int usedItems = 0; for (var i = 0; i < wordsAndTranslations.Length; i++) { if (wordsAndTranslations[i].Length == 2) { usedItems++; definedItems[i] = true; vocabularyItemsTemp[i] = new VocabularyItem(wordsAndTranslations[i][WordIdx], wordsAndTranslations[i][TranslationIdx]); } } VocabularyItem[] vocabularyItems = new VocabularyItem[usedItems]; int j = 0; for (int i = 0; i < wordsAndTranslations.Length; i++) { if (definedItems[i]) { vocabularyItems[j] = vocabularyItemsTemp[i]; j++; } } return vocabularyItems; } }