Code and comments

Practical and theoretical aspects of software development

Mastermind in Clojure and Java

200px-Mastermind

Have you heard of mastermind? It’s a logic game in which one player repeatedly tries determine the secret code that another player set at the beginning. With each guess, the player is given information on how many correct pegs his guess contains, and how many are in the correct position. For more details on the rules, check the wikipedia article.

I built a Clojure implementation of Mastermind as a learning project. (Code and details of functionality at github.) My primary goals were to gain familiarity with the language, and to see what the functional programming paradigm feels like when working on a project that is larger than one big function. After I finished, I re-implemented (almost) all of the features in Java for a comparison. (Code also available at github.) Interested in the results? read on.

Some numbers

Lines of code: Clojure 140, Java 450
Source code files: Clojure 5, Java 11

But it’s really worse than that. I didn’t implement a few features in Java, which code have amounted to another hundred lines. And about 10% of the lines in Clojure were comments, but I didn’t add any comments to the Java code. So I don’t think that it’s unreasonable to expect four times as many lines of code in Java compared to Clojure.

Semantics

Suppose you need to compare two lists, and count the number of pegs that are the same, and in the same place. This is necessary to determine the number of colored pegs given in response to a guess in Mastermind. Here’s how you do it in Java:

private static int exactMatches(List<Pre> guess, List<Pre> actual) {
    int matches = 0;
    for (int idx = 0; idx < actual.size(); idx++) {
        if (actual.get(idx) ==  guess.get(idx)) {
            matches++;
        }
    }
    return matches;
}

Not too bad, right? Just a loop, with a conditional that increments a counter. But notice that since we are comparing two lists, it is necessary to use the indices. That doesn’t seem like a big deal, because it is common, but understand that this question being asked has nothing to do with indices. Let’s compare this with the Clojure implementation.

(defn exact-matches [guess actual]
  (count (filter true? (map = guess actual))))

In my mind at least, this function is not only more succinct, but far closer to my mental model of what is happening. There is no counter, only a count function. There is no loop containing a conditional, rather a filter function that takes a function and a sequence. For the comparison, map applies the equals function successively to each of the items in the two sequences, producing a boolean sequence. Feel free to browse the code for more Java/Clojure comparisons.

Performance

Unfortunately, Java clearly won regarding performance. I’m not going to include any numbers here, because benchmarking should be done with simpler algorithms, where it is more obviously a fair comparison. Nevertheless, I won’t be recommending Clojure for any performance intensive applications soon.

Conclusion

For algorithmic problems, the flexibility and functional semantics are a huge win for Clojure. The performance is a negative. I didn’t miss Java’s static typing either, but that’s unfair, given how small this project was. As for objects, I haven’t missed them so far, and I’m loving the ease of use of Clojure collections. Time for another Clojure project, this time something that makes use of Clojure’s concurrency language features.

Written by Eric Wilson

December 11, 2012 at 12:58 pm

Posted in projects

Tagged with , ,

One Response

Subscribe to comments with RSS.

  1. […] Mastermind in Clojure and Java avendo tempo… ::: Code and comments […]


Comments are closed.