Tuesday, December 2, 2025

Advent of Code 2025, Day 2

The puzzle for Day 2 was about finding the needles in a haystack.  Or the bad SKUs in the product catalogue, which really clicked to with my retail experience at Dick's Sporting Goods. 

Part 1

Given list of numerical ranges, in form "x-y", find all the numeric values in the range (inclusive) that are the first half repeated.  so 55 (5 twice), 6464 (64 twice), and 123123 (123 twice)

The input might look something like this

11-22,95-115,998-1012,1188511880-1188511890,222220-222224

For a solution, I started with the LongRange type.  Ok, I didn't.  I started with IntRange, but I eventually had to upgrade everything to LongRange.  (LongRange is just more fun to say.  Am I right?). So my RangeParse class was just


class RangeParser {

fun parse(string: String): LongRange {

val numbers = string.split("-")
.map { it.toLong() }

if (numbers[1] < numbers[0]) {
throw IllegalArgumentException("Invalid range")
}

return numbers[0].rangeTo(numbers[1])
}

}

Where the input is one of the substrings out of the input like "11-22" or "1188511880-1188511890".  Turns out I didn't need the ordering check to make sure the second value was greater than the first, guess they choose not to throw any garbage data into this set.

Next we have to come up with a way to test each value in the range.  Now you could embed the evaluation in a for loop, but that would make it harder to test.  And while I'm not building these solutions test first, I always find String parsing a challenge, so I did write tests for this.  Back to the question of how to evaluate the Long values for this pattern.  

I decided to use the java.util.function.Predicate<T> interface for this.  I think I could have done this pure Kotlin, but decided to be explicit in this case.   Here's the implementation:


class PartOnePredicate : Predicate<Long> {

fun Int.isEven() : Boolean {
return this % 2 == 0
}

override fun test(t: Long): Boolean {

val stringForm = t.toString()

val l = stringForm.length

return if (l.isEven()) {
val halfLength = l/2
val firstHalf = stringForm.take(halfLength)
val secondHalf = stringForm.takeLast(halfLength)
return firstHalf == secondHalf
} else {
false
}

}

}

I would have sworn there was an "isEven" implementation in the Kotlin standard library, but I couldn't find one.  So, I decided to implement my own with an extension function.  And looking at this again I can see I'm making my code less readable using this single character variable names (l,t).  But they aren't anything meaning, unlike the variables in the second half of the function (pardon the pun). 

So, the answer to the puzzle is given a series of ranges, evaluate all the numbers in the range, idenity these "bad" numbers and sum them up across all the ranges.

Walking the range was really simple:


class RangeProcessor(private val predicate : Predicate<Long>){

fun process(range: LongRange) : Long {

return range
.filter { value -> predicate.test(value) }
.sum()

}

}

Originally, I just created the predicate instance as an attribute, but part 2 of the puzzle changed up the evaluation rules, so I added is a constructor argument.  This take a range, iterates over it, runs each value the Predicate. The predicate acts as a positive filter, meaning only elements that match the filter are included in the output.  Then I just had to sum up what passes the filter.

Then it was simply 


val rangeProcessor = RangeProcessor(predicate)

val answer = ranges.sumOf { range -> rangeProcessor.process(range) }

Admittedly, what I wrote originally was 


ranges.map { rangeProcessor.process(it) }.sum()

IntelliJ recommend the sumOf notation, which is a part of the streams API in the Kotlin standard library.  Another example of the higher level abstracts that can be built on top of Java because Kotlin is effectively a DSL on top of the JDK.

Part 2

Now, the bad numbers an not just "11" but also "111" and "2121212121".  This is where I really needed tests.  The tests for the these Predicate implementation were great opportunities for Parameterized tests in JUnit.   You can do really complex lists of parameters, but I think they work best with single value inputs.  Like this:


class PartTwoPredicateTest {

val predicate = PartTwoPredicate()

@DisplayName("ints with repeated values")
@ParameterizedTest(name = "{index}: {0}")
@ValueSource(ints = [ 11, 22, 99,111,1010,1188511885,565656])
fun `test returns true`(toTest : Int) {
assertEquals(true, predicate.test(toTest.toLong()))
}

@DisplayName("ints that do not have repeated values")
@ParameterizedTest(name = "{index}: {0}")
@ValueSource(ints = [ 12,121, 1234123,2345])
fun `test returns false`(toTest : Int) {
assertEquals(false, predicate.test(toTest.toLong()))
}

}


