robburke.NET
© 2010 Robert Burke
All Rights Reserved.

Legend of the Greasepole Title Screen

Legend of the Greasepole has been ported to Silverlight 4 and reincarnated on http://greasepole.net.

Greasepole is the long-suffering game about multimedia tribute to the inexplicable Engineering traditions at Queen’s University in Canada. Over 50 students contributed to the project back in the day.

There’s a significant AI component to Greasepole – the autonomous “frosh” characters have models for learning and communicating with one another.

A couple of years ago I ported it from C++ to C# and XNA. I abstracted out a series of services (graphics, sound, input, timer, persistence) so that it might ultimately be ported again to a platform like, say, Silverlight or something. Why? I don’t know, maybe I’m a little obsessed with the illusion of preservation.

The Silverlight 2 version was a bit shaky. Silverlight 4′s hardware acceleration and bitmap caching make it pretty solid. It is also awesome to hear from friends that it apparently works on the Mac.

Analyze These… Shenanigans

I also added a little analytics. Although it should probably be said that the Greasepole event largely defies analysis, the game itself does not, and so this is the first time I can let someone poke their head in and see how the froshies are doing all around the world.

Back in the day, the worldwide best time was in excess of a mere 53 minutes. But I had to learn that by way of Sean Murray (class of ’05; wonder where he is now) sending me a screenshot. Now the interwebs will tell us immediately. (Admittedly, it’s not a fair fight against Sean, because the frosh are now permanently in “keener” mode, and the Options screen has been replaced by a dozen trendy Achievements for you to “unlock”).

So get going stalling those frosh, and my question for you is – what statistics would you like to see?

“Number of pints Al ‘Pop Boy’ Burchell has quaffed?”

“Number of hippos fed”?

“Height of human pyramid vs time”?

I am going to enjoy cooking up visualizations for some of those.

(Coding notes: A few new VS2010 things helped with this update: Web.config transformation (rocks), improvements to Web Publish functionality, XAML designer, Entity Framework experience… and more.)

Play Legend of the Greasepole Online Edition.

Hello, Roomba

Hello, Roomba!

I finally watched a Roomba dance its funky dance.

The iRobot Roomba 550 we affectionately named Butler spent a half-hour cleaning the 4 downstairs rooms of a home, sucking up an impressive gob of dust from the previous night’s party.*

As I watched Butler, I realized I’d forgotten…

How inclined we are to anthropomorphize technology.
(His name is Butler, you see…)

How we’re wired to perceive complex reasoning where only simple behavior exists.
(He was doing his best to explore and clean his new home…)

How important it is to have users on your side!
(Because Butler was occasionally bumbling but always so helpful — looking everywhere for last night’s crumbs, remembering which area needs more attention, and just generally “doing his best.”)

First Impressions

The design of the unit is clean, sleek, and functional.

Roomba in Motion across the rug

Roomba in Motion, scooting across the rug

The “wall following” behavior is particularly clever and plays to the strengths of the round unit.

Object detection mostly works (it’s supposed to slow down before a bumper-kiss), but it was blind to some antique table legs on our test run, threatening to knock over some photo frames and antique china.

Its motion is smooth, and it successfully un-stuck itself from the curtains.

I loved watching it ultimately find “home base” by IR and dock with it, 2001 Blue Danube style.

But I worried..

  • About non-techie users having to choose a “home base” location. A sleepy Roomba needs to locate its home, but a resting Roomba is hardly showpiece décor.
  • About long-term battery wear and life.
  • About how often you’d need to empty the dust out of his bowels, and what happens if you forget to do so.
Roomba Cleaning Patterns (from the manual - click for .pdf download link)

Roomba Cleaning Patterns (from the manual .pdf)

Navigation & Hackery & Papers

Roomba uses behaviors like spiraling, wall-following and room crossing (as explained in the image, right, from the manual) to create its not-quite-completely-random walk.

And below, check out this very clever 30-minute long-exposure photo (found at SignalTheorist via Botjunkie) that reveals the Roomba’s “Lovely, Inefficient” cleaning path.

Roomba Path Long Exposure

Roomba Cleaning Path - Long Exposure Image

This brings us inevitably to the hacking. iRobot, to their credit, encourage you to hack Roomba!

Martha, whose Roomba apparently can bring her beer (wait… what?!), recommends the book Hacking Roomba. Here’s the book’s companion website.

Is anyone still using Microsoft Robotics Studio for stuff like this?  (ah, the memories of dancing Lego robots.)

