Welcome to my blog. Here you'll find mutterings and musings on whatever happens to tickle my fancy, but mostly relating to board games and card games.
Among other things, I run an on-line game store (http://housefullofgames.com) and I subscribe to various news feeds in order to keep abreast of my favorite topic.
If I see something that urges me to comment (or just share) then it'll probably find its way here.

Tuesday, January 26, 2010

Bringing Mü to the iPhone

About a year and a half ago I had a Zune. I'd been given one as a gift and my beloved iPod classic was broken. Microsoft had just released a free SDK that let people write code for it. Being the geek I am, I thought it would be a fun project to write a version of Mü that would run on my Zune. My friends all thought I was crazy. Surely it wasn't possible to make a good version of Mü on such a tiny, wimpy device! Nevertheless, I ignorantly forged ahead and a few months later I had a version of Mü that not only worked on the Zune, it worked surprisingly well! What I didn't have was a license to distribute the game. The Zune games market being what it is (non-existent) I didn't see much of a point.

Fast forward a few months. My wife and I had just bought iPhones and suddenly I was looking at some interesting possibilities. Unlike Zune, the iPhone has a very vibrant games market. While I was pretty sure I wouldn't make any serious money doing it (let's face it, the game is a little too complicated to appeal to your average iPhone gamer) I recognized that there just might be a market for an iPhone version of Mü; and besides, I wanted one for myself!

In this article I'll discuss some of the challenges I had to overcome and some of the things that I learned along the way. I hope you find it interesting.

Becoming Legal

The first hurdle that I had to overcome was the fact that Mü is a copyrighted game. I didn't really fancy the idea of stealing Frank Nestel's game and Doris Matthäus' artwork so before I even started writing code I sent email to Dr. Nestel, explained what I wanted to do, and asked if he would be interested in licensing his game. Happily he replied in the affirmative.

I probably don't need to tell you that the internet is a pretty wonderful thing. Thanks to the magic of the internet, finding Frank's contact information was extremely easy and we were able to handle pretty much everything via email. Still, conducting international business is never without its challenges. He's in Germany. I'm in Seattle. Luckily his English is way better than my German. Negotiations went fairly quickly since we were both pretty enthusiastic from the start but it still took quite some time to actually get a contract signed. In the mean time, I had begun development in earnest.

Preparing for Development

When this project started, I hadn't used a personal computer made by Apple since the 1980s. Since iPhone development requires a Mac, I had some shopping to do. I decided that the cheapest and quickest way to get things going would be to buy a used Mac Mini. My wife thought I was nuts when I spent most of a Saturday driving to some stranger's house to buy one that he'd advertised on Craig's List. It turned out to be a pretty good way to go though. I love the portability of the machine and while it's not the fastest Mac out there, it's more than powerful enough for iPhone development.

The other hurdle I had to overcome was that I had to learn the development environment. Luckily that didn't prove to be too difficult. Apple's on-line documentation and videos are surprisingly good. If anything, there was too much information. Objective C isn't my favorite language but it's not too bad. I've never been much of a language bigot. Unfortunately, since Zune development is typically done in C#, virtually none of the code that I'd done for the Zune version could be used unaltered. I had to essentially re-write the entire game from scratch. Still, that was probably a good thing. It forced me to reevaluate most of the decisions that I'd made on the first version and the result was a much stronger game.

I spent several weeks just pouring over Apple's documentation, trying to learn the environment and absorbing as many of Apple's recommended best practices as I could. I installed the SDK, I played around with sample code. I familiarized myself with the environment. I watched scores of video presentations. Looking back, I'm glad I did. All of that initial groundwork would eventually pay off when I submitted Mü to Apple and they approved it in just two days.

Screen Size

One major hurdle that any developer has bringing anything to a portable platform such as the iPhone is the small screen. The iPhone's 320x480 screen is pretty big for a hand-held device (that's twice as many pixels as there were on my Zune) but it's still pretty cramped. Furthermore, those pixels are crammed onto a screen that's only 3 inches high so coming up with cards that are readable becomes a huge challenge.

The cards underwent several design changes. I started with raw scans of the original cards shrunk down to 40x65 pixels. While that had worked OK on the Zune, that turned out to be way too small for the iPhone so I started over, this time with cards that were shrunk down to 44x70. That was still too small but I couldn't really go much bigger and still leave room for bidding areas for each player so I decided that I had to make some subtle changes to the card design.

The first thing I did was get rid of most of the white border around each card. I kept all of Doris' lovely artwork but made all of the elements on each card just a little bit larger. The numbers were pushed a little bit closer to the color bands and the color bands were enlarged so that they more completely filled each card. That left me with virtual cards that looked almost undistinguishable from the original cards but if you look closely, you might notice that the numbers are actually a bit larger.