Everything that was "bad" in Part 1 is still bad, so I decided to leverage the code in PartOnePredicate.  Don't repeat yourself, right?  I implemented this via aggregation, declaring an instance of PartOnePredicate in the PartTwoPredicate.  This could have be done via inheritance, which may have been the best representation of the problem.  But I've gotten away from using class hierarchies and use composition more and more, as it makes testing easier and it you avoid the unintended consequences of inheritance.

My solution for the PartTwoPredicate


class PartTwoPredicate : Predicate<Long> {

private val partOnePredicate = PartOnePredicate()

override fun test(t: Long): Boolean {

return if (!partOnePredicate.test(t)) {
val stringForm = t.toString()
val length = stringForm.length
val halfLength : Int = length/2

val chunks = 1..halfLength
chunks.forEach { chunkSize ->
val sample = stringForm.take(chunkSize)
val regex = Regex("($sample)+")
val matches: Boolean = stringForm.matches(regex)
if (matches) {
return true
}
}
return false
} else {
true
}

}

}

I am NOT proud of this code.  Multiple return statements and regular expressions are both things I like to avoid.  But in this case, it they both just made sense.  I could have manually walked the chunk through the balance of the String, but figured that would be ugly.

Anyway, that's it. Just drop this new predicate class into the RangeProcessor and get a difference answer. The a prime example of the Strategy pattern from the Gang Of Four book.  

See you tomorrow.  

Monday, December 1, 2025

Advent of Code 2025, Day 1

It's that time once again, to tell stories about elves with code. That's right  Advent of Code has come around again. Some folks treat try to solve these challenges with as little code as possible, to learn a new language or leverage the particular strengths of a language. This year I've decide to use the strong types in Kotlin to implement the problem space as closely as possibles using an object heavy approach. Originally that was just going to be "object oriented APIs" with whatever ever I needed to under the covers, but I eventually went full OO with this. 

The problem for Day 1 was based on the dial of a safe. Given the dial starts at 50, if you a apply series of rotations, how many times does the dial stop at 0. For example, given this set of rotations
  
  L68 
  L30 
  R48 
  L5 
  R60 
  L55 
  L1 
  L99 
  R14 
  L82
  
the tumbler would stop on 0 a total of 3 times.

The first step was how to model the inputs.

data class Turn(
     val direction: Direction,
     val quantity: Int)

Nice, clean, immutable data class. These things really don't get enough love. But what is a Direction?
enum class Direction(val abbr: Char, val multiplier: Int) {
    Left('L', -1),
    Right('R', 1);

    companion object {

        private val mapping = entries.associateBy { it.abbr }

        fun lookup(abbr: Char) : Direction{
            return mapping[abbr]?:throw IllegalArgumentException()
        }
    }
}

Maybe that lookup function should be in another class, a DirectionResolver or something like that. I'm focusing on the "modeling" part of OO, not so much the single responsibility principle. This small block of code shows a few neat tricks that Kotlin can provide because it's a DSL on top of Java.

A quick aside: 

You young folk out there don't remember this, but back at the turn of the century, Java didn't have enumerations.  Until Java 5 was released in 2005, you either had to use named int values (I'm looking you java.util.Calendar.December or had to use the boiler plate heavy pattern that Joshua Bloch described in Effective Java.  This frequently got of some "why even bother" kind of looks in the day, but like it says on the tin, it was effective.   I've not picked up a revised edition of the book, but the first edition was transformative for me.

To go from a "R14" to Turn(Direction.Right, 14), I created a class to do the mapping. Ok, I'll let you in on secret. I do love me some single responsibility principle.
class LineMapper() {

    fun map(line: String) : Turn {

        val d: Char = line[0]
        val q = line.substring(1)

        return Turn(
            Direction.lookup(d),
            q.toInt()
        )

    }

}

Processing the data files into a collection of turns is as simple as
    val lines = data.lines()
    val turns = lines.map { lineMapper.map(it) }
    
And you know I had to have a "dial" class.
class Dial() {

	private var currentState: Int =50

    fun turn(turn: Turn) {
       // a bunch of math and conditionals and absolute values
    }
    
    fun getCurrentState() : Int {
        return currentState
    }
    
}

A few design decisions here. 

1) in my original implementation this was data class, just out of habit. But given that the initial value of currentState attribute would never be provided by another class, I removed that keyword. 

 2) Kotlin attributes are public by default, but I made currentState private to secure access to the value. It can only be modified via the turn function.

Like I said above, the initial implementation was on OO in the APIs, as I've demonstrated so far.  And that worked for the first part of the challenge: how many times did the dial stop on 0.

