exercism

Exercism - Pig Latin

This post shows you how to get Pig Latin exercise of Exercism.

Stevinator Stevinator
11 min read
SHARE
exercism dart flutter pig-latin

Preparation

Before we click on our next exercise, let’s see what concepts of DART we need to consider

Pig Latin Exercise

So we need to use the following concepts.

String Split Method

The split() method divides a string into a list of substrings. When called with a space ' ', it splits the string into words.

void main() {
  String text = "hello world";
  
  // Split by space
  List<String> words = text.split(' ');
  print(words); // [hello, world]
  
  // Process each word
  for (var word in text.split(' ')) {
    print(word); // hello, world
  }
}

Map Method

The map() method transforms each element in a collection. It’s perfect for translating each word in a sentence.

void main() {
  List<String> words = ['hello', 'world'];
  
  // Transform each word
  var translated = words.map((word) => '${word}ay');
  print(translated.toList()); // [helloay, worlday]
  
  // Use with split
  String text = "hello world";
  var result = text.split(' ').map((word) => '${word}ay');
  print(result.toList()); // [helloay, worlday]
}

String Join Method

The join() method combines all elements of a list into a single string, with an optional separator between elements.

void main() {
  List<String> words = ['helloay', 'worlday'];
  
  // Join with space
  String sentence = words.join(' ');
  print(sentence); // "helloay worlday"
  
  // Chain with map
  String text = "hello world";
  String result = text.split(' ').map((word) => '${word}ay').join(' ');
  print(result); // "helloay worlday"
}

String StartsWith Method

The startsWith() method checks if a string begins with a specific substring. It’s useful for checking prefixes.

void main() {
  String word = "xray";
  
  // Check if starts with prefix
  print(word.startsWith('xr')); // true
  print(word.startsWith('yt')); // false
  print(word.startsWith('a')); // false
  
  // Use in conditionals
  if (word.startsWith('xr') || word.startsWith('yt')) {
    print("Rule 1 applies");
  }
}

String Contains Method

The contains() method checks if a string contains a specific character or substring. It’s useful for checking if a character is a vowel.

void main() {
  String vowels = 'aeiou';
  
  // Check if character is a vowel
  print(vowels.contains('a')); // true
  print(vowels.contains('e')); // true
  print(vowels.contains('x')); // false
  
  // Check first character
  String word = "apple";
  print(vowels.contains(word[0])); // true (a is a vowel)
  
  // Use in conditionals
  if (vowels.contains(word[0])) {
    print("Starts with vowel");
  }
}

String Indexing

Strings can be indexed like arrays to access individual characters. You can check specific positions in a string.

void main() {
  String word = "hello";
  
  // Access characters by index
  print(word[0]); // 'h'
  print(word[1]); // 'e'
  print(word[2]); // 'l'
  
  // Check first character
  char first = word[0];
  print(first); // 'h'
  
  // Use in conditionals
  if (word[0] == 'a') {
    print("Starts with 'a'");
  }
}

String Substring Method

The substring() method extracts a portion of a string. It takes a start index and optionally an end index.

void main() {
  String word = "hello";
  
  // Get substring from index to end
  String rest = word.substring(2);
  print(rest); // "llo"
  
  // Get substring with start and end
  String middle = word.substring(1, 4);
  print(middle); // "ell"
  
  // Split word into parts
  int splitIndex = 2;
  String part1 = word.substring(0, splitIndex); // "he"
  String part2 = word.substring(splitIndex);    // "llo"
  String result = part2 + part1;
  print(result); // "llohe"
}

While Loops

While loops repeatedly execute a block of code as long as a condition is true. They’re perfect for finding positions in strings.

void main() {
  String word = "hello";
  int i = 0;
  
  // Iterate through characters
  while (i < word.length) {
    print(word[i]); // h, e, l, l, o
    i++;
  }
  
  // Find first vowel
  int index = 0;
  while (index < word.length && !'aeiou'.contains(word[index])) {
    index++;
  }
  print(index); // 1 (first vowel 'e' at index 1)
}

Helper Methods

Helper methods break down complex logic into smaller, reusable functions. They improve code readability and maintainability.

String translate(String text) {
  return text.split(' ').map(_translateWord).join(' ');
}

