Files
anagram-generator/docs/LETTER_REMOVAL_FEATURE.md
2025-11-06 22:34:21 +01:00

8.1 KiB

Fonctionnalité de retrait de lettres

Vue d'ensemble

La fonctionnalité de retrait de lettres permet de générer des anagrammes plus prononçables en supprimant stratégiquement certaines lettres du mot source. Cette approche est particulièrement utile pour créer des pseudonymes à partir de mots difficiles à prononcer.

Motivation

Certains mots contiennent des combinaisons de lettres qui rendent difficile la création d'anagrammes prononçables :

  • Mots avec peu ou pas de voyelles (ex: "rhythm", "strength")
  • Mots avec de nombreuses consonnes consécutives
  • Mots longs avec une distribution difficile de lettres

Le retrait stratégique de lettres permet d'augmenter considérablement le taux de réussite et la qualité des pseudonymes générés.

Utilisation

Option CLI

-r, --remove-letters <NOMBRE>

Autorise le retrait jusqu'à <NOMBRE> lettres pour maximiser la prononçabilité.

Exemples

Mot difficile sans voyelles

# Sans retrait : aucun résultat avec score ≥ 60
cargo run -- --word bcdfghjkl --count 5 --min-score 60
# Résultat: No anagrams generated.

# Avec retrait : résultats possibles
cargo run -- --word bcdfghjkl --count 5 --min-score 40 --remove-letters 5

Mot avec consonnes consécutives

# Sans retrait
cargo run -- --word strength --count 10 --min-score 60
# Résultat: No anagrams generated.

# Avec retrait de 2 lettres
cargo run -- --word strength --count 10 --min-score 60 --remove-letters 2
# Résultats: thsetr, rtethg, trgent, hgestn, etc.

Algorithme

Stratégie adaptative

L'algorithme utilise une stratégie LetterRemovalStrategy::Adaptive qui :

  1. Explore différentes configurations : Teste 0, 1, 2, ..., N retraits de lettres
  2. Sélection aléatoire : Choisit aléatoirement quelles lettres retirer
  3. Critères de sélection :
    • Priorise le score de prononçabilité le plus élevé
    • À score égal, préfère les mots plus longs (moins de retraits)

Pseudo-code

pour chaque tentative de génération:
    meilleur_anagramme = None

    pour nombre_retraits de 0 à max_removals:
        lettres_gardées = sélection_aléatoire(source, taille - nombre_retraits)
        anagramme_candidat = mélanger(lettres_gardées)
        score = évaluer_prononçabilité(anagramme_candidat)

        si score >= score_minimum:
            si meilleur_anagramme == None ou score > meilleur_score:
                meilleur_anagramme = anagramme_candidat
            sinon si score == meilleur_score et len(candidat) > len(meilleur):
                meilleur_anagramme = anagramme_candidat

    retourner meilleur_anagramme

Limites

  • Longueur minimale : Au moins 1 lettre doit rester
  • Limite de retrait : min(max_removals, len(mot) - 2)
  • Pas de retrait excessif : Garde au moins 2 caractères pour maintenir un sens

Architecture logicielle

Enum LetterRemovalStrategy

pub enum LetterRemovalStrategy {
    /// No letters will be removed
    None,
    /// Remove up to N letters to maximize pronounceability
    Adaptive { max_removals: usize },
}

Configuration

// Par défaut : pas de retrait
let config = GenerationConfig::default();
assert_eq!(config.letter_removal, LetterRemovalStrategy::None);

// Avec retrait
let config = GenerationConfig::default()
    .allow_removing_letters(3);

// Ou explicitement
let config = GenerationConfig::default()
    .with_letter_removal(LetterRemovalStrategy::Adaptive { max_removals: 3 });

Méthodes du générateur

impl<R: Rng, S: PronounceabilityScorer> AnagramGenerator<R, S> {
    // Point d'entrée selon la stratégie
    fn try_generate_one(...) -> Option<Anagram>

    // Génération sans retrait (comportement original)
    fn try_generate_without_removal(...) -> Option<Anagram>

    // Génération avec retrait adaptatif
    fn try_generate_with_removal(...) -> Option<Anagram>

