236 lines
7.1 KiB
C#
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;
|
|
}
|
|
|
|
|
|
}
|
|
}
|