In the meantime, with my head full of Roomba, it’s the perfect time to re-read some of iRobot Founder Rodney Brooks‘ seminal papers, like Intelligence Without Representation and Elephants Don’t Play Chess.

Because Elephants these days apparently can clean living rooms!

*the dust was left behind from the previous night’s party, in an otherwise impeccably clean home (i.e. not mine)

deutscher

Deutscher's The Unfolding of Language

When Stephen Fry laments “it is a cause of some upset that more Anglophiles don’t enjoy language,” it’s as if Michael Phelps were to lament that not enough people enjoy water. So when Stephen wholeheartedly recommended Guy Deutscher’s The Unfolding of Language, which he characterized as more playful and engaging than books on similar subject matter, I was hard pressed to say no. It’s taken me ages to find time to get into the meat of this book (strictly my own fault), but now, about two-thirds of the way through, I wanted to offer it my wholehearted recommendation for anyone who is even remotely interested in language and its origins and evolution.

Deutscher’s prose is indeed playful and accessible, his examples thought-provoking, and his subject matter fascinating: what are the forces that shape and transform language?

Deutscher mentions more than once that “These days, there are no systems of communication which are in the process of evolving their first words.”  He’s right, I suppose, but only on a technicality.  Last week I was taught the basics of a computer scripting language I’d never worked with before. Surely the constructs of some arbitrary scripting language represent one of many “artificial” systems of communication which are in the process of evolving their first “words” (and tokens).

I am writing this now as Deutscher transitions in the book from talking about the destructive forces which are applied to language (which favor economy, expressiveness, and analogy), into the constructive ones which enable new linguistic richness to blossom. Metaphor, apparently, provides many of the raw materials for new grammatical elements.

With that observation under my belt, and aspiring to be a creative force in the universe, I suddenly feel a bit better about my obsession with admiration of Roger’s Profanisaurus (a dictionary of profanity that originates in the pages of the UK’s Viz magazine, which derives cleverness and vulgarity in equal measure from a playful, multi-layered cocktail of metaphor, rhyming slang and other wordplay).

And of course there are my dear LOLcats, who reflect (again in equal parts) the absurd and absurdly rapid evolution of linguistic memes as they’re propelled at the speed of the internets. Since I’m in Ireland, and Deutscher recently reflected on the necessity of the word possessing-implying “have”, here’s a somewhat appropriate LOLCat I just cooked up  – with my cap off to Jim Condron for his help with the Irish word for “flavr.” (context here for the uninitiated)

Orish Kitteh Ubserves: Deres a flavor on meh

oirish kitteh tinks: deres a flavr on meh, so dere iz.

Back to Deutscher’s book.  He spends the fifth chapter illustrating a point by employing a fictional dialogue between a cast of characters at a ‘George Orwell Centennary Conference’.  it’s a technique akin to the one I admired in Hofstadter’s Godel, Escher, Bach. Actually, that’s all I have to say.  Check it out.  Go for a swim.  And apologies to Deutscher, Mellie, Fry for this rambling but heartfelt review.

I didn't like this movie.I was asked a few weeks ago about why Artificial Intelligence over the past few decades has been such a “failure”, meaning mostly that it isn’t seen to be living up to its great expectations.

James Gaskin at NetworkWorld gives a well-referenced response very similar to the one I gave back then, which went like this:

Essentially, whenever some field of AI achieves a result, the successful work is given a name (intelligent search, [something] recognition, adaptive [something], smart [something], etc.), it leaves the lab, has an impact on industry / research / our lives, and “Artificial Intelligence” remains loosely defined as “the tough cognition problems we haven’t solved yet.”

Mind you, even defined in that way, Marvin Minsky would probably still agree that the creators of AI really need to get a hustle on.

If you’re authoring multimedia applications in Silverlight, you might be interested in how each of the core game engine services for Legend of the Greasepole is now implemented for the Silverlight 2 Beta.

From C/C++ to a Provider Model-Based .NET Engine

Some brief history to explain how we got here: Greasepole’s first incarnation was manky C/C++ stuff that I’d perf-optimized to bits back in 1997-98. Trainwreck stuff.

Migrating that C/C++ mess to a C# mess involved writing a lot of Visual Studio 2008 macros. These macros could gain surprising insight into non-compiling half-C++, half-C# code, in order to sweep through and perform laborious changes.

