exercism

Exercism - Kindergarten Garden

This post shows you how to get Kindergarten Garden exercise of Exercism.

Stevinator Stevinator
10 min read
SHARE
exercism dart flutter kindergarten-garden

Preparation

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

Kindergarten Garden Exercise

So we need to use the following concepts.

Enums

Enums define a set of named constants. They’re perfect for representing a fixed set of values like plants and students.

enum Plant {
  radishes,
  clover,
  violets,
  grass,
}

enum Student {
  Alice,
  Bob,
  Charlie,
  David,
  Eve,
  Fred,
  Ginny,
  Harriet,
  Ileana,
  Joseph,
  Kincaid,
  Larry,
}

void main() {
  Plant plant = Plant.grass;
  Student student = Student.Alice;
  print(plant); // Plant.grass
  print(student); // Student.Alice
}

Classes and Constructors

Classes define blueprints for objects. Constructors initialize instances with specific values. Initializer lists can be used to set fields before the constructor body runs.

class KindergartenGarden {
  final String _row1;
  final String _row2;
  
  // Constructor with initializer list
  KindergartenGarden(String diagram)
      : _row1 = diagram.split('\n')[0],
        _row2 = diagram.split('\n')[1];
}

void main() {
  String diagram = "VR\nRG";
  KindergartenGarden garden = KindergartenGarden(diagram);
  // _row1 = "VR", _row2 = "RG"
}

String split() Method

The split() method divides a string into a list of substrings. When called with '\n', it splits the string by newline characters.

void main() {
  String diagram = "VRCG\nVRCC";
  
  // Split by newline
  List<String> rows = diagram.split('\n');
  print(rows); // ["VRCG", "VRCC"]
  
  // Access rows
  String row1 = rows[0]; // "VRCG"
  String row2 = rows[1]; // "VRCC"
  
  // Use in constructor
  String row1 = diagram.split('\n')[0];
  String row2 = diagram.split('\n')[1];
}

Static Const Maps

Static const maps are class-level constants that can be accessed without creating an instance. They’re perfect for lookup tables like character-to-plant mappings.

class KindergartenGarden {
  // Static const map - shared by all instances
  static const _plantMap = {
    'G': Plant.grass,
    'C': Plant.clover,
    'R': Plant.radishes,
    'V': Plant.violets,
  };
  
  // Access without instance
  Plant getPlant(String code) {
    return _plantMap[code]!;
  }
}

void main() {
  // Access static const map
  Plant grass = KindergartenGarden._plantMap['G']!;
  print(grass); // Plant.grass
}

String Indexing

Strings can be accessed by index to get individual characters. The index starts at 0 for the first character.

void main() {
  String row = "VRCG";
  
  // Access by index
  char first = row[0]; // 'V'
  char second = row[1]; // 'R'
  char third = row[2]; // 'C'
  char fourth = row[3]; // 'G'
  
  // Use for extracting plants
  int col = 0;
  char plant1 = row[col]; // 'V'
  char plant2 = row[col + 1]; // 'R'
}

Enum values and indexOf()

Enum values can be accessed using .values, which returns a list of all enum values. The indexOf() method finds the index of a specific value in that list.

enum Student {
  Alice, Bob, Charlie, David;
}

void main() {
  // Get all enum values
  List<Student> allStudents = Student.values;
  print(allStudents); // [Student.Alice, Student.Bob, ...]
  
  // Find index of specific student
  int aliceIndex = Student.values.indexOf(Student.Alice);
  print(aliceIndex); // 0
  
  int bobIndex = Student.values.indexOf(Student.Bob);
  print(bobIndex); // 1
  
  // Use to calculate column
  Student student = Student.Alice;
  int col = Student.values.indexOf(student) * 2;
  print(col); // 0 (Alice gets columns 0-1)
}

List Literals

List literals allow you to create lists directly with square brackets. They’re perfect for building result lists.

void main() {
  // Create list with elements
  List<Plant> plants = [
    Plant.violets,
    Plant.radishes,
    Plant.violets,
    Plant.radishes,
  ];
  
  // Build list dynamically
  List<Plant> result = [
    _plantMap['V']!,
    _plantMap['R']!,
    _plantMap['V']!,
    _plantMap['R']!,
  ];
  
  // Use with calculations
  int col = 0;
  List<Plant> studentPlants = [
    _plantMap[row1[col]]!,
    _plantMap[row1[col + 1]]!,
    _plantMap[row2[col]]!,
    _plantMap[row2[col + 1]]!,
  ];
}