// Helper method: translate a single word
String _translateWord(String word) {
  // Translation logic...
}

// Helper method: check if starts with vowel
bool _startsWithVowel(String word) {
  return 'aeiou'.contains(word[0]);
}

Conditional Logic

Conditional statements allow you to execute different code based on conditions. This is essential for handling different translation rules.

void main() {
  String word = "apple";
  
  // Check different conditions
  if (_startsWithVowel(word)) {
    // Rule 1: starts with vowel
    print('${word}ay');
  } else if (word.startsWith('xr')) {
    // Rule 1: starts with "xr"
    print('${word}ay');
  } else {
    // Rule 2: starts with consonants
    // Move consonants to end...
  }
}

String Interpolation

String interpolation allows you to embed expressions and variables directly within strings using ${expression} or $variable.

void main() {
  String word = "hello";
  String suffix = "ay";
  
  // Build string with interpolation
  String result = '${word}${suffix}';
  print(result); // "helloay"
  
  // Combine parts
  String part1 = "ell";
  String part2 = "oh";
  String combined = '${part1}${part2}ay';
  print(combined); // "ellohay"
}

Increment Operator

The increment operator (++) increases a variable by 1. It’s commonly used in loops to move through string indices.

void main() {
  int i = 0;
  
  // Increment
  i++;
  print(i); // 1
  
  // Use in loops
  String word = "hello";
  int index = 0;
  while (index < word.length) {
    print(word[index]);
    index++; // Move to next character
  }
}

Introduction

Your parents have challenged you and your sibling to a game of two-on-two basketball. Confident they’ll win, they let you score the first couple of points, but then start taking over the game. Needing a little boost, you start speaking in Pig Latin, which is a made-up children’s language that’s difficult for non-children to understand. This will give you the edge to prevail over your parents!

Instructions

Your task is to translate text from English to Pig Latin. The translation is defined using four rules, which look at the pattern of vowels and consonants at the beginning of a word. These rules look at each word’s use of vowels and consonants:

  • vowels: the letters a, e, i, o, and u
  • consonants: the other 21 letters of the English alphabet

Rule 1

If a word begins with a vowel, or starts with “xr” or “yt”, add an “ay” sound to the end of the word.

For example:

  • “apple” → “appleay” (starts with vowel)
  • “xray” → “xrayay” (starts with “xr”)
  • “yttria” → “yttriaay” (starts with “yt”)

Rule 2

If a word begins with one or more consonants, first move those consonants to the end of the word and then add an “ay” sound to the end of the word.

For example:

  • “pig” → “igp” → “igpay” (starts with single consonant)
  • “chair” → “airch” → “airchay” (starts with multiple consonants)
  • “thrush” → “ushthr” → “ushthray” (starts with multiple consonants)

Rule 3

If a word starts with zero or more consonants followed by “qu”, first move those consonants (if any) and the “qu” part to the end of the word, and then add an “ay” sound to the end of the word.

For example:

  • “quick” → “ickqu” → “ickquay” (starts with “qu”, no preceding consonants)
  • “square” → “aresqu” → “aresquay” (starts with one consonant followed by “qu”)

Rule 4

If a word starts with one or more consonants followed by “y”, first move the consonants preceding the “y” to the end of the word, and then add an “ay” sound to the end of the word.

Some examples:

  • “my” → “ym” → “ymay” (starts with single consonant followed by “y”)
  • “rhythm” → “ythmrh” → “ythmrhay” (starts with multiple consonants followed by “y”)

How can we translate to Pig Latin?

To translate text to Pig Latin:

  1. Split into words: Divide the text by spaces
  2. Translate each word: Apply the appropriate rule to each word
  3. Join results: Combine translated words back into a sentence

For each word:

  • Rule 1: If starts with vowel, “xr”, or “yt” → add “ay” to end
  • Rule 2-4: Find where consonants end (first vowel, or special cases)
    • Rule 3: “qu” is treated as a unit (move it together)
    • Rule 4: “y” after consonants acts as a vowel
  • Move consonant cluster to end and add “ay”

The key insight is finding the split point where consonants end and the vowel part begins, handling special cases like “qu” and “y” after consonants.

Solution

