Sunday, February 17, 2013

From game developer to game reviewer

For one month, I was a game developer. The month after that, I became a game reviewer. This month, I'd like to tell you how that went.


Developer, reviewer, storyteller; those three roles are more similar than they seem. In all three cases, I have an audience. That's the part you fill in right now. Also, each role is partly about deciding what to share: choosing the most interesting game features, the most entertaining games, or the best anecdotes. Here's an example.

When me and my teammates were designing our game, we envisioned teleporting blocks, entanglement badges, decaying walls, a lot of good game mechanics which we had to discard because we had a lot more ideas than we had time for implementing them. Our tight deadline was due to the fact that we were competing in the GitHub Game Off, a programming competition inviting teams and individuals to create a web-based game in one month.

Finishing a game in one month is harder than it sounds. In fact, the overwhelming majority of the contestants failed to deliver a playable game at the end of the month. All of these flops became problematic during my second role, as a game reviewer: if I had not been smart about this, I could easily have spent more time discarding failed projects than playing and reviewing actual games.

Dealing with an overwhelming number of possibilities is a common problem, which I'm sure you also have to face sometimes. Here's how to fight back.

Ask other people for advice


When we were working on our game, we knew that our goal was to make a game which players would appreciate. We therefore decided that our first priority was to create a small, but playable version of the game, so that we could show it to our friends and ask them what to improve.

I thought I would have had to compile many suggestions and identify the most frequent requests, but to my surprise, almost everybody reacted to the game in almost the same way! Sadly, this common reaction was incomprehension, because our game mechanic was very complicated and not very well explained.

It turns out I was so familiar with the game that I was blind to its complexity. Play-testing early was a great plan, as it allowed us to discover the problem early on and to improve the clarity of our game throughout its development.

Did we succeed? See for yourself by playing it here!

Look around for inspiration


After our game was complete, I compared it with the competition. As I played one game after another, looking for my strongest competitor, patterns started to emerge.

There was a recurrent hero: Octocat, the mascot of GitHub. The contest page featured a few Octocats dressed as various game characters, so it was an obvious choice.

Our game was also using an Octocat until the last day of the competition, when we learned that this was against the rules! We changed the artwork, renamed the game, and then the server refused our changes because we ran out of disk space, something which shouldn't even happen on GitHub. It was a very dramatic climax at the end of the race.

Practice


Another common occurrence was games which were clearly aiming to emulate existing well-known games, like Osmosis and World of Goo. Imitating a game concept which has already proved to be a lot of fun sounds like a winning strategy, but it isn't, because games are about mastering new skills. In this case, however, I suspect it was not the players who were supposed to learn new skills.

When I first learned to code, I wrote a Pac-Man clone. Then I wrote a second one, to see if I could get the ghosts to animate smoothly instead of jumping from cell to cell. Then I wrote a Mario clone, and so on and so forth.

We game developers learn how to make games by copying the work of the masters, much like musicians begin by learning how to play famous songs before they become ready to compose their own.


There were also many documents in which contestants described their dream game in detail, without actually reaching the point where they would start implementing it for real. Again, I've been there. When I was a kid, I would draw detailed, life-size Mario-style levels... and then I would lay down the pages on the floor and jump on them. Always play-test your game as early as possible, kids!

I think the trend here is that learning to develop games is a long process, and those artifacts represent the different stages you have to go through before you become ready to create your own original games. So sure, as a game reviewer I have to say that the clones didn't introduce enough novelty and that a design document is in no way a substitute for a game. But as a fellow game developer who has been through those stepping stones, I say keep up the good work! Don't give up, you're on the right track.

Use tools


After comparing my game with all those clones and design documents, I was sure that we were going to win... but I was wrong. I had not compared our game against strong enough competitors.

To find my strongest competitor, I was willing to play through many clones and incomplete prototypes, but I quickly grew tired of the non-playable entries.

To help me on my quest, I used the GitHub API to obtain high-level information about all the contestants. I tried to filter the entries by code size and by the date on which the contestants had stopped working on their game, but neither metric clearly separated the games from the flops. Instead, I simply eliminated the entries which did not provide a URL at which their game could be played, and that turned out to be enough.

