Showing posts with label games. Show all posts
Showing posts with label games. Show all posts

Tuesday, August 12, 2014

Let's Code!

A recent article in Dr. Dobb’s Journal bemoans the complexity of today’s development toolchains: “it’s hard to get any real programming done”. However, my own experience suggests the opposite: I find programming is now easier than ever, partly due to better tools.

I say “partly” because when I was a kid, it was difficult to obtain code, compilers, and documentation, let alone luxuries like an SCM. I scoured public libraries for books on programming and checked out what they had, which meant I studied languages which I could never use because I lacked the right compiler, or even the right computer. I nagged my parents to buy me expensive books, and occasionally they’d succumb. Perhaps the most cost-efficient were magazines containing program listings which of course had to be keyed in by hand. (One of my most treasured was an issue of Dr. Dobb’s Journal, back when it was in print, and only in print.)

Nowadays, a kid can get free high-quality compilers, code, tutorials, and more at the click of a button. But I believe even without this freer flow of information, programming would still be easier than ever because our tools have improved greatly.


got git?

The author singles out Git as a source of trouble, but the reasoning is suspect. For example, we’re told that with respect to other “SCMs you’ve used…Git almost certainly does those same actions differently.”

This suggests that the author used other SCMs, then tried Git and found it confusing. In contrast, I used Git, then tried other SCMs and found them confusing. I predict as time passes, more and more developers will learn Git first, and their opinions of SCMs will mirror mine.

Nevertheless, I’m leery of ranking the friendliness of tools by the order you picked them up. I hereby propose a different yardstick. Take Git, and a traditional SCM. Implement, or at least think about implementing, a clone of each from scratch; just enough so it is self-hosting. Then the one that takes less time to implement is simpler.

I wrote a self-hosting Git clone in a few hours: longer than expected because I spent an inordinate amount of time debugging silly mistakes. Though I haven’t attempted it, I would need more time to write a clone of Perforce or Subversion (pretty much the only other SCMs I have used). With Git, there’s no transactions, revision numbers, rename tracking, central servers, and so on; Git is essentially SHA-1 hashes all the way down.

But let’s humour the author and suppose Git is complex. Then why not use tarballs and patches? This was precisely how Linux was managed for 10 years, so should surely suffice for a budding developer. In fact, I say you should only bother with Git once you realize, firstly, you’re addicted to coding, and secondly, how annoying it is to manage source with tarballs and patches!

In other words, although Git is handy, you only really need it when your project grows beyond a certain point, by which time you’ve already had plenty of fun coding. Same goes for tools like defect trackers.


Apps and Oranges

I agree that developing for mobiles is painful. However, comparing this against those “simple programs of a few hundred lines of C++ long ago” is unfair. With mobile apps, the program usually runs on a system different to the one used to write the code.

It might be fairer to compare writing an mobile app with, say, programming a dot matrix printer of yesteryear, as in both cases the target is different to the system used to write the code. I once did the latter, for the venerable Epson MX-80: after struggling with a ton of hardware-specific low-level nonsense, I was rewarded with a handful of crummy pictures. I would say it involved less “real programming” than writing an Android app.

All the same, I concede that writing Android software is harder than it should be, largely due to Java. But firstly, a mobile phone involves security and privacy issues that would never arise with a dot matrix printer, which necessarily implies more bookkeeping, and secondly, the Java problem can be worked around: either via native code, or a non-Java compiler that generates Dalvik bytecode. [I’ve only mentioned Android throughout because it’s the only mobile platform I’ve developed on.]

Comparing server-side web apps with the good old days is similarly unfair unless the good old days also involved networks, in which case they were really the bad old days. PC gamers of a certain age may remember a myriad of mysterious network options to configure multiplayer mode; imagine the even more mysterious code behind it. As for cloud apps, I would rather work on a cloud app than on an old-school equivalent: BBS software, which involves renting out extra phones lines if you want high availability.

