M.C. Escher - Metamorphosis II

zoneToRA / ToRAsConsole

Sun, 03 Feb 2008

Lost

Click for full version

This was a real conversation with a cabbie while trying to get to MSR for a meeting about things I could do for my PhD. Needless to say we did find it in the end. Next time I guess I'll have to make sure I have the address of where I'm going...

[/general] permanent link

Tue, 22 Jan 2008

Seeing only stars...

Yes, this blog entry is late this week. I have an excuse.

Cli
version

I never claimed it was a good excuse though. Super Mario Galaxy is, however, an awesome game. It's great fun, slightly addictive, and a great example of a simple game that works well without being overcomplex.

Now there's nothing in the game thats fundamentally new. Platforming in 3D was done in Mario 64 and Mario Sunshine, as-well as the Tomb-Raider series and many other games since. Even the format of many small levels you keep re-visiting to find different stars in was from Mario 64.

What about gravity and planets? Well there were 2D scrollers on the NES that had ways of swapping gravity. In 3D? Variable gravity was a great feature in Prey, and Zelda had areas with magnetic boots that were tantamount to the same thing. Planet and platform hopping in 3D is reminiscent of the previous Mario games, and the likes of Monkey Ball and DK Jungle Beat. I may concede that (as far as I know) this is the first game I've seen where can jump between platforms in 3D and quasi-float round them due to gravity.

Mentioning DKJB, I should point out that quite a few things seem to have migrated into the Mario franchise from that game - including (or perhaps especially) enemies. This seems sad, as there were plenty of SMB enemies that could be used, but they seem to continually become dropped and the existing ones are now more caricatures of their original forms from the earlier games, and, annoyingly, becoming easier to kill as the games evolve.

For example:

At least boo's can't be trivially killed now.

Anyways, I seem to have digressed. The point is, it is a fun game, and just when you think you've seen all the formulaic things it can throw at you, it adds just one more new thing to try out / see / do. Green stars, tricky (but much overrated ;)) trial galaxies, hungry stars, hidden stars, power stars, Luigi stars, comets, rabbits, goomba's, planets shaped like a Yoshi head...it's all there :).

The sound track is also stunning. Apparently it's live-recorded orchestra and disc-streamed. A very good move, and it really sets the mood, especially given a lot of the music are 'Mario classics' but re-recorded very nicely.

And now, CSI is on...normal service may resume next weekend...or I may talk about card magic.

[/general] permanent link

Sun, 13 Jan 2008

Simplifying Code

The process my brain goes through when programming...

Click for full
version

And now to prove the point of the diagram...

A task I've come across several times while programming is taking a list describing a template, and completing it with input from elsewhere.

Let me describe further (this post is a literate Haskell file...)

> import Data.Maybe > import Control.Monad > import Control.Monad.State > import Control.Arrow

For example, the list:

> testTemplate = [Just "This", Nothing, Just "a", Nothing, Nothing]

describes a template, where the first and third elements are fixed, but the remaining (second, fourth and fifth) elements come from external input.

So if testTemplate was used with the following filling...

> testFilling = ["is", "simple", "test"]

The result we expect would be:

> testResult = words "This is a simple test"

So we need to implement a function of type [Maybe String] -> [String] -> [String], and it should make our test give back True.

> test :: ([Maybe String] -> [String] -> [String]) -> Bool > test combiner = testResult == combiner testTemplate testFilling

Now the most explicit way to do this is to use pattern matching, and just work through the cases on the template list...

> combinerRec :: [Maybe String] -> [String] -> [String] > combinerRec [] _ = [] > combinerRec ((Just t):ts) filling = t:combinerRec ts filling > combinerRec (Nothing:ts) (f:filling) = f:combinerRec ts filling

Thing is, I rarely ever use explicit pattern matching nowadays (especially when it comes to lists and maybe), as there are a whole host of combinators that do it for you. Also using combinators over pattern matching can make your code a lot more readable. And anyways, explicitly writing out the recursion fills me with an ill feeling.

So what are we to do? Well one trick is to notice that the filling is actually some state in the algorithm. For each template element, we peel the next element off the state or just carry it across, depending on whether the template element is Nothing or Just.

> combinerState1 :: [Maybe String] -> [String] -> [String] > combinerState1 = evalState . mapM (maybe getNext return) > where > getNext = do > (h:tl) <- get > put tl > return h

Well that's concise-ish, and (assuming you know the standard libraries) is quite clear / reads well. Of course getNext's definition is a bit verbose, but it's hidden by a meaningful name.

But wait, there's more! If you stare at getNext for a while, with the definition of State next to it, you'll realise that State (\(h:tl) -> (h,tl)) does the same thing. So we can rewrite inlining getNext and using arrow combinators instead of the explicit lambda...

> combinerState2 :: [Maybe String] -> [String] -> [String] > combinerState2 = evalState . mapM (maybe (State (head &&& tail)) return)

Arn't we clever? Possibly too clever, while it is a 1-liner, it doesn't (to me) read like psuedo-english. I'd probably use something like this in reality, as (I think) it reads slightly better.

> combinerState3 :: [Maybe String] -> [String] -> [String] > combinerState3 template = evalState $ forM template (maybe getNext return) > where > getNext = State (head &&& tail)

So there you have it, how to spend at least an hour and a half blogging about how you can simplify a 3 line haskell function down to one line, and then realising that a different 3 line function reads better if you know lots of esoteric parts of the Haskell standard libraries. At least I havn't tried to write a monad tutorial...

[/general] permanent link

Tristan Allwood's weblog

M.C. Escher - Metamorphosis II