After encountering many comments on the internet from potential players who couldn't find the games among all the flops, I realized the value of my reduced list, and I decided to publish it.

Be persistent


Even with the list reduced to a tenth of its original size, there was still a large number of games to go through.

I kept looking at more competitors because every ten games or so, I would encounter a game which was genuinely fun and original, and this would motivate me to keep looking for more gems.

The fact that good games were so rare made me realize that publishing a list of all the games, even after filtering out all the flops, was not going to be very helpful. I had to sort the list! It is at this point that I took on the role of an amateur game reviewer.

Drop information


Comparing the games turned out to be more challenging than I had imagined. Among the top contenders, there was no game which was better than the others in every single respect; rather, I would find one game with impressive graphics, another game with stimulating music, and another one with an original new mechanic. It was like comparing apples and oranges.

Professional game reviewers often solve this issue by rating each game aspect in isolation. They then combine the individual ratings into one unified score, using a fixed weight for each aspect. That's a good idea, but with more than 150 games to review, I needed a more expedient scoring method!

I ended up separating the games into categories, then sorting the categories. For example, all the games with good ideas but poor execution ended up in one basket, and then I only had to decide whether I favoured games with great execution or games with great ideas. When I published the list, I concatenated all the lists and removed the category names, so that I wouldn't hurt anyone by telling them that their game was in the "poor execution" category.

Conclusion


Only sorting the baskets meant that games belonging to the same category would appear in an arbitrary order, falsely conveying my preference for one over the other. I decided that this did not matter. After all, my goal was not to share my preferences, but to help gamers find the most worthwhile games. No order I could have came up with would have precisely matched the preferences of all my visitors anyway.

In fact, once the results of the contest came out, I discovered that my preferences were even less representative than I thought. Some of the games which the judges decided to highlight had appeared very low on my list, and conversely, some of the games at the top of my list were not mentioned at all.

Do you agree with the choices made by the judges, or is it my list which most closely matches your taste? Check out the official GitHub Game Off results here, and my much longer list of all the games here.

Friday, December 14, 2012

Every single game from GitHub Game Off 2012

From the 1285 forks of GitHub's official game-off repository, only 182 contestants bothered to change the URL at the top of their repo page. Of these, only about 140 URLs actually point to a game you can play. Not many of those games are worth playing.

I know this because I have used GitHub's API to obtain basic information about all the forks. And because I have visited all 170 non-blank URLs, and played every single game. And now, so can you!

Well, I don't really recommend trying all 170, but for your convenience, I tried to list the most worthwhile games at the top. Obviously, my opinion as to which games are the best might not match yours, but as you go down the list, if you encounter a point where every single game feels sub-par, you should be able to stop and be confident that you are not missing a rare gem hidden much further down. That being said, if you want to maximize your enjoyment, better start by the end, and play the most polished games last!

Enjoy.