What about client-side web apps? As they can run on the same system used to develop them, it is therefore fair to compare developing them against writing equivalent code in those halcyon days of yore. Let’s look at a couple of examples.


Tic-tac-toe

I wrote a tic-tac-toe web app with an AI that plays perfectly because it searches the entire game tree; modern hardware and browsers are so fast that this is bearable (though we’re spared one ply because the human goes first). It works on desktops, laptops, tablets, phones: anything with a browser.

Here’s the minimax game tree search, based on code from John Hughes, Why Functional Programming Matters:

score (Game _ Won 'X') = -1
score (Game _ Won 'O') = 1
score _ = 0

maximize (Node leaf []) = score leaf
maximize (Node _ kids) = maximum (map minimize kids)

minimize (Node leaf []) = score leaf
minimize (Node _ kids) = minimum (map maximize kids)

Despite my scant Haskell knowledge and experience, the source consists of a single file containing less than 150 lines like the above, plus a small HTML file: hardly a “multiplicity of languages”. Writing it was enjoyable, and I did so with a text editor in a window 80 characters wide.

Let’s rewind ten to twenty years. I’d have a hard time achieving the brevity and clarity of the above code. The compiler I used didn’t exist, and depending how far back we go, neither did the language. Not that I’d consider compiling to JavaScript in the first place: depending how far back we go, it was too slow or didn’t exist.


Netwalk

In my student days, I developed a clone of a Windows puzzle game named Netwalk. I chose C, so users either ran untrusted binaries I supplied (one for each architecture), or built their own binaries from scratch. Forget about running it on phones and PDAs.

I managed my files with tarballs and patches. The source consisted of a few thousand lines, though admittedly much of it is GUI cruft: menus, buttons, textboxes, and so on. Lately, I hacked up a web version of Netwalk. The line count? About 150.

Thanks to Git, you can view the entire source right now on Google Code or GitHub, all dolled up with syntax highlighting and line numbers.

Building native binaries has a certain charm, but I have to admit that a client-side web app has less overhead for developers and users alike. I only need to build the JavaScript once, then anyone with a browser can play.

Thus in this case, my new tools are better than my old tools in every way.


Choose Wisely

The real problem perhaps is the sheer number of choices. Tools have multiplied and diversified, and some indeed impede creativity and productivity. But others are a boon for programmers: they truly just let you code.

Which tools are the best ones? The answer probably depends on the person as well as the application, but I will say for basic client-side web apps and native binaries, I heartily recommend my choices: Haskell, Haste, Git.

I’m confident the above would perform admirably for other kinds of projects. I intend to find out, but at the moment I’m having too much fun coding games.

Play Now!

Tuesday, July 29, 2014

15 Shades of Grey

John Carmack indirectly controlled significant chunks of my life. For hours at a time, I would fight in desperate gun battles in beautiful and terrifying worlds he helped create. On top of this, the technical wizardry of id Software’s games inspired me to spend yet more hours learning how they managed to run Wolfenstein 3D and Doom on PCs, in an era when clockspeeds were measured in megahertz and dedicated graphics cards were rare.

I read about cool tricks like binary space partitioning, and eventually wrote a toy 3D engine of my own. The process increased my respect for the programmers: it’s incredibly difficult to get all the finicky details right while sustaining good frame rates.

Accordingly, I paid close attention when John Carmack spoke about programming languages in his QuakeCon 2013 keynote. Many people, myself included, have strong opinions on programming languages, but few have a track record as impressive as his.


Carmack’s Sneaky Plan

I was flabbergasted by Carmack’s thoughts on the Haskell language. He starts by saying: “My big software evolution over the last, certainly three years and stretching back tendrils a little bit further than that, has been this move towards functional programming style and pure functions.”

He then states that not only is Haskell suitable for programming games, but moreover, thinks Haskell may beat typical languages by roughly “a factor of two”, which “would be monumental” and “a really powerful thing for game development”. He has even begun reimplementing Wolfenstein 3D in Haskell as part of a “sneaky plan” to convince others.

