I grew up in the countryside of northern Germany. Growing up sorrounded by woods and fields you get to appreciate some rather traditional, maybe even old-fashioned parts of German culture. One of these things is learning to play card games like āSkatā or āDoppelkopfā.
I remember my father and my uncles playing Doppelkopf for countless hours every year when we visited my grandmother (also an avid Doppelkopf player) for Christmas. Later at school, people played Skat or Doppelkopf in their breaks. Going to the pub you could sometimes spot people playing these games as well.
āDie Skatpartieā by Josef Wagner-Hƶhenberg
Luckily, I learned the complex rules of Doppelkopf from my parents when I was a child. We played here and there. I was good enough to internalize the basic rules but never good enough that I could challenge more experienced players. Try playing with your grandparents and youāll learn what losing looks like. After all, these folks have been playing that game all their lives. Theyāve seen it all, have played every hand there is to play and recognize every tiny mistake you do. Itās intimidating.
Earlier this year, some friends asked me if I wanted to join their Doppelkopf group in Hamburg. Knowing the basics of the game I was excited to join. Now weāre meeting once a week at a random pub or down at the harbour, have a beer or two and play Doppelkopf. Itās great fun and a nice breakout from my otherwise overly digitalised daily life. Every now and then a stranger stops by to kibitz. They always seem fascinated or even nostalgic by the archaic scenery of people playing traditional card games these days.
Doppelkopf is a complex game. It has a lot of rules, exceptions from these rules and the occasional exception from these exceptions. Itās best played with four players who form two different parties in each game (Re and Kontra). Itās all about taking tricks and getting the beter score for your party. To make it even more difficult, every group of players tends to have their very own set of extra rules. The game is full of jargon. For bystanders a conversation about the game simply sounds like a bunch of gibberish. Despite the steep learning curve itās really rewarding to learn the game. The countless hours of fun and socializing really make up for it.
Playing Doppelkopf in a Cafe in Hamburg, not meant to be a shameless plug for Astra
I have to admit that I kind of suck at Doppelkopf. My friends often kick my ass. Iām not good at memorizing all the special rules that are out there. I donāt dare to play a Solo because I know Iāll screw up. Iām bad at tactics and I canāt remember which cards have already been played in the current game. Fortunately Doppelkopf is a team effort and you rarely play on your own in a game. So my friends often make up for my lack of skills.
At one point I thought that I should have some practice to improve my game. As you might imagine, practising multiplayer game on your own is quite challenging. I looked out for Doppelkopf browser games and Android apps and sure enough there are plenty of them. Unfortunately almost none of them lived up to my expectations. They required you to register with your Facebook account, were full of ads or in-app purchases and required you to be online the entire time. I was rather looking for a no-frills, no-bullshit version. Something I could play as much as Iād like without being bugged with ads or having to fear about my personal activity being tracked with every step I take.
Iāll Build My Own Doppelkopf Game
Being a software developer I obviously found the best solution for this problem. āIām gonna build this myself!ā was my proclaimed goal.
Yeah, right, because that always works so well. Having quite a track record for starting side projects that I never finish (who hasnāt?) I know Iām probably lying to myself when I say that Iāll definitely finish that one. Still, I decided to build my own game, mainly for two reasons:
- Implementing your own Doppelkopf game will teach you a lot about the game
- I donāt get to do too much coding these days so a side project is more than welcome
I also found a niche for my game to live in. Seeing all the ad-infested bells-and-whistles games with social media integration out there, I knew I should build a game that has nothing of that. I thought about the great 2048 game and how often I used to play it on my daily commute because it was free, simple, didnāt require any installation and allowed me to play even without an internet connection. I knew that my browser game should have similar goals. Thatās why I decided that the Doppelkopf game Iām building should be
- free (as in free beer), forever, no discussion
- Open Source, available for everyone to see, modify and learn
- without ads or in-app purchases
- easy to start, ideally just loading a website
- available and playable when youāre offline
Thatās a lot. Especially the offline part is giving me a headache as this means Iād need to build an AI for the other players. Iāve never done that one before so thatās going to be a nice challenge. Still, Iām certain that itās worth it. I want the game to be as open and respectful of the user as possible. No bullshit, no screwing up the users.
Implementing the Game
Finding a tech stack was quite straightforward. As it should be an offline-first browser game there isnāt much technology to choose from. Back in the days I could have chosen Flash. Luckily, these days are over. I donāt want the user to install any plugins to play the game. They should just visit a website in their browser and be ready to play. This left JavaScript as the only option. Itās understood by every browser out there and has matured significantly over the recent years.
I sensed my chance to refresh on my frontend JavaScript skills for this task. I knew I wanted to use the latest JavaScript features available but had to keep in mind that even modern browsers do not support all of these features yet. So I got my hands dirty and set up Webpack and Babel to allow me to write the latest ECMAScript and to transpile it to JavaScript that todayās browsers can understand.
Fortunately I had a short-cut to understanding the setup of these tools. Peter Jang has written an excellent introduction to modern JavaScript that got me up and running in a breeze.
The Card Game Kata
I quickly noticed that writing a card game as code makes for a fantastic code kata. If you think of it as a domain modelling excercise it shapes up quite nicely.
- A
card
has asuite
and arank
- The
rank
of a card defines itāsvalue
- A
deck
consists of 40cards
1 - Each
player
has ahand
of 10cards
- A
hand
can be Re or Kontra - A
trick
goes to theplayer
who played the highestcard
And so on.
So far Iāve been busy capturing the essence of Doppelkopf in a domain model. With the help of Jest I worked on this in a strictly test-driven way. Being test-driven (and having set up a CI server) allowed me to work on my Doppelkopf game whenever I had a few minutes to spare. I could split the complex ruleset of Doppelkopf into hundreds of small-scoped bits and pieces that could be implemented within a couple of minutes. Having tests and a continuous integration server in place allows me to come back to where I left at any time.
Iām taking some extra care of massaging my domain model into a shape thatās pleasant to use and easy to read. With a domain as tangible as a card game this has worked really well. Take a look at these code snippets to see what Iām talking about:
test('a hand without queen of clubs is kontra', () => {
const cards = [
queen.of(suites.spades)
]
const hand = new Hand(cards);
expect(hand.isKontra()).toBeTruthy();
expect(hand.isRe()).toBeFalsy();
});
class Hand {
// [...]
value() {
return this.cards
.map(card => card.value)
.reduce((acc, value) => acc + value, 0);
}
// [...]
}
test('hand has a value', () => {
const cards = [
queen.of(suites.spades),
ten.of(suites.hearts),
ace.of(suites.diamonds)
]
const hand = new Hand(cards);
expect(hand.value()).toBe(24);
});
These tests are easy to understand, even if you donāt know the rules of Doppelkopf. They serve as a good documentation, make it easy for me to reason about small portions of the complex game at a time and the sum of these small portions add up to the wonderful game that is Doppelkopf.
Moving on
Right now my card browser game is only a bunch of domain classes and tests. Thereās nothing visible and Iām not even talking about anything thatās remotely playable yet. Still, this excercise has been so much fun for me and allowed me to work in a pace that keeps me motivated to move on, one simple rule at a time. The source code is already available on GitHub, feel free to check it out and track the progress.
There will be huge challenges further down the road. When I told my friends that Iām building a Doppelkopf game, they first raised the question how I wanted to build an AI for singleplayer mode. Actually, I donāt have a clue. Iāve never done this before and donāt know how to approach this. I guess thereāll be some research for me to do and a long way until I have build something that is more clever than a bunch of if-else
statements.
My friends also asked if there will ever be a multiplayer option for this game. This, however, is so far further down the road, that Iām not even thinking about it yet. I guess implementing multiplayer should be possible and is probably even easier than building a good enough AI. Still, for building a multiplayer version Iād first have to build a game thatās at least somewhat playable.
Iām really excited about this side project. Iām in here for the challenge and hope that reasoning deeply about the game makes me a better Doppelkopf player after all. Letās see how long I can keep this project alive and letās keep fingers crossed that it doesnāt end up at the side project cemetary like all the other things Iāve successfully abandoned.
Stay tuned!
Footnotes
-
At least in the version my friends and I play. We donāt play with nines. ā©