(full disclosure: my own game entry is somewhere in that list.)


  1. linkboy992000/game-off-2012
    challenging, polished puzzle game about cloning. story and music! Do *not* press 'A'.
  2. svenanders/jetmanjr
    hard exploration platformer.
  3. searlm/game-off-2012
    virus-themed shoot-em-up where you need to balance progress against collecting ammo.
  4. redmanofgp/game-off-2012
    hard, but fun shoot-em-up game where you can concentrate your mind power.
  5. gamefrogs/game-off-2012
    a puzzle version of pipe dream, on an hexagonal grid.
  6. flypup/game-off-2012
    short fighting game in which your opponent spawns copies of himself.
  7. ondras/star-wars
    hard, fun, ascii fighting game.
  8. jpfau/scrum
    a mix between a kind of tetris and a 3D shoot-em-up. on a GBA emulator.
  9. mindd-it/game-off-2012
    bird-themed single-button avoid-the-obstacles game
  10. wtjones/game-off-2012
    unique clone-climbing game.
  11. fragcastle/rock-kickass
    megaman-style game in which you steal the abilities of normal enemies
  12. sdrdis/hotfix
    single-button platformer with very nice increasingly difficult yet randomly-generated levels. upgrades are way too expensive.
  13. lulea/game-off-2012
    3D sokoban
  14. adhicl/game-off-2012
    puzzle game with a unique clone-and-lure mechanic
  15. KriScg/Waveform
    circuit-simulator puzzle game.
  16. 502Studios/game-off-2012
    mine-themed sokoban-style puzzle game.
  17. RonanL/game-off-2012
    a nice platformer about escaping from your clones.
  18. mvasilkov/game-off-2012
    typing game with gratuitious physics, space invaders, music, anime, oh my!
  19. Eugeny/foku
    an exceedingly pretty, but hard to control game about a magic fork.
  20. tapio/plasma-forks
    a first-person shooter.
  21. visualjazz-ngordon/Play-dot-to-dot
    short connect-the-dot game.
  22. tsubasa-software/game-off-2012
    pirate themed obstacle-avoiding game.
  23. duncanbeevers/game-off-2012
    over the top maze game.
  24. gelisam/game-off-2012
    hard sokoban variant with a confusing rewinding mechanic.
  25. loktar00/game-off-2012
    bejeweled-style game with a resource management side.
  26. AD1337/ForKingGame
    hard physics-based platformer.
  27. Seldaek/split
    obstacle-avoiding game with a unique splitting mechanic.
  28. dakodun/game-off-2012
    strategy game with a unique unit-pushing mechanism.
  29. volrath/game-off-2012
    a shoot-em-up game with powerups.
  30. cdata/solstice-submarine-ctf
    capture-the-flag game with an underwater theme
  31. ViliusLuneckas/Pipe-slime-adventure
    pipe-themed avoid-the-obstacles game.
  32. gbatha/PolyBranch
    3D avoid-the-obstacles game in a tunnel.
  33. kicktheken/game-off-2012
    an isometric exploration game in which you accumulate resources of different types.
  34. zombiebros/game-off-2012
    rambo-themed shoot-em-up
  35. Jidioh/SkyScaler
    short labyrinth with a world-flipping mechanic.
  36. lazor-base/fused-holiday
    a platformer in which you can push and pull crates.
  37. AntPortal/game-off-2012
    isometric quiz questions about git.
  38. Dover8/game-off-2012
    a puzzle where actions in one world affect the other copy.
  39. icebob/game-off-2012
    3D pong.
  40. Zolmeister/avabranch
    hard to control fork-and-avoid-the-obstacles game.
  41. eric-wieser/game-off-2012
    a variant of snake in which you can divide and control multiple snakes simultaneously.
  42. incorrectangle/game-off-2012
    astronaut-splitting, blob-merging puzzles. too short. a bit buggy.
  43. cnnzp/game-off-2012
    short track-building puzzle game.
  44. nojacko/game-off-2012
    strategy game in which you need to defend your buildings from the zombies.
  45. thehen/game-off-2012
    exploration game based on a World-of-Goo-style building mechanic. quite short.
  46. rozifus/game-off-2012
    hard sokoban variant with a color merging mechanic
  47. lantto/game-off-2012
    unique clone-spotting and killing game.
  48. jlongster/octoshot
    3d shooter on a small map
  49. RothschildGames/release-cycles
    circular avoid-the-obstacles game
  50. appleskin/game-off-2012
    block-carrying puzzle game.
  51. etamm/game-off-2012
    top-down zombie shooter with interesting alter-your-world mechanic.
  52. begillespie/cloned-game
    move in both copies of the world. Again.
  53. fengb/game-off-2012
    a unique drawing puzzle game, once you finally figure out what you're supposed to do.
    hint: click on the black strokes.
  54. sjthompson/game-off-2012
    a strategy game in which units are spawned off other units, not buildings.
  55. xSmallDeadGuyx/game-off-2012
    a nice little light-bot-style game.
  56. Gagege/game-off-2012
    unique, fast-paced memory game.
  57. notsimon207/game-off-2012
    physics-based platformer, clearly inspired by Gish. too hard to control.
  58. danfischer87/game-off-2012
    hard git-themed puzzle game. a bit buggy. too short!
  59. jeffreypablo/game-off-2012
    fighting game. terrible graphics, buggy, but the gameplay is there!
  60. scriptfoo/game-off-2012
    a game about learning Javascript. Incomplete? I got stuck after the toLowerCase() quest.
  61. petarov/game-off-2012
    distract your opponents while you pick up carrots. strangely-placed controls.
  62. Dave-and-Mike/game-off-2012
    short alien-cloning game. strangely-placed controls.
  63. murz/game-off-2012
    top-down shooter with multiple gun types.
  64. jsonsquared/game-off-2012
    multiplayer top-down shooter.
  65. DangerMcD/game-off-2012
    unique multitasking, block pushing game.
  66. Choctopus/game-off-2012
    guitar-hero-style game.
  67. gilesa/game-off-2012
    unique obstacle-avoiding game about writing software.
  68. vladikoff/game-off-2012
    complicated shooter.
  69. Chleba/game-off-2012
    short starwars-themed fighting game
  70. JasonMillward/game-off-2012
    hard obstacle-avoiding game.
  71. denniskaselow/game-off-2012
    asteroids-style game.
  72. mapmeld/game-off-2012
    missile command clone with an interesting "change the rules" mechanic.
  73. onethousandfaces/game-off-2012
    bonsai-growing pseudo-game. would be an interesting mechanic if there was a goal shape.
  74. vrgen/game-off-2012
    car-themed avoid-the-obstacles game
  75. gitdefence/game-off-2012
    complicated allele-sharing tower-defence game
  76. ChickenChurch/game-off-2012
    punch-the-obstacles game with annoying controls
  77. AreaOfEffect/game-off-2012
    food-themed shoot-em-up
  78. asswb/game-off-2012
    a bug-tracker simulator, where you solve issues by being patient.
  79. eleventigers/echo
    hard 3D platformer about capturing sounds. too hard for me.
  80. forrestberries/game-off-2012
    a online multiplayer version of the board game "Apples to apples".
  81. NetEase/game-off-2012
    diablo-style game. not worth the very long loading time.
  82. DancingBanana/game-off-2012
    platform game with a chronotron-like cloning mechanic. SaveTheClones, below, is the same idea but with more levels and... different graphics.
  83. lrem/kobo-san
    sokoban variant in which some blocks can be pulled.
  84. SUGameOffTeam/game-off-2012
    hard tank-wars clone with a kitchen theme. only one level.
  85. jisaacks/game-off-2012
    food-themed asteroids-style game.
  86. pce/game-off-2012
    short dream-themed obstacle-avoiding game.
  87. scurryingratatosk/game-off-2012
    two player Qix variant.
  88. bverc/miner-trouble
    sokoban variant with gems and bombs.
  89. Psywerx/game-off-2012
    obstacle-avoiding hipster-themed game.
  90. AmaanC/TinyWings
    tiny wings clone.
  91. Andersos/Meatballs
    meatball-themed obstacle-avoiding game.
  92. yosun/game-off-2012
    propel clones at your enemies. instructions would have been useful.
  93. Popcorn-Web-Development/Beaver-Words
    beaver-themed typing game.
  94. lessandro/dave
    short plaftormer with diamonds and a jetpack.
  95. dakk/game-off-2012
    nyan-cat themed obstacle-avoiding game.
  96. binary-sequence/game-off-2012
    firefighting game.
  97. condran/game-off-2012
    shoot-em-up with very limited ammo.
  98. Jacic/game-off-2012
    platform game with a chronotron-like cloning mechanic
  99. sourrust/game-off-2012
    double-jump platform game. only one level.
  100. MonsterGuden/game-off-2012
    single-button puzzle platformer
  101. JamieLewisUK/game-off-2012
    shoot the balloons for points.
  102. JuggleTree/game-off-2012
    catch fruits and throw them into a basket.
  103. mkelleyjr/game-off-2012
    snake clone.
  104. dafrancis/SpaceHam
    non-sequitur-themed shoot-em-up.
  105. playtin/game-off-2012
    wario-ware-style mini-games.
  106. gplabs/game-off-2012
    a tetris variant with more annoying controls. use space to attach/unattach to a piece.
  107. jimmycuadra/pushing-hands
    bejeweled variant where you swap whole rows at a time.
  108. doowttam/game-off-2012
    unique fix-the-pattern game.
  109. sunetos/game-off-2012
    unclear body simulation game.
  110. dicksontse/game-off-2012
    snake, without the snake.
  111. imagentleman/hackris
    original, but pointless incorporation of cloning and pushing into a typing game.
  112. brooss/game-off-2012
    answer text-questions, and hang out in a chat room.



    Games after this point did not make it into the list, but maybe it's just me.



    Not-quite-games

    I don't agree that those entries count as "games", so I couldn't compare them fairly.

  113. timehome/game-off-2012
    a clone of robocode; which, as you know, is not a game, but an AI competition.
  114. pkukielka/radiance
    a psychedelic experience, to be sure, but is this a game?

    Annoying

    I could not stand playing those games for long enough to give them a fair comparison.

  115. mosowski/game-off-2012
    a 3D game designed to give you motion sickness? why??
  116. gnius/droplet
    avoid the obstacles. annoying alert bomb each time you die.
  117. abrie/game-off-2012
    unique finger-twitching game with intentionally irritating controls.
  118. ess/game-off-2012
    platformer with intentionally irritating controls. too hard and annoying for me.

    Buggy

    I could not play those games either.

  119. heisenbuggers/game-off-2012
    buggy boggle variant.
  120. Dlom/game-off-2012
    buggy duck shooter with a silly intro.
  121. TARGS/game-off-2012
    buggy bejeweled variant.
  122. CalPolyGameDevelopment/ettell
    mini-games
  123. shinriyo/game-off-2012
    3D choose-your-character and sink-into-the-ground?
  124. dawicorti/helping-pibot
    you're supposed to be able to create new pieces, but they get messed up.

    Technical difficulties

    I am not entirely sure that those games would also fail on your computer.

  125. Finjitzu/Archetype
    placeholder?
  126. nuclearwhales/push-the-box
    doesn't work, even with "chrome native client" enabled and relaunched?
  127. drabiter/magnet
    requires access to my computer to run?
  128. py8765/game-off-2012
    abandoned Draw Something clone?
  129. MS-game/game-off-2012
    maybe my Java player is too old?
  130. reedlabotz/game-off-2012
    the "Create new game" button doesn't do anything?
  131. OpenSismicos/game-off-2012
    applet requesting access to my computer?
  132. wprogLK/4thDimensionGame
    failed to run.
  133. jamescostian/game-off-2012
    got a blank page, but this is supposed to use a 3D library?
  134. BumbleBoks/game-off-2012
    unclear path-drawing game.
  135. prgnization/game-off-2012
    you're supposed to be able to chat (as a core game mechanic!), but the text field doesn't respond to my keyboard.
  136. elmariofredo/game-off-2012
    the video shows a working level, but I my character doesn't go past the zeroth level.
  137. ThatsAMorais/game-off-2012
    a strategy game, but the units don't move unpredicably?

    Incomplete

    I couldn't play those games until the end, which is sad, because some were very promising.

  138. publysher/game-off-2012
    incomplete text adventure about eating a steak.
  139. MikeRogers0/game-off-2012
    short platformer with no ending. interesting shoot-your-own-platforms mechanic.
  140. SoftlySplinter/game-off-2012
    a shoot-em-up without things to shoot.
  141. mhluska/game-off-2012
    incomplete olive bouncer.
  142. Annovean/game-off-2012
    incomplete osmosis clone.
  143. leereilly/follow-dem-game-off-forkers
    item collection game with no way to lose.
  144. ozh/alchemy
    doodle-god clone
  145. Blipjoy/game-off-2012
    incomplete UFO-themed object-dragging game?
  146. FluffyCode/game-off-2012
    octopus-in-the-desert-themed top-down shooter
  147. ImmaculateObsession/game-off-2012
    some level editor with no way to play?
  148. devNil/game-off-2012
    a so-called "inverted tower-defence" which you can win by repeatedly clicking the "warrior" button.
  149. EpicFailInc/game-off-2012
    destroy walls using bombs and lose HP for no reason.
  150. ihcsim/game-off-2012
    top-down shooter in which you can't win nor lose.
  151. gcoope/game-off-2012
    hang-glider inverse shoot-em-up with no way to win.
  152. vespertinegames/game-off-2012
    prototype tile-based movement.
  153. wskidmore/game-off-2012
    for a game in which you have "endless destructive powers", there sure aren't many things to destroy.
  154. jamestomasino/game-off-2012
    just a grid.
  155. freejosh/game-off-2012
    the engine for a platformer.
  156. dparnell/game-off-2012
    a maze, but you no way to explore it.

    Access denied

    Maybe it's just a server configuration issue?

  157. superally/game-off-2012
    access denied.
  158. DarkForestGames/game-off-2012
    403 forbidden.
  159. lazyeels/game-off-2012
    forbidden

    Abandoned

    Some people wrote down their game ideas, but never got around to implement them. Others picked a URL, but never uploaded anything there.

  160. strugee/game-off-2012
    abandoned placeholder.
  161. cmdkeen/game-off-2012
    abandoned game concept.
  162. Willshaw/game-off-2012
    abandoned game concept.
  163. Vbitz/game-off-2012
    placeholder.
  164. EvilSpaceHamster/game-off-2012
    page not found
  165. fabriceleal/game-off-2012
    abandoned placeholder
  166. CodingEffort/game-off-2012
    page not found
  167. Jorjon/game-off-2012
    page not found
  168. mbl111/game-off-2012
    placeholder
  169. matthewtole/game-off-2012
    404
  170. will3942/game-off-2012
    placeholder

