Projects from CMU 15-214« back to projects
CMU’s 15-214 class is a principles of software engineering course taught in Java. I was fortunate to take the course under Josh Bloch and Charlie Garrod. I include here some of the projects that I wrote for that course, as they were often interesting both from a programming perspective and of their own accord.
Unfortunately, I am unable to release the source code for these programs due to academic integrity. However, I do have screenshots, and, in some cases, documentation!
“Scrabble with Stuff”
I implemented an expanded version of Scrabble called “Scrabble with Stuff,” which is just like Scrabble except for the addition of special tiles, which players purchase with points and then place on the board; special tiles are hidden to other players, and have some special effect when a tile is played on them.
Here’s a demo of me playing the game against myself on the Greek dictionary. (I’ve cut out boring portions when I was thinking about what words to play!)
Here are some fun facts about my implementation:
I wrote and tested all of the core logic before I wrote any of the GUI; the core was well-enough tested that I found only one minor bug in the core logic.
The core logic is written with an immutable state object. This immutability provides strong guarantees, and makes implementations of certain features much easier than they would otherwise be—in particular, challenges are simply a matter of rolling back to a previous game state, which does not require reversing the effects of mutations but rather simply updating the value of the state reference. (In fact, it’s possible to roll back to any previous state, for the purposes of replaying the history of a game!)
The GUI is written in a functionally reactive style. Unlike the traditional technique of using heavy events that contain information about the new state as instructions about mutations, my design uses a single source of truth (the
GameState), and simply asks components to update themselves whenever an action is performed. This design helps tremendously with encapsulation: components only need to know how to render themselves, and controllers don’t need to worry about what data to pass to what component. Most importantly, it is much easier to show that the views are correct, as they depend only on a single state object and not on a history of past mutations.
All icons are drawn programmatically with the AWT graphics facilities; there are no external resources (except for a dictionary file). This was fun for complex shapes like the bomb tile and the intricate details of the fringes around the board squares. I even have code to draw a perfectly pixel-aligned n-pointed star!
I’ve written tests for the GUI in the form of fixtures for various important components. Each fixture show the component in its most important states, so that I can easily iterate on the design and also so that I can easily identify regressions. Here are some sample fixtures: all the possible states for a board square (the bottom three rows are pulsing because the tiles there are only tentatively placed), and the icons for all the special tiles, at various sizes.
Data visualization framework
With a partner, I wrote a general-purpose data visualization framework. The framework allows clients to supply data source plugins and data view plugins. An arbitrary data source plugin can be used with any data view plugin, as long as it provides data of the right type (e.g., two numeric columns for a scatter plot).
This framework was selected as one of the four best in the class (out of about fifty total), so I provided support for the twenty students who chose to write source and visualization plugins for it. I prepared a “getting started” guide for students, and the formal Javadoc is also available online.
Here are some fun facts about my implementation:
A data view can require that the input be expressed in columns of any desired type. For example, a bubble chart might require three numeric columns (for the position and radius of each point), while a choropleth might require a more exotic “polygon column” in addition to some scalar value. I came up with some clever tricks with generics and static typing to allow this to work completely type-safely; not only does the client code not require any casts, the framework backend doesn’t, either!
The framework supports dynamic (runtime) loading of plugins stored in JAR files, so students don’t have to recompile the framework to link their creations. When selecting a JAR file, the framework will scan it for all implementations of the plugin interfaces, and will register them automatically; on subsequent launches, the selected JAR files and plugins will be remembered and loaded.
The sample plugins that I provided with the framework include basic readers like CSV file input, as well as more interesting algorithms, like an s-expression evaluator for arbitrary parameterized functions and different approaches for k-dimensional randomness (a uniform distribution vs. Bridson’s algorithm). The latter allows for an interesting visualization comparing the uniform distribution with the Poisson-disc sampling (open in new tabs for best comparison). This is, of course, inspired by “Visualizing Algorithms.”