Null Assertion Operator (!)

The null assertion operator (!) tells Dart that a value won’t be null. It’s used when you’re certain a map lookup will succeed.

void main() {
  Map<String, Plant> plantMap = {
    'G': Plant.grass,
    'C': Plant.clover,
  };
  
  // Null assertion - we know 'G' exists
  Plant grass = plantMap['G']!;
  print(grass); // Plant.grass
  
  // Use in list building
  String code = 'V';
  List<Plant> plants = [
    plantMap[code]!, // Safe to use ! (we know code is valid)
  ];
}

Arithmetic Operations

Arithmetic operations like multiplication (*) and addition (+) are used to calculate column positions.

void main() {
  // Calculate column based on student index
  int studentIndex = 0; // Alice
  int col = studentIndex * 2; // 0 (Alice gets columns 0-1)
  
  int studentIndex2 = 1; // Bob
  int col2 = studentIndex2 * 2; // 2 (Bob gets columns 2-3)
  
  // Access adjacent columns
  char plant1 = row[col]; // First cup
  char plant2 = row[col + 1]; // Second cup
}

Initializer Lists

Initializer lists allow you to initialize fields before the constructor body runs. They’re perfect for parsing input data.

class KindergartenGarden {
  final String _row1;
  final String _row2;
  
  // Initializer list - runs before constructor body
  KindergartenGarden(String diagram)
      : _row1 = diagram.split('\n')[0],
        _row2 = diagram.split('\n')[1];
}

// Equivalent to:
KindergartenGarden(String diagram) {
  _row1 = diagram.split('\n')[0];
  _row2 = diagram.split('\n')[1];
}

Introduction

The kindergarten class is learning about growing plants. The teacher thought it would be a good idea to give the class seeds to plant and grow in the dirt. To this end, the children have put little cups along the window sills and planted one type of plant in each cup. The children got to pick their favorites from four available types of seeds: grass, clover, radishes, and violets.

Instructions

Your task is to, given a diagram, determine which plants each child in the kindergarten class is responsible for.

There are 12 children in the class:

Alice, Bob, Charlie, David, Eve, Fred, Ginny, Harriet, Ileana, Joseph, Kincaid, and Larry.

Four different types of seeds are planted:

PlantDiagram encoding
GrassG
CloverC
RadishR
VioletV

Each child gets four cups, two on each row:

[window][window][window]
........................ # each dot represents a cup
........................

Their teacher assigns cups to the children alphabetically by their names, which means that Alice comes first and Larry comes last.

Example

Here is an example diagram representing Alice’s plants:

[window][window][window]
VR......................
RG......................

In the first row, nearest the windows, she has a violet and a radish. In the second row she has a radish and some grass.

Your program will be given the plants from left-to-right starting with the row nearest the windows. From this, it should be able to determine which plants belong to each student.

For example, if it’s told that the garden looks like so:

[window][window][window]
VRCGVVRVCGGCCGVRGCVCGCGV
VRCCCGCRRGVCGCRVVCVGCGCV

Then if asked for Alice’s plants, it should provide:

Violets, radishes, violets, radishes

While asking for Bob’s plants would yield:

Clover, grass, clover, clover

How do we determine which plants belong to each child?

To determine each child’s plants:

  1. Parse diagram: Split the diagram by newline to get two rows
  2. Calculate column: Each child gets 2 columns (2 cups per row)
    • Alice (index 0) → columns 0-1
    • Bob (index 1) → columns 2-3
    • Charlie (index 2) → columns 4-5
    • Formula: column = studentIndex * 2
  3. Extract plants: For each child, get 4 plants:
    • Row 1, column col: first cup
    • Row 1, column col + 1: second cup
    • Row 2, column col: third cup
    • Row 2, column col + 1: fourth cup
  4. Convert to enum: Use map to convert characters to Plant enum values