Monday, August 13, 2012

A little bit of Waterfall

Agile, what have you done! I used to believe in you.

There I was, happily finishing iteration N of my online board game library, unaware of the terrible event which would shatter iteration N+1. While thinking about which features I would like to add next, I stumbled upon a major feature for which I was not ready yet, and probably never will! Not with this codebase, anyway.

This was a board game library. I was working on a board game library because recently, I have been playing a lot of digital board games on my iOS devices. I was mostly playing them in the subway. So, it would make sense to assume that a major use case for my online board game library would be for a group of friends to play together in the subway, or on the train, while waiting to get to their destination.


The problem is, there is no internet in the subway.

My codebase was an HTTP server written in Haskell, so I pretty much had to scrap the project and start anew. I'm trying node.js this time, this should allow me to use the same game logic on the server (for distributed games), as on the browser (for local games).

The point of this post is not that node.js is better; I don't know that yet. The point of this post is that if I had done a bit more planning at the beginning of the project, the "also works offline" requirement would have jumped at me as being the serious technology-limiting, can't-do-it-in-Haskell-then factor that it is. I didn't spot it early because I didn't plan that far ahead: being a good Agile developer, I only planned the features I could complete within the first iteration.


Clearly, I am not going to ditch Agile on the first offence, but next time, before I even begin iteration 1, I am certainly going to spend some time collecting requirements. And throwing them in the garbage. After all, the details are clearly going to change midway during the project, that's why we use many iterations. But by looking at a large enough sample of example requirements, I should be able to pick a more appropriate technology next time.