The next thing that I did was dramatically over-saturate all of the colors on the cards. I found that the original suit colors were far too difficult to distinguish when reduced to those sizes. Over saturating and slightly altering all of the colors made it much easier to tell blue from green from black.

I finally had cards that were readable and still looked like Doris' originals but that still wasn't good enough. The ornate numbers on the cards made them a little difficult to read and one of my testers was really pushing for a solution that was more friendly to the color-blind. I was really reluctant to abandon any elements of Doris' card design but I finally realized that it had to be done. Not wanting to completely abandon the traditional design, I left the traditional cards in the game as an optional setting but the default card set was changed to use the cleanest font I could find and different symbols were used as the pips of each suit.

original colors

traditional cards

final design

Screen Layout

The next difficult decision I had to make was how to arrange all of the game elements. I had originally thought that I would lay out the screen in landscape mode as I had done on the Zune but the more I experimented with my mock-ups the more I began to drift away from that decision. I realized that if I used the standard iPhone OS elements of a navigation bar at the top and a status bar at the bottom, I'd be left with a nearly perfect square in the center of the screen. That would give me a natural place to put menu icons and status text and allow me to follow iPhone conventions as much as possible. Following iPhone conventions would mean that users would feel more at home with the user interface and it would also make it possible for me to use many of the built-in features of the iPhone operating system.

Zune screen layout

I also realized that when I hold my iPhone, it just feels more natural in the portrait orientation. Landscape is fine for two-handed action games like shooters and the like but for a card game, where one hand cradles the device and the other hand is used to interact with the game, portrait mode just feels more natural to me. That's a personal preference of course but hey, it's my game so I get to do what I like.

iPhone screen layout

Early in the development process I realized one other unanticipated benefit of sticking with portrait mode. I could use the iPhone's built-in accelerator functionality to attach subordinate UI screens to the two landscape orientations. I decided to use the left landscape orientation to display the summary cards and the right landscape orientation to display a score sheet.

The game screen can still get quite crowded because I had to make it possible to represent the scenario where the maximum of six players have bid nearly all of their cards, and I needed room for essential scoring information, player names, link status and bidding feedback. Despite being a little crowded, I think it works pretty well.

One request that I've had from time to time is to display points taken during the current hand while the hand is in progress. Early on I decided not to do that for a number of reasons: first, it would be yet another set of numbers on an already crowded screen; second, it's information that you normally would be required to keep in your head during a real game; but third, and more importantly, if you stop to think about it, it's not really very useful information. Think about it. Are you really likely to change the way you play on a trick based on that knowledge? Almost certainly not. You're going to try to give as many points to your team as you can while keeping as many points away from your opponents. It doesn't really matter if the bid is already made or not. The only scenario where it might matter is if you've already got the result you wanted and you're deciding whether to give a point card to a partner or trying to keep it for yourself, and that scenario really isn't all that important in the grand scheme of things. If you're the type of player for whom that one or two points really matters, then you can track the points in your head, just as you would have to do in a live game.

UPDATE: After some great customer feedback I changed my mind on this last point. In the current version of the game, you CAN see how many points have been taken so far throughout the hand. Just rotate the device to the right and check the scorecard. Putting that info on the scorecard is a great compromise because it avoids cluttering the main screen (my main objection to it in the first place) and it also keeps it out of sight for players who don't want that level of help from the computer.

Input Method

Another difficult, and perhaps somewhat controversial decision that I had to make was to decide how the user would select, bid, and play cards. I looked at several different methods before finally making a choice.

The most obvious method for playing a card would be simply to allow the player to touch the card he wants to play. On its surface this seems like a good idea but I quickly rejected it. Fat fingers touching tiny cards on a tiny screen are not very precise. The cards are small enough that it is all too easy to accidentally touch the wrong card. There are few things more frustrating than playing a card by mistake. That clearly wasn't going to work.

Tapping a card and dragging or flicking it to the middle of the screen worked a little better but I still found it too easy to accidentally select the wrong card. What I wanted was an input method that was very clear and as error free as I could make it.

Eventually I settled on an input method where the selected card is always shown in front of the rest of the hand, making it very obvious which one is selected. If you've got the wrong card you can tap on a different one or slide your finger to one side or the other until you find the card you want. An arrow icon appears above the selected card, further reinforcing the selection. Only after tapping on that icon is the card actually played to the table. This extra step has seemed a little awkward to some but of all the input methods that I experimented with, this one was by far the most error resistant.