What came out the other end of the refactor was a C# core engine for the game that required the implementation of five platform-specific services:

  • RenderingService,
  • SoundService,
  • InputService,
  • GameTimerService, and
  • GameSettingsService.

I previously implemented those services for the XNA version. Now let’s look at the Silverlight versions of these services.

Silverlight RenderingService

When each frame is rendered, the engine ultimately requests that the RenderingService draws a series of sprites from particular “frame descriptions” or “FrameDesc”s (a vestigial name, essentially meaning bitmaps with metadata) at given (x,y) coordinates:

public void DrawBitmap(TSprite associatedSprite, FrameDesc frameDesc, int nScrx, int nScry, byte[] replaceRGB, byte[] substituteRGB)

The bitmaps themselves are stored as Resources in two assemblies (SilverLegendAssetsMenu.dll and SilverLegendAssetsGame.dll) that I download on-demand using WebClient. This has the advantage of dramatically reducing startup time, and only requiring the game engine to manage the downloading of two files over the web after startup. An equivalent option would have been downloading archives full of bitmaps, but I was concerned that this would require decompressing the bitmaps at runtime.

The RenderingService pre-caches the URIs for the bitmap associated with each FrameDesc (e.g. “SilverLegendAssetsGame;component/Graphics/Frosh4a.BMP”) so that the bitmap can be looked up without string manipulation whenever it is requested by a sprite.

Each game sprite is assigned its own System.Windows.Control.Image by the RenderService, which is initialized by having its UriSource Property set to a System.Windows.Media.Imaging.BitmapImage. When the FrameDesc for the sprite changes (and therefore the sprite’s bitmap appearance has changed), the Source Property of the BitmapImage, a URI, is changed to the appropriate cached Uri. (It looks as though you’re not permitted to re-use BitmapImage instances across multiple Images.)

Mirrored images are achieved by setting a MatrixTransform on the sprite’s Image’s RenderTransform.

Z-Ordering is performed by using the ZOrder property on the Images.

After each frame is rendered, the RenderingService iterates through all the Images on the Canvas, looking for any that weren’t rendered during that frame and therefore should be removed from the Canvas.

But what’s with the byte[] replaceRGB, byte[] substituteRGB parameters on the DrawBitmap call? In all the other versions of Greasepole, the characters became multicultural by performing color-key swapping of their solid skintones. The DirectX engine used two BitBlts, and the XNA engine uses custom shaders. Achieving this in real-time with Silverlight 2 is something I haven’t yet figured out.

Silverlight SoundService

Sounds assets are stored as MP3 Resources in the previously-mentioned download-on-demand assemblies SilverLegendAssetsMenu.dll and SilverLegendAssetsGame.dll.

Just as with with RenderService, the SoundService pre-caches the URIs to all the sound files.

The SoundService keeps a static collection of MediaElements around. These are added as children to an invisible Canvas called SoundCanvas. When the engine requests that a sound is played, the SoundService finds an unused MediaElement in the static collection, sets its Source Property to the correct URI, and Play()s it.

The MediaElement’s MediaEnded event is handled to either loop the sound by either (1) setting .Position=TimeSpan.Zero and calling Play() again, or, (2) if it’s not looping, to add the MediaElement back to the static collection of available Media Elements.

Incidentally, this whole MediaElement juggling trick was a highly unstable process in the Silverlight 2 Alpha which seems to work reliably in the beta.

Silverlight InputService

In the Silverlight 2 Beta, handling input was a piece of cake. Mouse and Keyboard events are handled for events on the main Canvas to inform the InputService of human interaction.

Unfortunately for game developers, keyboard input is more or less crippled when Silverlight is in fullscreen mode. Luckily, we’d designed Greasepole to be playable with just one mouse button.

I also wish I could use the right mouse button for input, but instead it brings up the Silverlight Configuration menu.

Silverlight GameTimerService

To create a game loop, Greasepole uses the “empty Storyboard technique” outlined at Silverlight Games 101. The game loop calls Update enough time to ensure a constant 24 updates-per-second update rate, and Render whenever possible, which triggers the RenderingService (see above).

In every other respect, the game timer is the exact same as in the XNA version. DateTime.Now works as advertised!  Here’s to a common set of .NET Framework classes!

Silverlight GameSettingsService

The IsolatedStorageFile API makes it very easy to rapidly save and load game settings in a local sandbox.

See this sample for more information on how to use the virtual file system in Silverlight. The GameSettingsService uses a very similar technique.

Previous Articles »