That is, next time, I will put a bit of Waterfall in my Agile wine.

Monday, July 23, 2012

Agile vs Scrum

Recently I have been thinking more abstractly about what Agile is, and why (or whether) it is good. The first thing I have discovered is that I was not, in fact, following Agile's practices, but Scrum's!

The difference between the two is less subtle than I thought.


According to the Scrum guide, Scrum consists of "roles, events, artifacts, and the rules that bind them together. [...] Scrum’s roles, artifacts, events, and rules are immutable and although implementing only parts of Scrum is possible, the result is not Scrum."

That is, Scrum has rigid rules which cannot be broken, mandatory meetings with strict time limits, and long lists of responsibilities for each role.


According to the Agile Manifesto, Agile is a short list of four value judgments.

That is, Agile lets you make your own decisions, but leads you in the right direction by (1) emphasizing the important goals, and (2) reminding you that achieving those goals may require you to sacrifice other goals.


Clearly, Agile is much more flexible than Scrum, while Scrum is much more complete and precise. Since I like to tweak my workflow from iteration to iteration, I think Agile is more appropriate for me.

Surprisingly, Agile by itself doesn't even mandate the work to be divided into iterations, and neither of them requires the work to be divided into stories! So... whose recommended practices have I been following, then?

I feel like there is a third contender which I have yet to discover.

