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 { /// /// 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. /// class Generator { protected Syllabary _syllabary; protected uint _lenght = 0; protected string _syntaxe; protected Random _r = new Random(); protected StringBuilder _word; protected GeneratorSettings _genSett; /// /// Instantie un générateur de mot en utilisant un syllabaire et une longueure de mot. /// /// Le syllabaire dans lequel l'application puise ses éléments. /// La longueur (approximative) des mots à produire. /// Autorise l'utilisation de syllabes dans la composition. 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 generateWords(decimal thisMuch) { var results = new Dictionary(); 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 remaningCandidats = new List(); 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; } } }