UPDATE: I've slightly changed my opinion on this as well. While working on the new iPad version, I realized that my concerns with tapping and dragging cards didn't really apply to the larger device. With larger cards, it becomes much more natural to tap and drag cards so I decided to go ahead and add multi-touch tap and drag to the possible ways to select and play cards. The older input method still works exactly as before but now you can also slide your finger vertically over a card to pick it up, at which point you can move it over the play area and let it go to play it. You can also double-tap on a card to play it. I also decided to go ahead and add it to the iPhone version since some had asked for it. Still a bit worried about accidental card play, I put an option in the settings to allow users to turn the feature off should they find that they're playing cards by mistake.

Bidding uses exactly the same method except that instead of playing your card to the trick, it pushes your card forward in a "marked for bidding" state. The icon above the card changes to a down arrow. Touch the down arrow and the card will be pulled back into your hand. A second icon, pointing to your opponent, is used to lock in your bid and yield control to the next player. This results in an input method that is consistent across the entire game and very resistant to accidental taps, touches or swipes. It may take a little bit of getting used to at first but I remain convinced that it's the best solution.

From the start, I disallowed selecting illegal cards but one of my testers suggested a wonderful finishing touch: that I grey out or dim illegal cards, making it easy to tell at a glance which cards are legal to play and which ones are not.

Artificial Intelligence

Of all the obstacles that I had to overcome on this project, the AI was certainly the most challenging. Mü is a very complicated game with a rich bidding mechanic. When I was doing the initial Zune version I did a lot of research on the topic and I have to say that what I learned was not very encouraging. After decades of research and development, computers are only just now able to play a decent game of Bridge, and that's on a very powerful computer! Card play isn't too terribly difficult but even that's not easy (witness all of the really crappy Hearts games out there) but bidding! that's another matter entirely. Getting bidding right is a notoriously hard problem.

Step one to creating a good game of Mü is just to get the computer to play a hand correctly. I didn't even think about bidding at the start. Card play is complicated by the fact that trump changes dramatically from hand to hand, as do partnerships, and the cards are not all worth the same amount of points. That meant that a lot of the conventional optimization tricks that are used to speed card play in a Bridge game just don't apply. I had to come up with my own optimization techniques, based on some of what I'd seen in Bridge implementations to be sure, but my own nonetheless.

