Lexicasius/WordGen/Model/Generator.cs
Thoscellen 39783cd91e init
2020-05-16 17:45:13 +02:00

236 lines
7.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WordGen.Model.Exceptions;
using WordGen.View.LocalizationString;
namespace WordGen.Model {
/// <summary>
/// Représente un générateur de mot utilisant un syllabaire donnée et d'autres informations sur la manière de générer des mots.
/// </summary>
class Generator {
protected Syllabary _syllabary;
protected uint _lenght = 0;
protected string _syntaxe;
protected Random _r = new Random();
protected StringBuilder _word;
protected GeneratorSettings _genSett;
/// <summary>
/// Instantie un générateur de mot en utilisant un syllabaire et une longueure de mot.
/// </summary>
/// <param name="thisSyllabary">Le syllabaire dans lequel l'application puise ses éléments.</param>
/// <param name="wordLenght">La longueur (approximative) des mots à produire.</param>
/// <param name="allowSyllable">Autorise l'utilisation de syllabes dans la composition.</param>
public Generator(Syllabary thisSyllabary, uint wordLenght, GeneratorSettings mySettings = null) {
this._syllabary = thisSyllabary;
this._lenght = wordLenght;
if (mySettings == null)
mySettings = new GeneratorSettings();
this._genSett = mySettings;
this._syntaxe = convertLenghtToSyntaxe();
}
public Generator(Syllabary thisSyllabary, string thisSyntax) {
this._syllabary = thisSyllabary;
this._syntaxe = thisSyntax;
}
protected string convertLenghtToSyntaxe() {
StringBuilder syntaxer = new StringBuilder();
for (int i = 0; i < _lenght; i++) {
if (i == 0) {
if (_syllabary.vowels.Count > 0 && _r.Next(101) < _genSett._vowelBeginProba) {
syntaxer.Append('v');
continue;
} else if (_syllabary.syllables.Count > 0 && _r.Next(101) < _genSett._syllableBeginProba) {
syntaxer.Append('s');
continue;
}
}
// s'il y a des syllabes et que le hazard veux qu'on utilise une syllabe maintenant...
if (_syllabary.syllables.Count > 0 && _r.Next(101) < _genSett._syllableProba) {
// ...on ajoute une syllabe.
syntaxer.Append('s');
// si c'est le premier charactère et que le hazard le veux...
} else if (_syllabary.consonants.Count > 0 && _syllabary.vowels.Count > 0) {
// si rien de tout ça n'est arrivé, on met une consonne et une voyelle.
syntaxer.Append("cv");
} else if (_syllabary.vowels.Count > 0) {
syntaxer.Append('v');
} else if (_syllabary.consonants.Count > 0) {
syntaxer.Append('c');
} else if (_syllabary.syllables.Count > 0) {
syntaxer.Append('s');
} else {
throw new GeneratorException("Impossible de générer des mots à partir du syllabaire choisit. Le syllabaire doit contenir des voyelles, des consonnes ou des syllabes.");
}
}
return syntaxer.ToString();
}
public Dictionary<string, GeneratorException> generateWords(decimal thisMuch) {
var results = new Dictionary<string, GeneratorException>();
var courage = 5;
for (int i = 0; i < thisMuch; i++) {
_syntaxe = convertLenghtToSyntaxe();
try {
// generation of a word.
string aWord = this.generateOneWord();
results.Add(aWord, null);
} catch (NoBeforeSyllableMatchException nbsme) {
results.Add(nbsme.wordSoFar, nbsme);
} catch (EmptyConsonnantListException ecle) {
results.Add(ecle.wordSoFar, ecle);
} catch (EmptySyllableListException esle) {
results.Add(esle.wordSoFar, esle);
} catch (EmptyVowelListException evle) {
results.Add(evle.wordSoFar, evle);
} catch (GeneratorException ge) {
results.Add(ge.wordSoFar, ge);
//} catch(ArgumentNullException ) {
// continue;
} catch (ArgumentException) {
if (courage <= 0) {
break;
}
i--;
courage--;
continue;
}
// other exception are managed upstair
}
return results;
}
protected string generateOneWord() {
_word = new StringBuilder();
char previousLetter = '0';
foreach (char letter in _syntaxe) {
switch (letter) {
case 'c':
//if counsonne.count != 0
_word.Append(selectAConsonnant());
break;
case 'v':
_word.Append(selectAVowel());
break;
case 's':
_word.Append(selectASyllable(previousLetter));
break;
default:
break;
}
previousLetter = letter;
}
return _word.ToString();
}
protected string selectAVowel() {
int aNumber = _r.Next(_syllabary.vowels.Count);
return _syllabary.vowels.ElementAt(aNumber);
}
protected string selectAConsonnant() {
int aNumber = _r.Next(_syllabary.consonants.Count);
return _syllabary.consonants.ElementAt(aNumber);
}
protected string selectASyllable(char previousLetter = '0') {
int aNumber = _r.Next(_syllabary.syllables.Count);
string candidat = _syllabary.syllables.ElementAt(aNumber);
switch (_syllabary.beforeSyllable) {
// Comble d'un caractère adpaté avant la syllabe.
case BeforeSyllable.AutoInsert:
if (!isAttachable(previousLetter, candidat)) {
switch (previousLetter) {
case 'c':
candidat = this.selectASyllable() + candidat;
break;
case 'v':
candidat = this.selectAConsonnant() + candidat;
break;
case 's':
default:
break;
}
}
break;
// Choisit une syllable compatible avec le caractère précéent.
case BeforeSyllable.AutoSelect:
// Toutes les syllables peuvent candidater.
List<string> remaningCandidats = new List<string>();
remaningCandidats.AddRange(_syllabary.syllables);
// tant que la syllabe candidate n'est pas attachable avec le caractère précedent, on en choisit un autre
while (!isAttachable(previousLetter, candidat)) {
remaningCandidats.Remove(candidat);
// Si à la fin aucun candidat ne peux prétendre aller avec le caractère précédent, on lève une exception.
if (remaningCandidats.Count() == 0) {
throw new NoBeforeSyllableMatchException(_word.ToString(), candidat, _syntaxe, _syllabary);
}
aNumber = _r.Next(remaningCandidats.Count());
candidat = _syllabary.syllables.ElementAt(aNumber);
}
break;
// Ne fais pas de changement de la syllabe choisit
case BeforeSyllable.AsIs:
default:
break;
}
return candidat;
}
protected bool isAttachable(char previousLetter, string candidat) {
switch (previousLetter) {
// cas consonne
case 'c':
// pour chaque consonne dans la syllabaire
foreach (string aCons in _syllabary.consonants) {
// si le candidat commence avec cette consomne.
if (candidat.StartsWith(aCons)) {
// alors ce candidat ne peux pas être utilisé.
return false;
}
}
break;
// cas voyelle
case 'v':
foreach (string aVow in _syllabary.vowels) {
if (candidat.StartsWith(aVow)) {
return false;
}
}
break;
// cas syllabe
case 's':
// toute syllabe est compatible avec les autres.
return true;
// autres cas (dont '0')
default:
// tout les syllables sont compatible
return true;
}
return true;
}
}
}