Wow! I had always thought Haskell was a pretty but impractical language. I loved composing elegant Haskell snippets to solve problems that one might encounter in interviews and programming contests, but for real stuff I resorted to C.

Among my concerns is garbage collection: I have bad memories of unexpected frequent pauses in Java programs. But Carmack notes that Haskell’s almost uncompromising emphasis on purity simplifies garbage collection to the point where it is a predictable fixed overhead.

A second concern is lazy evaluation. It’s easy to write clear and simple but inefficient Haskell: computing the average of a list of numbers comes to mind. Carmack is also “still not completely sold on the value of laziness”, but evidently it’s not a showstopper for him. I suppose it’s all good so long as there are ways of forcing strict evaluation.

A third concern (but probably not for Carmack) is that I don’t know how to write a Haskell compiler; I’m more at ease with languages when I know how their compilers work. I can ignore this discomfort, though I intend to overcome my ignorance one day. I’m hoping it’s mostly a matter of understanding Hindley-Milner type inference.

Speaking of types, Carmack is a fan of static strong typing, because in his experience, “if it’s syntactically legal, it will make it into the codebase”. He notes during his recent foray into Haskell, the one time he was horribly confused was due to untyped data from the original Wolfenstein 3D.


My Obvious Plan

Once again, I’m inspired by Carmack. I plan to take Haskell more seriously to see if it really is twice as good. Although I lack the resources to develop a complex game, I may be able to slap together a few prototypes from time to time.

First up is the 15-Puzzle by Noyes Palmer Chapman with a cosmetic change: to avoid loading fonts and rendering text, I replaced the numbers 1 to 15 with increasingly darker shades of grey.

I began with a program depending on SDL. The result was surprisingly playable, and I found the source code surprisingly short in spite of my scant knowledge of Haskell. To better show off my work, I made a few edits to produce a version of my program suitable for the Haste compiler, which compiles Haskell to JavaScript. I added mouse support and tweaked the HTML so the game is tolerable on tablets and phones.

Play now!

Sunday, September 16, 2012

Programming Dominion

I recently learned to play Dominion, a game that spawned a genre known as deck-building card games. I’m a terrible player. While suffering defeats at the hands of a simple AI, I realized I might have more fun writing a Dominion-playing program.

Implementing just the basic rules is a boring exercise. Luckily, Dominion is a self-modifying game. For example, each turn, you’re supposed to start with one Action and 5 cards in your hand, but there are ways of increasing your Action count, or changing the number of cards in your hand.

Moreover, rule modifications interact with one another, further increasing complexity. For example, playing Witch causes other players to gain a Curse card, but not if the supply of Curse cards is exhausted, or a player is holding a Moat. Or take Throne Room, which plays another Action card twice. How can we design software to handle so many special cases?

Of course, sufficient spaghetti can get anything working. But we should try to minimize mess; ideally the logic for each card should be as isolated as possible. It’d awful if, say, Throne Room required us to bury code somewhere in the Action-playing routine so it runs twice instead of once.

Dominion in Go

I’m reasonably pleased with my first attempt. For the simplest cards, the logic is completely contained in a string, in a tiny domain-specific language:

Village,3,Action,+C1,+A2
Woodcutter,3,Action,+B1,$2

Less trivial cards require a bit more:

case "Feast":
add(func(game *Game) {
p := game.NowPlaying()
game.trash = append(game.trash, p.played[len(p.played)-1])
p.played = p.played[:len(p.played)-1]
pickGain(game, 5)
})

And that’s it! To add a card, just one string, and maybe one block of code. As time passed, it became easier to add new cards. For some cards, it was more like data entry than programming.

Moat is an exception. As the only Reaction card in the Base set, rather than figure out a clean way to implement it, I sprinkle ad hoc code here and there to get it working. If I were to add more Reaction cards, I’d factor out the common parts. There’s no reason to do so pre-emptively. In fact, that’s what happened with other cards: I would only refactor once there was duplicate code to eliminate.