Wednesday, June 06, 2012

Specification aphorism

I would rather have an imperfect program which does the wrong thing than a perfect specification which doesn't do anything.


That is all.

Sunday, May 20, 2012

Thank you, KeyRemap4MacBook!

At long last! I managed to fully reproduce my Linux xmodmap layout on OS X.


I don't think I have particularly peculiar typing needs. I often type code, which frequently uses characters like "[", "{", and "<". Those are easy to type using the US keyboard layout. I also often type French, which frequently uses accented characters like "é", "à", and "û". In that situation, most people opt for switching between keyboard layouts depending on the situation. I, however, opted for a custom keyboard layout.

My custom keyboard layout is mostly the US keyboard layout, plus some Alt+key combinations for dead keys like "´", "`", and "^". On Linux, this was easy to setup using xmodmap. Implementing the keyboard layout on OS X was a bit more complicated, because its XML representation of keyboard layouts is very long and it's not easy to test changes incrementally, but I eventually managed to do it.


Then one day, I decided that the modifier keys were too low.

I am not even using Emacs, but typing Ctrl with my pinky is really twisting my hand in a way I don't like. So I bought an ergonomic keyboard. It didn't help.


One of the reasons I chose this particular keyboard was because of the two little extra arrow keys below the space bar. I thought I could remap them to Ctrl and Shift, thereby allowing me to type those troublesome modifiers using my thumb instead of my pinky. That didn't work either. The keyboard preferences which were installed with the keyboard helpfully allow me to remap those to any other key... except modifiers. No luck directly modifying the layout files either, not even through keyboard layout creation tools like Ukulele. I did manage to turn Caps Lock into an extra Ctrl, but the other modifiers looked like they would be stuck in place forever.


