184 lines
No EOL
6.2 KiB
C#
184 lines
No EOL
6.2 KiB
C#
using Figgle;
|
|
|
|
namespace VocabularyTrainer;
|
|
|
|
/// <summary>
|
|
/// Vocabulary trainer.
|
|
/// Based on a supplied vocabulary training cycles are performed.
|
|
/// </summary>
|
|
public sealed class Trainer
|
|
{
|
|
private const int WordIdx = 0;
|
|
private const int TranslationIdx = 1;
|
|
private const int CycleCount = 3;
|
|
private readonly VocabularyItem[] _vocabularyItems;
|
|
|
|
/// <summary>
|
|
/// Constructs a new <see cref="Trainer"/> instance based on the given vocabulary.
|
|
/// </summary>
|
|
/// <param name="wordsAndTranslations">Raw vocabulary read from a file</param>
|
|
public Trainer(string[][] wordsAndTranslations)
|
|
{
|
|
_vocabularyItems = CreateVocabularyItems(wordsAndTranslations);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs a training cycle for <see cref="CycleCount"/> words.
|
|
/// </summary>
|
|
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}");
|
|
|
|
return;
|
|
}
|
|
|
|
Console.ResetColor();
|
|
}
|
|
Console.WriteLine();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prints training statistics to the terminal.
|
|
/// </summary>
|
|
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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Picks the next word by random.
|
|
/// If all words have already been used any one is chosen.
|
|
/// </summary>
|
|
/// <param name="alreadyAsked">An array of flags indicating which words have already been used</param>
|
|
/// <returns>Index of next word to use</returns>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sorts the vocabulary items using the CompareTo method of the <see cref="VocabularyItem"/> class.
|
|
/// </summary>
|
|
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]);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a <see cref="VocabularyItem"/> array from the raw words.
|
|
/// </summary>
|
|
/// <param name="wordsAndTranslations">Raw vocabulary read from a file</param>
|
|
/// <returns>A <see cref="VocabularyItem"/> for each (valid) word</returns>
|
|
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;
|
|
}
|
|
} |