Trick or Treat: A Halloween Kata

Learn how to use Eclipse Collections APIs in a fun Java code kata.

Is a Cup a Bag?

Kata Time

At Oracle CodeOne last week I co-presented a talk titled “Invest in your Java Katalogue”. I’ve co-presented the talk previously at QCon New York. There is a video of the talk from QCon NY available here. In the talk, I encourage developers to create their own katas to teach themselves new programming skills and then to share those katas with other developers. I often say that we learn best by doing, and the best way to learn is to teach.

More simply:

  1. Do
  2. Teach

So here I am now, practicing what I preach. The rest of this blog will include code for a Halloween Kata using Java 8 with Eclipse Collections. I just developed the kata this evening. There’s perhaps no better way to see how sweet the APIs of Eclipse Collections are than with a cup or Bag of candy. You might also get to see how sweet some of the Java Time APIs are along the way.

Getting Started

You can find Maven coordinates to get the Eclipse Collections binaries here if you want to set up a simple Maven project to work in. To make things even easier, you can also just download the Eclipse Collections Katas from GitHub, import it into your favorite IDE as a Maven project and add a class in the test folder under the Pet Kata. This is exactly what I did. I called my class HalloweenKata. I’ve included the imports I used below to be helpful.

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZoneId;
import java.util.Random;
import java.util.stream.IntStream;

import org.eclipse.collections.api.bag.Bag;
import org.eclipse.collections.api.list.MutableList;
import org.eclipse.collections.api.set.MutableSet;
import org.eclipse.collections.api.tuple.primitive.ObjectIntPair;
import org.eclipse.collections.impl.collector.Collectors2;
import org.eclipse.collections.impl.factory.Lists;
import org.eclipse.collections.impl.factory.Sets;
import org.junit.Assert;
import org.junit.Test;
public class HalloweenKata
{
....
}

Trick or Treat

Here’s an enum of Candy. You can include this as an inner class in HalloweenKata. Do you see all of your Halloween favorites? I left my favorite candy bar out — Whatchamacallit? Too tempting.

enum Candy
{
SNICKERS,
MILKYWAY,
REESES_PIECES,
REESES_PEANUT_BUTTER_CUPS,
M_AND_M_S,
TWIZZLERS,
WHOPPERS,
ONE_HUNDRED_GRAND,
SKITTLES,
TWIX,
CANDY_CORN,
JOLLY_RANCHERS,
NERDS,
ALMOND_JOY,
MOUNDS,
BABY_RUTH,
THREE_MUSKETEERS,
HERSHEYS,
CRUNCH,
HERSHEYS_KISSES,
MIKE_AND_IKE,
MILK_DUDS,
SWEDISH_FISH,
YORK_PEPPERMINT_PATTY
}

Time to send the kids out trick or treating

We usually see several rounds of kids come to our house looking for candy on Halloween. I’ve grouped them by three educational groupings in the United States to keep things simple.

private MutableList<Bag<Candy>> collectBagsOfCandy()
{
LocalDate halloween =
LocalDate.of(2018, Month.OCTOBER, 31);
LocalTime elementarySchoolStart =
LocalTime.NOON.plus(Duration.ofHours(3));
LocalTime middleSchoolStart =
elementarySchoolStart.plus(Duration.ofHours(2));
LocalTime highSchoolStart =
middleSchoolStart.plus(Duration.ofHours(2));
long candyCount = 250L;

Bag<Candy> elementarySchoolBag = this.trickOrTreat(
halloween.atTime(elementarySchoolStart),
candyCount);
Bag<Candy> middleSchoolBag = this.trickOrTreat(
halloween.atTime(middleSchoolStart),
candyCount);
Bag<Candy> highSchoolBag = this.trickOrTreat(
halloween.atTime(highSchoolStart),
candyCount);

return Lists.mutable.with(
elementarySchoolBag,
middleSchoolBag,
highSchoolBag);
}

When each group goes trick or treating, they get a random collection of candy in their bags, seeded by their start time.

public Bag<Candy> trickOrTreat(LocalDateTime time, long candyCount)
{
ZoneId newYork = ZoneId.of("America/New_York");
IntStream limit = new Random(
time.atZone(newYork).toEpochSecond())
.ints(0, Candy.values().length - 1)
.limit(candyCount);
Bag<Candy> bagOfCandy = limit.mapToObj(i -> Candy.values()[i])
.collect(Collectors2.toBag());
System.out.println(bagOfCandy.topOccurrences(10));
return bagOfCandy;
}

A fix the test style kata

This test is missing some code. Your job is to fill in the missing code with code that will compile and pass the test. This is where you get to try things out and experiment as you look to learn some unfamiliar or even practice familiar APIs in Eclipse Collections.

@Test
public void topCandy()
{
MutableList<Bag<Candy>> bagsOfCandy =
this.collectBagsOfCandy();

// Hint: Flatten the Bags of Candy into a single Bag
Bag<Candy> bigBagOfCandy = null;

// Hint: Find the top occurrence in the bag and convert that
// to a set of Candy.
MutableSet<Candy> mostCommon = null;
Assert.assertEquals(
Sets.mutable.with(Candy.CRUNCH),
mostCommon);

// Hint: Find the top 10 occurrences of Candy in each of the
// bags and intersect them to see which are the common ones
// between all of the bags.
MutableSet<Candy> commonInTop10 = null;
Assert.assertEquals(
Sets.mutable.with(Candy.REESES_PIECES, Candy.CRUNCH),
commonInTop10);
}

Note: I have tried running these tests on a Mac Book Pro and Windows 10 Machine with Java 8. The results are consistent between runs, but I have not verified if they are consistent on any other platforms and Java versions.

Kata to learn, Kata to teach

I put this kata together quickly today to show how you can explore different APIs in a programming language and library by building a kata. You could try this same kata in different languages or with different collections libraries or using Java Streams. It’s really up to you to decide what you want to learn and what you want to teach others. This kata focused on learning and teaching several APIs available on Eclipse Collections types. I built a simple use case to demonstrate these APIs that I thought many developers might find fun and inviting.

I have posted my solutions to the kata.

Happy Halloween!

Eclipse Collections is open for contributions. If you like the library, you can let us know by starring it on GitHub.