generateWordPairs function Null safety

Iterable<WordPair> generateWordPairs(
  1. {int maxSyllables = maxSyllablesDefault,
  2. int top = topDefault,
  3. bool safeOnly = safeOnlyDefault,
  4. Random? random}
)

Randomly generates nice-sounding combinations of words (compounds).

Will only return word combinations that are maxSyllables long. This applies to the joined word, so that, for example, timetime will not pass when maxSyllables == 2 because as a single word it would be pronounced something like "time-ee-time", which is 3 syllables.

By default, this function will generate combinations from all the top words in the database (adjectives and nouns). You can tighten it by providing top. For example, when top is 10, then only the top ten adjectives and nouns will be used for generating the combinations.

By default, the generator will not output possibly offensive compounds, such as 'ballsack' or anything containing 'Jew'. You can turn this behavior off by setting safeOnly to false.

You can inject Random using the random parameter.

Implementation

Iterable<WordPair> generateWordPairs(
    {int maxSyllables = maxSyllablesDefault,
    int top = topDefault,
    bool safeOnly = safeOnlyDefault,
    Random? random}) sync* {
  final rand = random ?? _random;

  bool filterWord(String word) {
    if (safeOnly && unsafe.contains(word)) return false;
    return syllables(word) <= maxSyllables - 1;
  }

  List<String> shortAdjectives;
  List<String> shortNouns;
  if (maxSyllables == maxSyllablesDefault &&
      top == topDefault &&
      safeOnly == safeOnlyDefault) {
    // The most common, precomputed case.
    shortAdjectives = adjectivesMonosyllabicSafe;
    shortNouns = nounsMonosyllabicSafe;
  } else {
    shortAdjectives =
        adjectives.where(filterWord).take(top).toList(growable: false);
    shortNouns = nouns.where(filterWord).take(top).toList(growable: false);
  }

  String pickRandom(List<String> list) => list[rand.nextInt(list.length)];

  // We're in a sync* function, so `while (true)` is okay.
  // ignore: literal_only_boolean_expressions
  while (true) {
    String prefix;
    if (rand.nextBool()) {
      prefix = pickRandom(shortAdjectives);
    } else {
      prefix = pickRandom(shortNouns);
    }
    final suffix = pickRandom(shortNouns);

    // Skip combinations that clash same letters.
    if (prefix.codeUnits.last == suffix.codeUnits.first) continue;

    // Skip combinations that create an unsafe combinations.
    if (safeOnly && unsafePairs.contains("$prefix$suffix")) continue;

    final wordPair = WordPair(prefix, suffix);
    // Skip words that don't make a nicely pronounced 2-syllable word
    // when combined together.
    if (syllables(wordPair.join()) > maxSyllables) continue;
    yield wordPair;
  }
}