The key insight is that children are assigned alphabetically, so each child’s index in the Student enum corresponds to their column position (multiplied by 2, since each child gets 2 columns).

Solution

enum Plant {
  radishes,
  clover,
  violets,
  grass,
}

enum Student {
  Alice,
  Bob,
  Charlie,
  David,
  Eve,
  Fred,
  Ginny,
  Harriet,
  Ileana,
  Joseph,
  Kincaid,
  Larry,
}

class KindergartenGarden {
  final String _row1;
  final String _row2;
  
  static const _plantMap = {
    'G': Plant.grass,
    'C': Plant.clover,
    'R': Plant.radishes,
    'V': Plant.violets,
  };

  KindergartenGarden(String diagram) 
      : _row1 = diagram.split('\n')[0],
        _row2 = diagram.split('\n')[1];

  List<Plant> plants(Student student) {
    final col = Student.values.indexOf(student) * 2;
    
    return [
      _plantMap[_row1[col]]!,
      _plantMap[_row1[col + 1]]!,
      _plantMap[_row2[col]]!,
      _plantMap[_row2[col + 1]]!,
    ];
  }
}

Let’s break down the solution:

  1. enum Plant - Plant enum:

    • Defines the four plant types
    • Values: radishes, clover, violets, grass
    • Used to represent plants in the result
  2. enum Student - Student enum:

    • Defines all 12 students in alphabetical order
    • Order matches assignment order (Alice first, Larry last)
    • Used to identify which student’s plants to retrieve
  3. class KindergartenGarden - Main class:

    • Encapsulates the garden diagram
    • Stores the two rows as private fields
    • Contains plant lookup map and plants method
  4. final String _row1 and final String _row2 - Row storage:

    • Private fields storing the two rows of the diagram
    • Example: “VRCG” and “VRCC”
  5. static const _plantMap = {...} - Plant lookup map:

    • Static const map shared by all instances
    • Maps character codes to Plant enum values
    • ‘G’ → Plant.grass, ‘C’ → Plant.clover, etc.
  6. KindergartenGarden(String diagram) - Constructor:

    • Takes diagram string with two rows separated by newline
    • Uses initializer list to parse rows
  7. : _row1 = diagram.split('\n')[0] - Parse first row:

    • Splits diagram by newline
    • Gets first element (row 1)
    • Stores in _row1 field
  8. : _row2 = diagram.split('\n')[1] - Parse second row:

    • Gets second element (row 2)
    • Stores in _row2 field
  9. List<Plant> plants(Student student) - Get student’s plants:

    • Takes a Student enum value
    • Returns list of 4 Plant enum values
    • Represents the student’s four cups
  10. final col = Student.values.indexOf(student) * 2 - Calculate column:

    • Gets student’s index in enum (0 for Alice, 1 for Bob, etc.)
    • Multiplies by 2 (each student gets 2 columns)
    • Example: Alice (index 0) → col = 0
    • Example: Bob (index 1) → col = 2
  11. return [...] - Build result list:

    • List literal with 4 elements
    • Each element is a Plant enum value
    • Order: row1[col], row1[col+1], row2[col], row2[col+1]
  12. _plantMap[_row1[col]]! - First plant (row 1, first cup):

    • Accesses character at column col in row 1
    • Looks up in plant map
    • Null assertion (!) because we know the character is valid
    • Example: row1=“VRCG”, col=0 → ‘V’ → Plant.violets
  13. _plantMap[_row1[col + 1]]! - Second plant (row 1, second cup):

    • Accesses character at column col + 1 in row 1
    • Example: row1=“VRCG”, col=0 → ‘R’ → Plant.radishes
  14. _plantMap[_row2[col]]! - Third plant (row 2, first cup):

    • Accesses character at column col in row 2
    • Example: row2=“VRCC”, col=0 → ‘V’ → Plant.violets
  15. _plantMap[_row2[col + 1]]! - Fourth plant (row 2, second cup):

    • Accesses character at column col + 1 in row 2
    • Example: row2=“VRCC”, col=0 → ‘R’ → Plant.radishes

The solution efficiently determines each child’s plants by calculating their column position based on their alphabetical index, then extracting the four characters (two from each row) that correspond to their cups. The static const map provides a clean way to convert character codes to Plant enum values.


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.