    // Essai avec un nombre spécifique de retraits
    fn try_with_specific_removals(...) -> Option<Anagram>
}

Tests

Couverture des tests

10 tests dédiés dans tests/letter_removal_tests.rs :

  1. Configuration :

    • test_letter_removal_disabled_by_default
    • test_letter_removal_can_be_enabled
    • test_config_builder_with_letter_removal
    • test_letter_removal_strategy_with_method
  2. Comportement :

    • test_generation_without_removal_produces_same_length
    • test_generation_with_removal_may_produce_shorter_words
    • test_letter_removal_respects_max_removals
    • test_letter_removal_maintains_min_word_length
  3. Efficacité :

    • test_letter_removal_improves_pronounceability
    • test_letter_removal_with_good_word

Exécuter les tests

# Tous les tests
cargo test

# Tests spécifiques au retrait de lettres
cargo test --test letter_removal_tests

# Un test particulier
cargo test test_letter_removal_improves_pronounceability

Performance

Impact sur le temps d'exécution

Le retrait de lettres ajoute une complexité computationnelle :

  • Sans retrait : O(1) par tentative (un seul shuffle)
  • Avec retrait (N max) : O(N) par tentative (N+1 shuffles)

Optimisations

  1. Early exit : Si un score parfait est atteint avec 0 retrait, arrêt immédiat
  2. Limite adaptative : Ne teste pas plus de retraits que nécessaire
  3. Sélection intelligente : Préfère les mots plus longs à score égal

Recommandations

  • Petites valeurs : Utilisez --remove-letters 2-3 pour la plupart des cas
  • Valeurs moyennes : --remove-letters 4-5 pour des mots très difficiles
  • Augmentez les tentatives : Combinez avec --max-attempts 5000+ pour des mots problématiques

Cas d'usage

1. Génération de pseudonymes courts

cargo run -- --word "christopher" --count 10 --min-score 70 --remove-letters 5
# Génère des pseudonymes de 8-13 lettres prononçables

2. Mots techniques ou étrangers

cargo run -- --word "krzyzewski" --count 5 --min-score 50 --remove-letters 4
# Adapte des mots difficiles en pseudonymes prononçables

3. Amélioration du taux de réussite

# Faible taux de réussite sans retrait
cargo run -- --word "complexity" --count 20 --min-score 75

# Meilleur taux avec retrait
cargo run -- --word "complexity" --count 20 --min-score 75 --remove-letters 3

4. Création de noms de marque

cargo run -- --word "innovative" --count 15 --min-score 80 --remove-letters 2
# Génère des noms courts et mémorables

Principes SOLID respectés

Single Responsibility Principle

  • LetterRemovalStrategy : Définit la stratégie
  • Méthodes séparées pour chaque comportement

Open/Closed Principle

  • Extensible : Nouvelles stratégies peuvent être ajoutées
  • Fermé : Code existant non modifié

Liskov Substitution Principle

  • Toute stratégie respecte le contrat
  • Comportement prévisible

Dependency Inversion Principle

  • Configuration injectable
  • Pas de dépendance hard-codée

Limitations actuelles

  1. Sélection aléatoire : Les lettres à retirer sont choisies aléatoirement

    • Amélioration possible : Cibler les consonnes problématiques
  2. Pas de cache : Recalcule à chaque tentative

    • Amélioration possible : Mémoriser les scores calculés
  3. Pas de heuristiques phonétiques : Ne considère pas la structure phonétique

    • Amélioration possible : Retirer préférentiellement certaines consonnes

Extensions possibles

Stratégies avancées

pub enum LetterRemovalStrategy {
    None,
    Adaptive { max_removals: usize },
    // Nouvelles stratégies possibles :
    TargetedConsonants { max_removals: usize },
    PreserveVowels { min_vowels: usize },
    PhoneticOptimization { target_score: u32 },
}

Configuration fine

pub struct AdaptiveRemovalConfig {
    pub max_removals: usize,
    pub prefer_consonant_removal: bool,
    pub preserve_starting_letter: bool,
    pub target_length: Option<usize>,
}

Références