Intrepid readers can browse my git repo: https://github.com/blynn/gominion.git

But beware. It’s all in one untidy monolithic file, the UI is horrible, and the AI is stupid, though it still beats me when I get too greedy with Action cards! The game state is shared by all players. If network play were added, to prevent cheating, information would need to be more tightly controlled.

I have no plans to work much more on this, as many mature implementations already exist, and Rio Grande Games plans to release an official online version soon. All the same, I highly recommend learning to play Dominion, and then trying to program it. Both are enlightening experiences.

Monday, April 5, 2010

At last


I don't play much DDR anymore. Making it through Max 300 on Heavy mode was an old goal I thought I had no hope of achieving. But several days ago I had energy to burn and played a few rounds on a whim. Oddly, my game has improved despite lack of practice. The arrows felt slower than I remember. I tried Max 300 almost as a joke, and was amazed that I finally passed it.

Now I have to work my way up to an A!

Sunday, November 8, 2009

Project Euler

Lately my spare time has been eaten by an MMORPG: Project Euler. Even though I have played few RPGs, I’m sure Project Euler is one of the most difficult and challenging.

Actually, it’s really not an RPG. Rather than reward the clicking of buttons, the only way to gain levels in Project Euler is to submit answers to puzzles. Each involves a little bit of computer science and a little bit of mathematics.

Along the way, I wrote a library to make it easier to do arbitrary precision arithmetic in C. For example, to solve problem 97, I could write:

  mpz_t z;
mpz_init(z);
mpx_eval("mpz a; a = (28433 * 2^7830457 + 1) % 10^10;", z);
gmp_printf("%Zd\n", z);

Strangely, Project Euler only lets you try at most 25 problems over n days, where n is your current level (except at level 0, when it is 1). Perhaps I should be grateful, as bumping into this limit gives me time to post code!

Friday, May 16, 2008

Thai Rummy

I've already written about my fascination with playing cards and card games. At last I've filled in a conspicuous gap in my repertoire: a two-player card game I can play for hours.

I've somehow overlooked a family of two-player card games that require only a standard deck and are playable in many situations: Gin Rummy and friends. I had tried playing before but I never appreciated them until recently, when a veteran taught me an interesting variant, and repeatedly beat me easily. At first, that is!

Apparently, this variant is popular in Thailand, but I have yet to see these precise rules described elsewhere, though 500 Rum comes close.

Deal: I believe the first dealer is determined randomly. In following hands, the loser of the previous hand is dealer.

The dealer deals 13 cards to each player, and places the remainder, the stock, face-down. The top card of the stock is placed face-up in between the players to start the discard pile. The non-dealer goes first.

One aims to meld all cards in hand, either in sets: 3 or 4 cards of the same rank, or in runs: 3 or more cards of the same suit in sequence. A card can only be melded once, so it is impossible for it to count towards a set and a sequence. Aces are always high, and 2s are always low, so in particular A-2-3 is an invalid run.

Play: Each turn consists of three phases:

1. Draw: a player can take a card within the discard pile, if they can use it to form a set or run with at least one card in their hand and optionally using discards further up in the pile, and additionally if they take every card lying on top. They must display the meld, by laying it on the table in front of them.

In other words, they take some number of cards from the top of the discard pile, and use the bottommost card taken in a meld, which must then be exposed immediately.

If a player is unwilling or unable to take any cards from the discard pile, they must draw a card from the stock, unless the stock is exhausted in which case the player must pass. If both players pass, the hand ends.

2. Meld: the player may display on the table as many melds as desired from their hand, so long as they have at least one card left in hand. They may add cards to existing melds belonging to either player, but in both cases the cards are placed in front of the player extending the meld.

3. Discard: the player must discard one card. If it is their last card because all their other cards have been displayed, then it is placed face-down on the discard pile and the hand ends. Otherwise it is placed face-up on top of the discard pile and off to one side, so that every card in the discard pile can be seen at all times.