The card play logic in Mü (like most card games) is handled using something called a Monte Carlo routine. In a Monte Carlo routine you start with all of the cards that you know (because they've already been played or because they've been bid or because they're in your own hand) and you randomly assign all of the others. Then you play a number of tricks and you evaluate the outcome. Repeat that process a number of times and whichever card gives the best results, that is the card you play. It's a brute-force implementation that, given enough random samples, and given that you play enough tricks ahead, will result in optimal play. The problem is that on the iPhone we don't have nearly enough computing power to evaluate enough tricks or samples to arrive at optimal play so on top of this foundation I poured a little bit of secret sauce that allows the computer to make slightly better than average choices despite the very limited thinking time. The computer DOES NOT CHEAT but it does get a little bit of help from my experience as a player. There isn't enough time to really analyze the hand properly so it will occasionally make a blunder or two but most of the time it gets it right and in my opinion, that only serves to make the game a little more interesting and lifelike.

Bidding is a much harder problem. At its core, it still works much the same way: you take a whole bunch of random samples, you analyze them, and you make the choice that seems to yield the best results. Unfortunately, if computing power was scarce during card play, it's REALLY scarce during bidding so I had to take a lot of short cuts. Still, I did manage to leave most of the bidding decisions up to the computer. It analyzes the current bids to determine who it thinks is likely to be chief, who is likely to be partner, who is likely to be vice, and what is likely to be trump. At each stage in the bidding it needs to decide if it should take chief, take vice, put itself on the hook, position itself to be partner, or just pass. Every major decision is made by playing a number of randomized hands to completion and deciding what it thinks the score in a given situation is likely to be. It doesn't take chief or vice unless it thinks there is a material advantage to doing so within a given margin for error. Deciding what that margin for error should be can be tricky. I probably played thousands of hands where the computer played against me or against itself. I analyzed so many hands that I got well and truly sick of looking at them but the results were worth it. It still doesn't play perfectly but given the limitations of the hardware, I'm very satisfied. The fact that I can regularly lose to my own game is quite satisfying.

Linked Play

The final challenge, and certainly a formidable one, was getting linked play to work. I really wanted to be able to play a game with several human players, all linked over the network. Getting there turned out to be a lot of work.

I immediately discarded the idea of linking arbitrary iPhones over the internet. That would require some sort of match-making service or dedicated server to enable players to find one another and that was way beyond the scope of what I was interested in doing. Instead, I focused on linking over Bluetooth. That had some immediate advantages: first, it meant that I didn't also have to implement some sort of chat facility because using Bluetooth implies that all players are within shouting distance of one another; second, the iPhone v3.0 SDK has built in matchmaking facilities for linking players over Bluetooth. The only real drawback there was that I wanted to be able to link more than two players at a time and nowhere could I find any examples of code that did that. I couldn't even find any games in the App Store that did that. (I'm sure they must exist but I couldn't find any in my admittedly short search.)

Once I'd figured out how to link multiple players, I still had other challenges. Even though I had designed the game from the start with the knowledge that I would be adding networked play, and even though I had experience working on other networked games, I still found it more difficult than I had anticipated. When you have two computers linked together, all playing the same game, you need to be very careful that they both stay in sync. Furthermore, because they ARE separate computers, there is a built-in expectation that they should both be able to be doing different things at the same time. For instance, one player could be reviewing the score sheet while another player is bidding. Keeping all of those states synchronized and dealing with the fact that you could be getting messages (or not getting messages) from another player at any time is really challenging. Despite all of my careful planning, I still went through several builds where I was unable to play more than a hand or two without encountering really strange behavior. Players would play cards that had already been played. I'd end up with multiple partners, or sometimes no partner at all. Cards would mysteriously move about the screen. Good times.

That was complicated further by the fact that none of my beta testers seemed to be much help where multi-player games were concerned. Most of my beta testers lived in different cities (or even countries) and therefore they couldn't really test linked play. Luckily my wife and I both have iPhones and my son has an iPod Touch so I was able to test linked play myself. My son and I played a lot of games but I still wish we'd had a lot more time to test. I'm keeping my fingers crossed that someone won't run into some really hideous bug when playing with six humans all linked over Bluetooth.

There were some other really interesting limitations imposed by the iPhone form factor. The iPhone does not support running more than one application at once and your application can be shut down at any time for any number of reasons. That meant that the game had to be designed from the start to be able to save and resume automatically and with a minimum amount of user interaction.

Furthermore, what do you do if someone gets a phone call or a text message in the middle of your linked game and he has to exit the game to answer it? How do you get that player back into the game? And what if someone has to go home? Do you force everyone to quit the game just because little Bobby's out past his curfew? Clearly I needed to allow players to jump back into the middle of a game in progress and I needed to allow the computer to fill in should someone leave. Making that happen in a way that was as simple as possible for the user was a bit of a challenge.

Localization

Both Frank and I really wanted Mü to be available in more languages than just English. One of the first things that Frank requested was that we do a German version. I was completely on board with that idea, especially knowing that the German board game market is so active, so from the start, I structured the game to allow localization. That turns out to be really easy on the iPhone. The iPhone has built-in facilities for separating localizable resources and bundling multiple languages into the same application package. I also had past experience with localization so I was aware of virtually all of the issues I would come up against. From the start I made sure that any localizable strings used the NSLocalizedString macros. I used icons instead of text whenever it made sense to do so. I was also very careful to avoid writing code that would build sentences from component phrases. That resulted in some redundant strings here and there but it gave me the luxury of rewording longer sentences if they became too long to fit on screen after localization and it meant that localizers were always free to use the proper grammar.

I speak Portuguese so I did a very rough Portuguese translation early on which I used to work out any kinks in the process. Unfortunately, my Portuguese isn't good enough that I could release THAT version of the game. It's currently being proof-read by a native speaker to fix all of my many embarrassing mistakes.

All of the in-game documentation (and there is quite a bit of it) is displayed using the iPhone's wonderful built-in web controls so I was able to put it all in html files which made localizing the rules and credits a breeze.

Conclusion

This was a phenomenally satisfying project. I feel that I've produced a fantastic game and I've learned a lot along the way. I can now play my favorite card game during my commute! Will it prove to be financially profitable? That remains to be seen but either way it was well worth the undertaking. Bringing a game I love to the iPhone has been a reward unto itself.

8 Comments:

This was a fantastically interesting post. Thanks for posting it -- and thanks for the game! I ran to the App Store as soon as I saw it was available. I've never been able to play Mu enough to get good at it, but I find it a lot of fun, and this gives me the chance to play more.

Very cool, thanks for sharing all of that. I don't suppose you want to share how you managed the multiple bluetooth connections, do you? I'm working on an iPhone/iPad game that will need it and haven't tackled it yet.

(I've also been thinking of doing a Tichu implementation after this project but haven't done too much yet... if you are planning to do so, let me know and I'll abandon it.)