Pinochle 2.0 (or how to manage cards in a GUI)

Your JoeDog’s Pinochle contains a bug. Under yet-to-be-determined circumstances, some cards won’t render. It’s not clear why. No exceptions are thrown; the cards just silently disappear. It only happens on startup. If you have cards when the game begins, you’ll have cards when it ends.

The game was written in java and we used the Overlap Layout to help manage the presentation of the hands. It was easy to implement but it led to some design gymnastics. For example, each player had a reference to the JPanel on which his cards were positioned. We suspect this is associated with the disappearances.

Rather than fight this design any further, Your JoeDog decided to rework the architecture. He wanted the GUI to be as dumb as possible. A thread runs in the background and it just paints cards on the table. That thread runs in an endless loop. It asks the model, “What am I painting? Where am I putting it?” The GUI — or View, in MVC parlance — also listens for mouse events. When the user clicky-clicks, it sends coordinates to the model to determine if a card was clicked. If a card was selected, the controller determines what should become of that.

To make this system work, Your JoeDog needed a way to track the coordinates of the cards. It was then that he stumbled upon JGameGrid. The author, Aegidius Plüss, treats each game piece as an Actor. Each actor contains a Location object which holds its positional coordinates. Your JoeDog didn’t steal the entire GameGrid but he did incorporate that notion into his pinochle game. When the View thread asks “What am I painting?” The model hands it a list of cards. When it needs to know “Where am I putting it?” It just asks each card. 

Version 2.0 should be available shortly. 



Parse The Version Number With Ant

“The best programmers are all alike; every shitty programmer is shitty in his own special way.” –Anna Karenina

Earlier Your JoeDog mentioned a trait of good programmers. They model data so each element is stored in only one location. This principle is known as a Single Source of Truth. To illustrate that principle, he pointed to siege’s version numbering. The number had to be available in both the program and its helper scripts. In order to uphold SSoT, he stored the number in version.c and parsed that file with a helper script.

Here’s an astonishing fact: not everyone loves the C programming language. Some of you are Java weenies! Fear not, weenies, for you we have another example.

Same problem, different language. We want to store the version number in one location but it must be available for two mechanisms. The first mechanism is the program itself. That’s important, right? It helps answer the question “Which fscking version am I running?” The other mechanism is ant. When we build our jar file we’d like to add the version number to its name, i.e., pinochle-1.0.7.jar.

Let’s examine this is closer detail after the jump.

Continue reading Parse The Version Number With Ant



ArrayList.ensureCapacity

Have you ever wanted to initialize a java ArrayList to a certain size? You peruse the javadoc and you see what appear to be two different options, one is a constructor option and the other is a chained method.

Here’s the constructor:

ArrayList (int initialCapacity)

Constructs an empty list with the specified initial capacity.

And here’s the method:

void ensureCapacity(int minCapacity)

Increases the capacity of this ArrayList instance, if necessary, to ensure that it can hold at least the number of elements specified by the minimum capacity argument.

And here’s the thing: Neither one changes the logical size of the array. They each change its capacity. That is they change the size it can reach before it has to start copying its values to resize itself. If you do something like the following, you’ll get an IndexOutOfBounds Exception:

ArrayList<String> list = new ArrayList<String>();
list.ensureCapacity(200);
list.add(190, "JoeDog");

Exception in thread "main" java.lang.IndexOutOfBoundsException

If you want to initialize an ArrayList to a particular size, you’ll have to roll your own method:

 private static void ensureSize(ArrayList<?> list, int size) {
   list.ensureCapacity(size);
   while (list.size() < size) {
     list.add(null);
   }
 }

You can call it like this:

ArrayList<Thing> list = new ArrayList<Thing>();
ensureSize(list, 64);

 




It Knows Me Better Than I Know Myself….

robotI write a lot of software with which I interact. If it’s easy for me, then it’s easy for you. I try to keep it easy for me. JoeDog’s Pinochle is the first program against which I’ve competed. It’s been a surreal experience.

The program was designed to be competitive against me. Tonight it took two out of three games. The damn thing knows me inside and out. And why not? I wrote it. And while I can exploit some knowledge of its inter-workings, I can’t predict all its behavior. It was designed to learn bidding from experience.

Bidding is the hardest aspect of this game. The team that wins the bid has an incredible opportunity to earn a lot of points. At the same time, overbids come at a large price. A failure to make the bid means the bid is deducted from your score.

When the game was first released, its bids were implemented programmatically. I like to think I’m a pretty good programmer but that version of the game played like a moran. To improve it, I had the game play itself hundreds of thousands of times. It would store those results and use them to generate future bids.

This implementation has resulted in a much more competitive program. Now it bids more aggressively — much more aggressively. It bids like me which is odd because I didn’t tell it to do that. I told it to learn from its experience and as a result of that experience, its personality morphed into mine.