Scoring: A player receives 50 points for placing a card face-down on the discard pile, that is, when they have melded all their cards save one which becomes the discard. They are considered the winner of the hand, even if they ultimately have a lower score. If the game ends but both players still have cards, the winner is the player with the higher score.

A player adds the values of the cards displayed in front of them and subtracts the values of the cards remaining in their hand: cards of rank 2 to 9 are worth 5 points each, 10, J, Q, K are worth 10 points each, and Aces are 15 points each, with two exceptions. Both the Queen of Spades and Two of Clubs are worth 50 points.

Typically a hand ends because one player has melded their entire hand, and only one player subtracts the values of cards from their total. Both players subtract values of cards only when a hand ends because both players have passed.

There are two "stupidity" penalties. Firstly, if a player wins by melding their whole hand after taking just the top card of the discard pile, that is, the opponent's last discard, the opponent subtracts 50 points from their score.

Secondly, during the game, when a player discards a card that could have been used to extend an exposed meld, that player loses 50 points. The penalty is cumulative; each offence costs a player 50 points.

Lastly, there is a doubling rule: if a player does not display any melds except possibly in the final turn, their score for the hand is doubled. So if a player wins by melding their entire hand, and had not previously displayed any melds, their score is doubled. This is almost always beneficial because they usually have a positive score. And if a player wins by melding their entire hand and their opponent has not yet displayed a single meld, the opponent's score is doubled. This is always harmful to the opponent because they must have a negative score, seeing as no melds were made and cards remain in hand.

Winning: The final score is added to a running total. There are two victory conditions. If a player has -500 or fewer points, their opponent wins the game instantly. Otherwise the first player to have 500 points or more after going out wins the game.

More players: if there are a few more players, deal three fewer cards per extra player.

Distinguishing Characteristics

Summary for those familiar with rummy games:
  • Aces always high, 2s always low
  • Can take variable number of cards from top of discard pile; must use the bottommost card taken
  • Must make a new run or set with this card; cannot just extend existing meld
  • Must meld with at least one card in hand with this card
  • Boathouse rule: must discard when going out
  • Hand ends immediately after a player goes out
  • 50 pts for going gin
  • -50 pts for giving opponent single discard used to go out
  • -50 pts for discard card that could augment a displayed meld
  • Score doubled for never displaying melds
  • Values of cards: 2-9: 5 pts, 10-K: 10 pts, A: 15, except QS, 2C: 50 pts.
  • -500 pts loses the game
  • 500 pts insufficient for win; must also go out
Update 20090504: Ricky emailed me about his site, rummy.com, where you can find rules and background information for other rummy variants from around the world. You can also play them online.

Thursday, November 22, 2007

Music Players and Game Consoles

Long ago, over a long period of time, I wore out my old MP3 player, a Cowon iAudio X5. First its battery life shortened dramatically. Then after severe mistreatment during a long flight, the headphone jack loosened and became very fussy. Only by pushing the plug in a certain way was I able to achieve stereo sound.

Its condition worsened over time, and the final nail in the coffin was hammered in when, in desperation, I opened it up hoping I could readjust the socket somehow. I wound up breaking a wire.

I could solder it back, but what's the use of bringing it back from the dead if it has a run-down battery and a messed-up audio jack? Besides, I now had a great excuse to shop.

I considered getting another product in the same family, such as the A2, but in the end I took a different direction. Two different directions in fact: I wound up buying two MP3 players to replace my old one.

First, some lessons learned:
  • I often just pushed play, and didn't bother fiddling around with the controls. Instead I'd cram it into my pocket, and perform other tasks.
  • The built-in battery was annoying, especially when traveling. I'd have to find adapters and/or transformers, or have a computer around. Not to mention carry a strange, easy-to-lose connector and a power cord.
  • Its utility greatly decreased with its battery life.
  • For some situations it was too big and unwieldy, while for others, such as when reading text files and playing movies, it was too small and unwieldy.