I had no such problems with Linux. Again using xmodmap, I converted the key above the enter into an extra Shift key, much to the relief of my right pinky. The only annoyance with this solution was that I kept trying to use that key as a Shift on the Mac computer too, only to be presented with a disappointing backslash character as a result.

Well, those days are now behind me! Today, I downloaded KeyRemap4MacBook, a very helpful tool which managed to accomplish what so many others had failed. I am now typing this text on my Mac, using the backslash key as a Shift! And my right pinky is very grateful.


Thanks, KeyRemap4MacBook!

Sunday, April 29, 2012

Building qtHaskell on OS X


Finally! I spent the entire weekend on this, but I finally managed to compile qtHaskell on OS X. I spent a lot of that time on the internet googling for the error messages I encountered, to no avail. So, to save some time to the next person who google them, here is what worked for me.


The qtHaskell documentation recommends that you use their ./build perl script. That almost works, but not quite. Thankfully, by giving arguments to the scripts, we can run the parts which work, and skip over the parts which don't.

Speaking of arguments, one the most annoying errors is the "scattered reloc r_address too large" error message which only occurs at the very end of a very length compilation. I stumbled upon a page recommending to use "--extra-ld-opt=--architecture=x86_64" to fix a similar error message, and since then I have superstitiously stuck the argument everywhere I could, just to be sure.


So, let's build qtHaskell, shall we? First of all, qtHaskell is a set of Haskell bindings for Qt, so you need to install Haskell and Qt. I used Qt 4.7.1, qtHaskell 1.1.4, and GHC 7.0.4 (64 bits). Actually I had the 32 bits version of GHC at first, and that let to the aforementioned r_address problems, followed by linking problems afterwards. Better upgrade to 64 bits!

brew uninstall ghc
brew install ghc --64bits

We should now be ready to compile qtHaskell proper. There are actually two parallel hierarchies to be compiled, the C++ implementation and its Haskell FFI interface. Both are very large, because, well, Qt is large.