The second part of the challenge was "how many times did the dial SHOW 0".  Now, I could do more math and conditionals and absolute values and track the before and after values from a turn and see if crossed 0.  Instead the code increments or decrements the integer value for ever tick the dial is turned. Which looked like this:

val tick = 1 * turn.direction.multiplier

(1..turn.quantity).forEach { _ ->
    currentState += tick
    if (currentState < 0) {
        currentState = 99
    } else if (currentState > 99) {
        currentState = 0
    }
    if (currentState == 0) {
        passesZero++
    }
}

So, there's just a simple increment operation, the bounds checking and a counter.
This is not going to win any awards for computational efficiency, that's for sure. But one of the strengths of Kotlin is the readability of the code, compared Java and especially to other lower level languages and I think this solution demonstrates that capability.
Ho, ho, ho an 'nat!

Saturday, October 19, 2019

Learning me a Haskell

I was doing more katas on Code Wars this afternoon and came across this one called Isograms. I quickly created a solution in Java which did the thing it needed to do.


    public static boolean isIsogram(final String str) {

        if (str == null) {
            throw new IllegalArgumentException(
               "str parameter may not be null."
            );
        }

        if ("".equals(str)) {
            return  true;
        }

        final String lowerCase = str.toLowerCase();
        final char[] chars = lowerCase.toCharArray();

        final List charactersFound = new ArrayList();

        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            if (charactersFound.contains(c)) {
                return false;
            } else  {
                charactersFound.add(c);
            }
        }

        return true;
    }


Not pretty, not concise, but it gets the job done. I knew that it could be solved far more concisely using streams, so I switched to Kotlin and wrote this.


    fun isIsogram(str: String): Boolean {

        if ("" == str) {
            return true
        }

        val distinctCharacters = str.toLowerCase()
                  .asSequence().distinct().count()

        return str.length == distinctCharacters

    }


I'm pretty sure something similar could be done in Java 8+, but I've been developing in Kotlin almost exclusively for almost two years now, so it's my go-to language for the JVM.

I've trained myself over the years to avoid function chaining so that one line makes my brain itch a bit. However, I think this implementation is much more expressive and concise than what I wrote in Java.

One of the reasons I like Kotlin is the implicit null safety. In the Kotlin solution, I didn't have to protect the function from a null argument value. It makes the solution more concise and easier to parse mentally. If I wanted to allow null as a value, I'd have to add special syntax to support it. That extra step always makes me stop and think is there a better way than allowing a null input and I can typically find a better way.

Using the stream features in my Kotlin solution reminded me that I wanted to learn more about Functional Programming. Code Wars offered a Haskell version of the kata, so I decided to give that a shot.

Unfortunately, I don't know anything about Haskell. Not even how to spell it. I always want to have just one L.

Fortunately, I listened to a lot of the early episodes of The Bikeshed and had heard Sean and Derek mention Miran Lipovaca's Learn You A Haskell website many times.

I started going through the content and found it very accessible. It's a good balance of explanation and examples. Pretty soon I was taking the individual topics and combining them to solve new problems.

For example, during the section on list operations, I was trying to write a function that would remove prune one list from another. That is, given lists A and B return A with everything in B removed. I couldn't find a solution using just the set operators, but once I got to the section on list operations a light bulb went of. After some trial and error, I came up with this:


    filterOut s f  = [ x | x <- s, not (elem x f) ]


For example:

ghci> filterOut ['A'..'Z'] ['I','P']
"ABCDEFGHJKLMNOQRSTUVWXYZ"


And, yes. Deep down inside I still find 3rd grader humor potty funny.

I still don't know enough to solve the Isogram problem in Haskell, but I'm getting close.

Friday, October 18, 2019

The Dubstep Kata

The first kata I trained with on codewars.com was the dubstep kata. To summarize, a DJ creates the dubstep version of a popular song by inserting 1 or more WUBs between any word in the song, or 0 or more before or after the lyric. And because dubstep is always up-tempo, the DJ also removes all the spaces between words and capitalizes all the characters. So, the opening line of Hotel California could be:

ONWUBAWUBWUBDARKWUBWUBDESERTWUBHIGHWAYWUBWUB
but not

WUBONAWUBDARKWUBDESERTWUBHIGHWAY