To address some of these concerns, I bought one of those small cheap MP3 player that is little more than a USB SD card reader. It's powered by a single AAA battery, and sports a tiny display and a few buttons. It's perfect for those times when I'm focused on something and want some background music. Instead of playlists, I treat SD cards like CDs, and swap in different cards when I want to change genres.

It's convenient to travel with, due to its low cost and small footprint. Furthermore, AAA batteries are readily available anywhere. As a bonus, it can function as a low-capacity USB thumb drive.

However, there are times when I want to read text files or watch movies on the go, and times when I absolutely must listen to that song right now. I also missed my iAudio's ability to play different music formats, and its ability to run the open source firmware Rockbox.

So on an impulse, I recently picked up a GP2X F-200. It does music and video of various formats, but what really piqued my interest was that it plays games and runs Linux. It has two 200MHZ ARM9 processors, which amuses me because only three desktops ago, my system was a Pentium 200. And in line with my new philosophy, it has an SD card slot and is runs on 2 AA batteries.

I still miss the 20 gigabyte hard drive, FM radio and recording capabilities of my X5, but the GP2X offers more possibilities.

Hello, GP2X F-200
Mainstream gamers no doubt prefer the well-known brands for a hand-held gaming platform, as they have a wide selection of new titles and probably have better build quality. But my priorities are different: I mostly wanted a replacement music and video player, and the GP2X appeals to me thanks to its geek cred.

There is a highly active GP2X development scene. It mostly revolves around simple homebrew games, ports of classics, and emulators, but there are a few commerical games, and some of the freeware offerings are amazingly good.

One such gem is Cave Story, which I found on the bundled CD. I'd never heard of this game before, though it's been available for other platforms for quite some time. As a programmer and amateur game developer, I'm green with envy that one person alone was able to create this marvel.

Soon after my unit arrived, I looked into how the development process works. I followed the Open2x installation instructions at the GP2X wiki (except I placed them in a different directory) but for touchscreen support, afterwards I installed the newest version of the SDL library found on Paeryn's page.

I then set about writing the obligatory "Hello World" program. It's not good enough to print to standard output, because nothing shows up. Instead, I wrote a full-blown SDL program that uses the SDL_ttf library to render a string. Additionally, I had to write a shell script to return to the main menu after the program exits (and also sync the SD card).
Next I augmented the code to experiment with the touch screen, and the result is a simple drawing program. I'm disheartened by many spurious events, though I have a few ideas on how to clean them up. This must be done if I'm to get the most out of this feature.
Green circles represent when the stylus was placed on the screen, and red circles represents when it was lifted, corresponding to SDL's MOUSEBUTTONDOWN and MOUSEBUTTONUP events. As can be seen, there are times when it thinks you've lifted the stylus when you haven't, and a fair amount of jitter, usually in the horizontal axis.

Wednesday, February 14, 2007

Chase the Pig

I was surprised to find that Wikipedia currently lacks an entry for the card game 拱豬 (Gong Zhu). This four-player trick-taking Hearts-like game is often played by my relatives on my mother's side, and I assume it's relatively well-known amongst the Chinese.

John McLeod maintains a page describing various rulesets for Gong Zhu (in particular the variants involving exposing cards sound highly intriguing to me), but none of them exactly match the one I was taught. For posterity I'll record my family's rules here.

For the first deal, the player with the seven of spades leads the first trick. The lead can be any card, not necessarily the seven of spades. In subsequent deals, the player that took the Queen of Spades in the previous deal leads the first trick. This player is sometimes nicknamed "The Pig". As in Hearts, there are no trumps, and the winner of the trick leads the next trick.

Why the seven of spades and not the two? Because another card game popular amongst my aunts and uncles involved building sequences starting with seven, and the first card played in that game had to be a seven. They adopted this rule for consistency.