String translate(String text) {
  return text.split(' ').map(_translateWord).join(' ');
}

String _translateWord(String word) {
  // Rule 1: Vowel at start, or "xr"/"yt" prefix
  if (_isRule1(word)) {
    return '${word}ay';
  }

  // Rules 2, 3, 4: Move consonant cluster to end
  final splitIndex = _findSplitIndex(word);
  return '${word.substring(splitIndex)}${word.substring(0, splitIndex)}ay';
}

bool _isRule1(String word) {
  return _startsWithVowel(word) || 
         word.startsWith('xr') || 
         word.startsWith('yt');
}

bool _startsWithVowel(String word) {
  return 'aeiou'.contains(word[0]);
}

int _findSplitIndex(String word) {
  var i = 0;

  while (i < word.length) {
    final char = word[i];

    // Found a vowel (but not 'y' at the beginning)
    if ('aeiou'.contains(char)) {
      return i;
    }

    // Rule 4: 'y' after consonants acts as a vowel
    if (char == 'y' && i > 0) {
      return i;
    }

    // Rule 3: Handle "qu" as a unit
    if (i < word.length - 1 && word.substring(i, i + 2) == 'qu') {
      return i + 2;
    }

    i++;
  }

  return i;
}

Let’s break down the solution:

  1. String translate(String text) - Main method that translates a sentence:

    • text.split(' '): Splits the text into individual words
    • .map(_translateWord): Translates each word using the helper method
    • .join(' '): Joins the translated words back into a sentence with spaces
    • Returns the complete translated sentence
  2. String _translateWord(String word) - Translates a single word:

    • if (_isRule1(word)): Checks if Rule 1 applies (starts with vowel, “xr”, or “yt”)
    • return '${word}ay': If Rule 1, simply add “ay” to the end
    • final splitIndex = _findSplitIndex(word): Otherwise, find where to split the word
    • word.substring(splitIndex): Gets the part from split point to end (vowel part)
    • word.substring(0, splitIndex): Gets the part from start to split point (consonants)
    • return '${word.substring(splitIndex)}${word.substring(0, splitIndex)}ay': Moves consonants to end and adds “ay”
  3. bool _isRule1(String word) - Checks if Rule 1 applies:

    • _startsWithVowel(word): Checks if word starts with a vowel
    • word.startsWith('xr'): Checks if word starts with “xr”
    • word.startsWith('yt'): Checks if word starts with “yt”
    • Returns true if any condition is true (uses OR operator ||)
  4. bool _startsWithVowel(String word) - Checks if word starts with a vowel:

    • 'aeiou'.contains(word[0]): Checks if the first character is in the vowel string
    • Returns true if first character is a, e, i, o, or u
  5. int _findSplitIndex(String word) - Finds where to split the word:

    • var i = 0: Start at the beginning of the word
    • while (i < word.length): Loop through each character
  6. Vowel check: if ('aeiou'.contains(char)):

    • If current character is a vowel, return its index
    • This handles Rule 2 (consonants followed by vowel)
  7. Rule 4 check: if (char == 'y' && i > 0):

    • char == 'y': Current character is ‘y’
    • i > 0: ‘y’ is not at the beginning (after consonants)
    • Returns index of ‘y’ (treats ‘y’ as vowel when after consonants)
  8. Rule 3 check: if (i < word.length - 1 && word.substring(i, i + 2) == 'qu'):

    • i < word.length - 1: Ensure we can check two characters
    • word.substring(i, i + 2) == 'qu': Check if current position starts “qu”
    • return i + 2: Return index after “qu” (treats “qu” as a unit)
  9. i++ - Move to next character:

    • Increments index to continue searching
  10. return i - Fallback:

    • Returns word length if no vowel found (shouldn’t happen in valid words)

The solution efficiently translates text to Pig Latin by splitting words, identifying the appropriate rule, and moving consonant clusters to the end while handling special cases like “qu” and “y” after consonants.


A video tutorial for this exercise is coming soon! In the meantime, check out my YouTube channel for more Dart and Flutter tutorials. 😉

Visit My YouTube Channel
Stevinator

Stevinator

Stevinator is a software engineer passionate about clean code and best practices. Loves sharing knowledge with the developer community.