Kata Challenge Wordle JLDD
Kata are code puzzles that will help you hone your skills.
I enjoy creating and solving code katas. Code Kata are programming puzzles to help you hone your programming skills.
I wrote an article called “Learn to Kata and Kata to Learn” for the book “97 Things Every Java Programmer Should Know”, and a link to the article is available for free here at publications on Medium.
The Wonderful World of Wordle
Wordle is a very popular online puzzle game where you have six chances to guess a five letter word.
Each guess leads to learning which characters correspond to the characters in the word. You are given hints with colors that let you know if you have correctly inserted a letter in the correct position, if the letter is in the word but in the wrong position, or if the letter does not correspond to any letter in the word.
You can learn more about the Wordle craze in this article.
Wordle explained: Everything you need to know to master the viral word game
Wordle is a viral word game recently acquired by the New York Times for several million. But…
JLDD = Jet Lag Driven Development
In the old days, when tech conferences and world travel were commonplace, a few Java champions(Jose Pomar, Nikhil Naniwadekarand I) shared coding challenges on Twitter while we were at conferences (usually JavaOne/Oracle CodeOne).
We all had varying degrees of jet lag during conferences, so we decided to use the hashtag JLDD (jet lag driven development) when posting programming challenges.
Most often, programming tasks were aimed at solving problems with Java collections or streams. I usually posted solutions using Eclipse Collections.
Throughout the pandemic, we have shared JLDD issues with each other on Twitter from time to time, even though the jet lag has long since ended. A few weeks ago I shared Haiku Kata using Java Text Blocks and Eclipse Collections.
Haiku in Java using Text Blocks
Creative writing combined with Java text blocks and Eclipse collections
Jose Pomar then went above and beyond and coded the JLDD challenge live in the 25 minute JEP Cafe #9 video. He does an amazing job explaining Eclipse Collections and Java 17 solutions. Great job!
Wordle Kata
Jose Pomar This week I was sent a Wordle Kata JLDD challenge as a test, for which I had to write code that passes this test. I like this type of kata that follows the classic TDD style using a “test first” approach. Above is test code for kata using simple JUnit 5 assertions.
The rules based on this test are pretty simple.
If the letter in the guess string does not match the letter in the hidden word, replace the character in the output with “.”
If the letter in the guess string matches the letter in the hidden word and the letter is in the same position, then replace the character with a capital letter.
If the letter in the guess string matches the letter in the hidden word, but the letter is in a different position, then replace the character with a lowercase letter.
If the letter matches but appears more times in the guessed string than in the hidden word, then replace the additional characters in the output with “.”.
My first solution using Eclipse Collections
The solution I came up with looked like this and passed all the tests.
The code takes a guess, compares each letter to the hidden word, and if there is a direct match, prints an uppercase letter, otherwise prints a lowercase letter if there is an indirect match, or “.” if there is no match or the letter is an additional matching character.
Method collectWithIndex
type CharAdapter
converts the string guessChars
one character at a time. At first I thought that none char
values will not be boxed as objects Character
but it turned out I was wrong.
Method collectWithIndex
accepts CharIntToObjectFunction
which means that the values char
for each output symbol will be packed as objects Character
.
This also means that we don’t have a purely primitive version collectWithIndex
in Eclipse Collections, as is the case with collectChar
. I think this is probably acceptable in most cases and shouldn’t be too costly for this particular use case.
I don’t think adding a purely primitive named version collectCharWithIndex
would make sense.
However, there is a bigger problem than packaging. char
values in the form Character
objects before generating output String
. I found that there is no test case and an additional rule that we need to add to the kata.
Rule: favor direct matches over indirect ones.
I have added the following test case which causes my first solution to fail.
Let me zoom in so you can see the test case more clearly.
In this case, the letter “a” will have a direct match in third position, but indirect matches in guess should be ignored in favor of a direct match in third position.
My updated solution
For those who know me, you should know that I am somewhat obsessed. ensuring good symmetry in the Eclipse Collection API.
In this particular use case, it would be ideal if there was an equivalent selectWithIndex
And rejectWithIndex
available for primitive collection types in Eclipse Collections. This particular use case might make me agree and add the missing methods.
However, there is an alternative method that I can use to implement the equivalent of these two methods. This is the method injectIntoWithIndex
.
Here is my updated solution using injectIntoWithIndex
for creating CharBag
with the remaining characters that don’t have direct matches.
If you want to understand how injectIntoWithIndex
works, you can read the following blog about injectionInto (EC by Example: InjectInto). The injectInto method can be used to implement most of the iteration patterns, which also applies to injectIntoWithIndex
. These are both magical and powerful methods.
Update: Alternative solution using zipChar
Sometimes when you work on the same code for 18 years, you forget things. Luckily, a friend will occasionally remind you of things you may have forgotten. It happened this week when Vladimir Zakharov shared another solution for Wordle JLDD Kata on Twitter using the method named zipChar
.
Vlad’s solution is pretty cool and it’s definitely not the approach I would have thought of. I forgot that zip
a primitive version was available in Eclipse Collections. Every primitive type OrderedIterable
in Eclipse Collections supports zip
of the same type. So a CharAdapter
there is a method zipChar
.
I soon remembered that there was a blog I wrote over four years ago about primitive zip
.
Once I saw Vlad’s solution, I realized that I could write an alternative to my own solution using zipChar
for replacement injectIntoIndex
And collectWithIndex
.
Two solutions that use zipChar
differ significantly in the algorithm they use to calculate the final result of the guess string.
Source for my final solution with Eclipse Collections
I created my final solution to the Wordle Kata JLDD problem using Eclipse Collections. I’m looking forward to seeing a pure Java 17 solution from Jose Pomar.
. I always learn something new and interesting about Java from José that I didn’t know before.
import org.eclipse.collections.api.bag.primitive.MutableCharBag;
import org.eclipse.collections.impl.factory.Strings;
import org.eclipse.collections.impl.factory.primitive.CharBags;
import org.eclipse.collections.impl.string.immutable.CharAdapter;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class WordleTest
{
@Test
public void wordleTest()
{
Assertions.assertEquals(".....", new Wordle("aaaaa").guess("bbbbb"));
Assertions.assertEquals("A....", new Wordle("aaaaa").guess("abbbb"));
Assertions.assertEquals(".A...", new Wordle("aaaaa").guess("babbb"));
Assertions.assertEquals("..A..", new Wordle("aaaaa").guess("bbabb"));
Assertions.assertEquals("...A.", new Wordle("aaaaa").guess("bbbab"));
Assertions.assertEquals("....A", new Wordle("aaaaa").guess("bbbba"));
Assertions.assertEquals(".a...", new Wordle("abbbb").guess("caccc"));
Assertions.assertEquals("..a..", new Wordle("abbbb").guess("ccacc"));
Assertions.assertEquals("...a.", new Wordle("abbbb").guess("cccac"));
Assertions.assertEquals("....a", new Wordle("abbbb").guess("cccca"));
Assertions.assertEquals("A....", new Wordle("abbbb").guess("accca"));
Assertions.assertEquals("A....", new Wordle("abbbb").guess("accaa"));
Assertions.assertEquals("A..a.", new Wordle("aabbb").guess("accaa"));
Assertions.assertEquals("AA...", new Wordle("aabbb").guess("aacaa"));
Assertions.assertEquals("...aa", new Wordle("aabbb").guess("cccaa"));
Assertions.assertEquals("..A..", new Wordle("bbabb").guess("aaaaa"));
Assertions.assertEquals("AAAAA", new Wordle("aaaaa").guess("aaaaa"));
Assertions.assertEquals("BRAVO", new Wordle("bravo").guess("bravo"));
}
record Wordle(String string)
{
Wordle(String string)
{
this.string = string.toLowerCase();
}
public String guess(String guess)
{
CharAdapter guessChars = Strings.asChars(guess.toLowerCase());
CharAdapter hiddenChars = Strings.asChars(this.string);
MutableCharBag remaining = hiddenChars
.injectIntoWithIndex(
CharBags.mutable.empty(),
(bag, each, i) -> guessChars.get(i) != each ? bag.with(each) : bag);
return guessChars.collectWithIndex((each, i) -> hiddenChars.get(i) == each ?
Character.toUpperCase(each) : this.replaceDifferentPositionOrNoMatch(remaining, each))
.makeString("");
}
private char replaceDifferentPositionOrNoMatch(MutableCharBag remaining, char each)
{
return remaining.remove(each) ? each : '.';
}
}
}
Final thoughts
I hope you enjoyed this blog about my JLDD Kata solutions using Eclipse collections. Of course, I would be happy to see other solutions to these problems so that we can all learn new and different solutions to programming problems. These solutions can be in Java using your favorite libraries or even in another programming language.
Thanks for taking the time to read!