My family always played a predetermined number of hands (e.g. 4) and the winner was the player(s) with the highest total score, but the more standard convention seems to be that one keeps playing until someone has a total score of -1000 or lower, and then the player(s) with the highest score is the winner. (I'm guessing they did this because when playing for stakes, payoffs occur more frequently with this scheme.)

The values of the cards are as follows:

  • Jack of Diamonds, or goat (羊): +100
  • Queen of Spades, or pig (豬): -200
  • Ten of Clubs: doubles your score, unless you have won no other cards in which case it is worth +50
  • Hearts: two to ten are worth minus their pip value, except for four which is worth -10. The Jack is -20, Queen -30, King -40 and Ace -50. The other cards are worth nothing.

I was taught a couple of mnemonics for the Four of Hearts being -10. Firstly, 4 is an unlucky number amongst the Chinese (I was told this is because the word for 4 sounds similar to the verb "to die" in Mandarin, and also in other variants of Chinese), so that's why its penalty value is worse than it should be.

Secondly, the word for 4 and the word for 10 in Mandarin sound similar. If you know a Mandarin speaker, get them to say "44 is 44" to hear for yourself!

If a player wins all the hearts, then the values of the hearts are reversed in sign, that is, they are positive instead of negative, and it can be checked that they are worth 200 points in total. Furthermore, if that same player also wins the pig, the pig is now worth +200 points.

If you win every card with a value, then you receive 100 points for the goat, 200 for the sheep, 200 for all the hearts, and finally your score gets doubled by the Ten of Clubs, giving a total of 1000 points. This is is the best possible score. The worst possible score is -796, when all but the Jack of Diamonds and Two of Hearts is taken.

Naturally, the name of the game refers to the practice of leading low spades in an attempt to flush out the pig: eventually the holder of the Queen of Spades may be forced to play it and take the trick.

Comparison with Hearts

I prefer this game to Hearts. There is something special about every suit in this game, whereas in Hearts, the clubs and diamonds tricks feel like filler. Winning the Jack of Diamonds is always good, and winning the Ten of Clubs sometimes helps, so even if you're not going for all the hearts there is something to do.

I never liked the Hearts rule preventing players from "breaking into" hearts, and I'm glad that Gong Zhu is free from this restriction.

Scoring is more complicated as each heart has a different penalty value. However I found after several hands I enjoyed the less trivial mental arithmetic, even missing it when playing Hearts.

Generally, I feel the game experience is richer because there are more important cards than Hearts, yet the additional complexity is not overly random nor overwhelming. In contrast, while playing Hearts if I'm not trying to shoot the moon, my play feels almost forced, as my only goal is to avoid the Queen of Spades and as many hearts a possible. Sometimes I can choose who to penalize more by playing in a certain way, but this aspect of the game is limited and unrewarding.

Even when shooting the moon, the strategy is often clear, a drawback that I feel is exacerbated by the prohibition on breaking into penalty cards.

I'm ambivalent about the Hearts convention of passing three cards before the game starts. Sometimes it's extremely helpful since some people I've played with are rather predictable, allowing me to mold hands which I can easily shoot the moon with. On the other hand, this does reduce the challenge, and in general getting extra information about opponent's hands detracts from the game experience.

The internal conflicts are more intense and exciting. I can feel my greed fight my fear. Do I save high cards to win the goat? What if this causes me to wind up with the pig and/or a bunch of high hearts as well? Do I go for the double? It's 50 points on its own, but how sure am I that I won't pick up any hearts later on?

Other Fun Card Games

I recall being enthralled when introduced to playing cards as a child. Nothing but fifty-two bits of pasteboard, yet the possibilities are legion. Games of pure skill. Games of pure chance. Games that fell in between, and it seemed that a game existed for any given skill/luck ratio. And they can be played almost anywhere, with any number of people, even alone. Such power, and I could hold it in one hand. Merely shuffling and performing sleights at once soothed and inspired me. To this day I often carry a pack of cards on my person.

One of my well-loved books from my childhood was "The Book of Games" by Richard Sharp and John Piggott (ISBN 0883653893). I read it cover to cover countless times, though not necessarily in order, marvelling at the illustrations and fascinated by the history. I tried out many of the games within, goading whoever was around me to learn their obscure rules so I could play.

(I took offence to one sentence however: in the entry on Mah Jong it describes the Chinese as "devious". I don't think they're inherently better at games than other races!)

If only the internet and Wikipedia existed back then! I was frustrated by rules they omitted, not to mention the games they left out. Sometimes the descriptions were too concise due to space limitations. Today the rules of just about any game with some following are at one's fingertips, and one can sometimes even find free programs for an instant opponent, instructor and umpire. Unfortunately, this came after my heaviest gaming days (at least, games that don't involve computers!), so the games below are mostly from the above book.

