Voici une solution en C# qui semble fonctionner à partir d'une poignée de cas de test que je lui ai soumis. [Certaines parties de l'expression regex ont été empruntées à un répondeur précédent].
public static bool IsWordNiceable(string word, int maxVowels, int maxConsonants)
{
if (IsUgly(word, maxVowels, maxConsonants)) return false;
int i = 0;
while ((i = word.IndexOf('?', i)) != -1)
{
string newWord = word.Substring(0, i) + "a" + word.Substring(i+1);
bool vowelMakesNice = IsWordNiceable(newWord, maxVowels, maxConsonants);
newWord = word.Substring(0, i) + "b" + word.Substring(i + 1);
bool consonantMakesNice = IsWordNiceable(newWord, maxVowels, maxConsonants);
if (!(vowelMakesNice || consonantMakesNice)) return false;
i++;
}
return true;
}
private static bool IsUgly(string word, int maxVowels, int maxConsonants)
{
string consonants = "bcdfghjklmnpqrstvwxyz";
string vowels = "aeiou";
string uglyRegex = string.Format("([{0}]{{{1},{1}}})|([{2}]{{{3},{3}}})", vowels, maxVowels, consonants, maxConsonants);
Match match = Regex.Match(word.ToLower(), uglyRegex);
return match.Success;
}
Elle teste d'abord le mot donné tel quel pour voir s'il est laid (y compris les points d'interrogation, le cas échéant). Puis elle boucle sur le mot, en remplaçant le premier " ?" par une voyelle et une consonne, et s'appelle en utilisant le nouveau mot. Si le remplacement des voyelles et des consonnes ne parvient pas à rendre le mot agréable, alors cette branche renvoie false (laid).