(there's no WUB between "ON" and "A")
The exercise was to extract the original lyric from the DJ's dubstep version.
My first stab at this was very mechanical. Walk the string looking for "WUB" and then throwing them away. It looked like this:

    public static String SongDecoderAlpha (String song) {

        final StringBuilder builder =  new StringBuilder();

        while (song.length() > 0) {
            if (song.startsWith(WUB)) {
                song = song.substring(3);
            } else {
                int i = song.indexOf(WUB);
                if (i >= 0) {
                    String temp = song.substring(0, i);
                    appendWord(builder, temp);
                    song = song.substring(i);
                } else {
                    appendWord(builder, song);
                    break;
                }
            }
        }

        return builder.toString();

    }

    private static void appendWord(final StringBuilder builder, 
                                   final String temp) {
        if (builder.length() > 0) {
            builder.append(" ");
        }
        builder.append(temp);
    }
I wasn't really excited about this. It did what it needed to do, passed all of the tests, but it is very complex. A while loop with nested booleans. I think it wouldn't be too hard to figure out what it does, but it wouldn't be easy to understand all the permutations. Plus it has the additional appendWord() function, reducing duplicated code and complexity, but also adding another chunk of code to understand. So, I decided to come up with another solution.
    public static String SongDecoderBeta (String song) {

        song = song.replace(WUB, " ");
        song = song.trim();
        while (song.contains("  ")) {
            song = song.replace("  ", " ");
        }

        return song;

    }
This one was better. There are fewer lines of code and no if statements. There is literally almost nothing to it. It also more clearly describes what the solution is:
  1. replace all the WUB tokens with spaces
  2. clean up all the extra spaces
This was ultimately the solution I submitted, though I wasn't really happy with it. The while loop replacing the double spaces with a single space didn't quite sit right with me. After submitting my solution, I looked at what other folks had submitted and I saw that it was possible to use greedy REGEX expressions to do this more concisely. As a rule of thumb, I avoid using regular expressions because they can be hard to understand. In this case, the expression is so simple that the risk of confusion is minimal.
So, a revised implementation would look like this:
    public static String SongDecoder (String song)
    {

        song = song.replace(WUB, " ");
        song = song.trim();
        song = song.replaceAll(" +", " ");

        return song;

    }
Three lines of code and the only thing that is not direct is what the regex is doing, but that's easy enough to look up. I'm not sure which one I'd use in production code.

Thinking about how this solution worked, I realized that the code was extracting the original lyrics by parsing out the WUBs. I decided to experiment with this approach to see if it was more understandable. The result was this:
    public static String SongDecoder(String song)
    {

        final String[] words = song.split(WUB);
        final StringBuilder stringBuilder = new StringBuilder();

        String word;
        for (int i = 0; i < words.length; i++) {
            word = words[i];
            if (word.length() == 0) {
                continue;
            }
            if (stringBuilder.length() > 0) {
                stringBuilder.append(" ");
            }
            stringBuilder.append(word);
        }

        return stringBuilder.toString();

    }

This is better than the original in that it is self-descriptive of the approach. The one thing I hadn't considered was the behavior of String.split() when there consecutive delimiters. For example, the input RWUBWUBWUBLWUB resulted in the following tokens:
[R]
[]
[]
[L]
Not sure if this the defined behavior of split() or not; I didn't dig into it. But that meant I had to add another if statement to handle those empty string tokens. I do like this approach because the code to add a space between words only existed in one branch. This eliminated the need to extract it into another method.

Looking at the lines of code and number of branches, it's easy enough to see which solution is the simplest. But I wanted to quantify the differences. I found the website lizard.ws which offers online complexity analysis of 8 languages, include Java. I plugged in each version of my solution and got the following results:

Solution NLoC Complexity Tokens
mechanical 25 6 (4+2) 160
replace 9 2 51
greedy replace 7 1 40
split 17 4 104

NLoC is Noncommented Lines of Code: anything that isn't a blank line or a comment line.
I think that makes it clear: The greedy replace solution has the lowest possible complexity score and one-third the lines of code and tokens of my original solution. By removing all that other code for your brain to parse, I'm comfortable you'd have the overhead to ponder the regex.

So I changed direction already

A co-worker told me recently that he was similarly decided to start doing practice exercises on codewars.com to expand his skills. 

I hadn't heard of the website, so I checked it out briefly.  I completed one kata in Java to see how it worked.  I liked that the site supports solutions to katas in multiple languages, which would help me with the goal of expanding my fluency.  I also liked that, at least for Java, unit tests are a part of the process, example tests are provided and that I could add my own tests to the suite.

So, I'm going to give this a shot and see what I can get out of it.  I'm also going to do a write up each exercise here to explain my solution and my thought process.