Though I'll mention card games of many species, some bias will be noticeable since I'm fond of lightweight teamless trick-taking games. Player ability varies wildly in some circles, making partner selection problematic in games such as bridge and canasta.

If there are four players, I almost always enjoy playing Hearts and Chase the Pig. Big Two is another favourite.

When there are three players, Knaves is a good choice if I'm in the mood for something like Hearts. It is also a no-trump trick-taking game with penalty cards, but also gives one an incentive to win as many tricks as possible. Sergeant Major is an entertaining diversion for three, especially for those newer to trick-taking games. My friends and family found David Parlett's Ninety-nine refreshingly unique and challenging. (We played the original rules, as described in The Book of Games.)

I never found two-player card games appealing, though I feel like I could if I dedicated more time to them. In particular, I feel like I should like Cribbage, Bezique and Piquet. I've tried some novel two-player games described in "The Pan Book of Card Games" by Hubert Philips, but never grew attached to them.

For five players or above, I'd play poker, or in a less serious crowd, Bartog.

Also, Napoleon is a five-player trick-taking game whose gimmick is the existence of a secret partnership: the identity of highest bidder, Napoleon, is known, but his secretary is determined by the holder of a particular card that is not revealed until played during a trick. Thus it is a two-versus-three game where initially no one knows the composition of the teams.

I had forgotten the details of this game. But thanks to Google, I rediscovered this old friend, and learned a lot more. Apparently, my parents left out at least half the rules when they taught it to me. Also, it seems Napoleon is a popular Japanese card game.

As for patience/solitaire for one, I'd recommend downloading a program like PySol and exploring.

Monday, March 27, 2006

Mathematical Go

I was taught to play go as a child, but it wasn't until a few years ago that I learned how complex the rules are, at least the ones used in tournaments. I had previously thought the rules were elegant and simple.

Actually, mathematicians have devised elegant and simple rules of go. [Broken? archived version] Unfortunately the mathematical rules are rarely used. Instead, there are several popular rule sets with different properties.

Luckily in most games the complicated cases never arise, but it is irritating to know that in general, the outcome of the game can depend on the legality of suicide, and in many cases it is unclear whether a group is live or dead if the mathematical rules are not followed. [Link broken; the FAQ can be found in the nextgo package.]

Evidently when the game was first invented, nobody thought about the messy corner cases. It seems as each one was discovered, an ad hoc solution was proposed, and over time these cumulative patches to the basic rules eroded the austere grace of the game.

As one might expect, starting afresh and approaching the game from a mathematician's point of view not only restores clarity and precision, but also yields unexpected results. For example, Berlekamp and Wolfe describe bizarre positions where highly nonintuitive moves are required to win. Even though such situations never occur in real play, studying them hints at the richness and depth of this ancient game. Unsurprisingly, it was a mathematician who first drew my attention to the flaws in traditional go rule sets!

I am not sure why the mathematical rules have not caught on. Are they too difficult to implement in a tournament? Is the grip of tradition is too strong? Or is it simply that most in the go world are unfamiliar with these recent developments?