First, the C++ part: no problems here, the build script works just fine for this part.

./build user cpp qmake cmake \
    --extra-ld-opt=--architecture=x86_64
./build user cpp-install \
    --extra-ld-opt=--architecture=x86_64 --no-sudo

Note that even though the "user" flag was given, the build script will still
install the files globally in /usr/local/lib/libqtc_*. Presumably, the flag is only for the Haskell part, for which the steps would ideally be as follows.

./build user haskell configure \
    --extra-ld-opt=--architecture=x86_64
./build user haskell build \
    --extra-ld-opt=--architecture=x86_64
./build user haskell-install \
    --extra-ld-opt=--architecture=x86_64 --no-sudo

Unfortunately, the middle step fails with the following error message.

unrecognised command: makefile (try --help)
runghc Setup.hs makefile: No such file or directory

Fear not! This cryptic-looking error message is actually a clue towards the solution. Apparently, "runghc Setup.hs makefile" is the command used for building the Haskell part. Using the help, as recommended in the error message, leads to the following alternative build commands.

runghc Setup.hs configure --user \
    --extra-ld-opt=--architecture=x86_64
runghc Setup.hs build

Unfortunately, that doesn't work either, at least not with a recent GHC. There is a problem in the qtHaskell code, which leads to the following error message.
Qtc/Core/Attributes.hs:583:13:
    Could not deduce (Qstt a (QDialogSc b))
      arising from a use of `slotReject''
    from the context (Qstt a (QDialogSc b1))
      bound by the instance declaration
      at Qtc/Core/Attributes.hs:581:10-52
    Possible fix:
      add (Qstt a (QDialogSc b)) to the context of
        the instance declaration
      or add an instance declaration for (Qstt a (QDialogSc b))
    In the expression: slotReject'
    In an equation for `reject'': reject' = slotReject'
    In the instance declaration for `QsaSlotReject a'


If you are familiar with Haskell, you should be able to fix the problem on your own. Alternatively, you could grab Uduki's hsQt fork of qtHaskell, which comes pre-patched. Or you might apply the following patch yourself:
diff --git a/Qtc/Core/Attributes.hs b/Qtc/Core/Attributes.hs
index 197c506..217d585 100755
--- a/Qtc/Core/Attributes.hs
+++ b/Qtc/Core/Attributes.hs
@@ -580,7 +580,7 @@ class QsaSlotReject w where
 
 instance (Qstt a (QDialogSc b)) => QsaSlotReject (a) where
   slotReject' = (Qslot "reject()", \_ -> ())
-  reject' = slotReject'
+  reject'     = (Qslot "reject()", \_ -> ())
 
 class QsaSignalRejected_nt_f w x f where
   signalRejected', rejected' :: x -> SltConf w f

Now that the source is patched, the Haskell part should finally compile.

runghc Setup.hs build

If you run out of memory during this phase, just run the command again. And again. As many times as it takes to compile all the targets. When you get the the very last target, qtHaskell is finally linked... and then, like me, you might get one of those nasty "scattered reloc r_address too large" errors. Did you? If so, you might have skipped the very first step and be stuck with a 32 bits version of GHC. Check using "ghc --info".

If you insist on using the 32 bits version, you could try the following variant of the build command, which got me through that step. Still got troubles when linking programs using qtHaskell, though.
runghc Setup.hs configure --user --disable-library-for-ghci

Now that the Haskell part is built, we can finally install it! This time, the "user" flag is honored.
./build user haskell-install \
    --extra-ld-opt=--architecture=x86_64 --no-sudo

Let's test this! The qtHaskell helpfully provides the following Hello World code, just put it in a file with the "hs" extension and build it into an executable using "ghc --make".

module Main where

import Qtc.Classes.Qccs
import Qtc.Classes.Gui
import Qtc.Gui.Base
import Qtc.Gui.QApplication
import Qtc.Gui.QPushButton

main :: IO Int
main = do
  qApplication ()
  hello <- qPushButton "Hello qtHaskell World"
  resize hello (200::Int, 60::Int)
  qshow hello ()
  qApplicationExec ()
Tada!
At long last. A button!