Tuesday, March 31, 2009

Blast From The Past

A long long time ago, in the days before the Weird World Web. In a time of BBS’s and modems. A time when viruses roamed every floppy disk and computers were IBM Compatible.
In that faraway past just before the last decade of the 20th century a game was created by Activision.

This game was far ahead of it’s time. So far in fact that since its creation it was never again duplicated. Many tried, none succeeded.

I am speaking of course about Death Track (cue insane laugh).

You may find yourself thinking: "Death Track?... Death... Track? Really? I mean Death and Track?? "
Yes. Really!

I know the name is pretty lame (lame is also pretty lame)* but the game is not. You see, Death Track had everything. It had cars with cool and exciting weapons, it had contract killing and it had upgrades.

Ok, let me explain:
Death Track was the first Racing+Shooting game i ever played. I have played all racing+shooting games i could get ever since. No game was ever like Death Track. It may just be the nostalgia talking but i really think that at least until this point in time, it has never been surpassed in it's genre.

Many games since added some element of weaponry or destruction, but no racing game i know was solely dedicated to killing off your opponents. To facilitate this the game offered a wide array of weapons:
Machine guns, Lasers, Mines, Missiles, Ram Spikes and more. All the weapon systems in the game were upgradable. This was a very important element in the gameplay. you always wanted more: better weapons, better armor, faster engine. There were plenty of things you wanted to upgrade. Some helped you make money by winning races while others helped you win races by killing off the competition.

Of course, the competition didn't wait around for your to kill it. They would go after you as well. The game also featured contract eliminations that won you large sums of money if you succeeded. These were substantial enough to focus on killing your target even if you didn't get 1'st prize from winning the race.

I think that the upgrade elements were an important part of what made it so addictive. The game managed to always keep you wanting more, and you got to feel a real sense of acheivement when you got that next upgrade. And it payed off too. There is nothing more satisfying than blowing up your nemesis with your new tracking missiles.

I wonder why this was never done since. There are plenty of racing games around, and plenty of racing game engines. Many of which feature arcade to ultra-realistic damage systems. I would really love to see an arcady Need For Speed based game combining weapons, upgrades and total destruction.

On that note i would like to say that many of the console racing games have this element of certain upgrades opening up only after you played part of the game. I think this is really the wrong way to keep players interested. Money is a great way to achieve this: Its clear and its a simple way to give you multiple alternatives. If you feel that the only thing stopping you from getting to that next upgrade is X amount of $ its a whole other thing then knowing you need to complete the next stage or circuit. The fact that you have to comparmise and think about what to upgrade adds certain elements longer term strategy.

In many games you don't even know what's available. Give me the option to buy things and make the purchase worth-while. Let me feel i get an edge, a sort of "cheating" advanted over my oponents that really makes a difference in the game. The best way to keep gamers interested is by dangling the possibility right in front of them, and allowing them to choose how they get it.
If i want to play that same level 10 times on an easier setting to get the money for the upgrade i want - give me that option.


Its now twenty years since Death Track came out, and it seems like i should maybe let go of my dream of playing a game like that again on modern hardware, engine and graphics. But if there ever was an industry that keeps recycling the classics its the gaming industry.

My only fear is that it comes out exclusively for PS3...

Addendum:

Mmmm....I have just been informed that i am an idiot. turns out that in the very link i added was the link to the New version of Death Track!
I am downloading the demo now. Thanks Dan, I Can't tell you how exciting it is to finally play Death track with modern graphics.


* - That's a triple lame sentence. This is the first time such a fete has been attempted. Do not try this at home.

Monday, March 30, 2009

Trivial Statistics

So we got the new Scene It? Box Office Smash for the xbox 360.
We really like trivia games and we especially enjoy the Scene It series (we also have Lights, Camera, Action).
We like the subject, but much more than that we enjoy the presentation. Questions like anagrams, pictogram, skewed images that gradually clear, sound bites that require that you pay attention to the details etc'. All in all its a well made game with original question presentation. It also has the advantage of being one of the too few 4 player games (on the same xbox).

However, there is a serious downside to the game and it has to do with the way questions are selected.
In Scene It? Lights,Camera, Action there were 1,800 new questions (For some reason this information on Box Office Smash is hard to track down). Unfortunately we never got to experience all these questions because relatively quickly we started noticing questions repeating. This got me thinking: there are 1,800 questions and there's no way we played long enough to see 1,800 questions, why are we seeing repeats?

The cause as it turns out, is statistics. Specifically a phenomenon similar to the birthday paradox.
Quick review for those who are not familiar with the birthday paradox and can't be bothered to read the wiki page:
If you sit in a room with a group of 23 randomly selected people (like a classroom) there's a 50 percent chance 2 people in the room have the same birthday.
for 57 people there's >99% chance for two people to have the same birthday.
To get the general idea why your intuition (that this is sounds wrong) is wrong, think of the 2 kids in your elementary school or high school class that had the same birthday.
Oh, and think of how many people you know that also had 2 kids with the same birthday in their class (hint: you went to school with them :) )*.

How is this the same for a game that randomly selects questions?
Without going into the math too much lets assume you played the game for a little while and you saw 180 questions (10%).
At this point, the probability that the next question is a question you already answered is ~1/10. This already is high enough to be discouraging. Worse yet, the expected number of repeat questions until you reach 180 questions is ~8.4! (because of the birthday paradox).
Now lets assume you played long enough to answer 600 (~33%) questions in the game. Out of the 600 question ~80(!!) are expected to be repeats. Needless to say, if you saw a third of the questions (you need to answer more then 600 questions for that) then one in every three questions will be one that you saw already.
At 1/10 its annoying. at 1/3 the game is unplayable. So everybody loses. You enjoy only about a third of the value you thought you were getting from the game, and the game developer works very hard to create 1,200 more questions that you will never see.

The good news is that there is a pretty simple solution for this problem that works out well for everyone.
You see, the problem stems from the method of randomly selecting the questions. Fortunately there is a different method that both guarantees randomly selected questions and no repetitions. instead of "rolling the dice" every time we need to select a game we select a permutation of the sequence of questions (in simple terms - we randomly rearrange the sequence of questions) and save this permutation. This guarantees that you will see all 1,800 questions before you see a question you know.
Since 1,800 is a decent number of questions there's a good chance that you will forget the earlier questions in the sequence. But even if you don't - at least you get to enjoy all of the questions in the game.

BTW: On xbox.com Feature listing for the game mentions a "minimal repeat" feature for the game which keeps track of questions answered to minimize repeats.
I don't know how that feature is implemented, but i can tell you from experience that it doesn't seem to work very well as we saw plenty of repeats. Besides, there's no reason the number of repeats should be anything other then zero.

Oh, and as for the issues of online play and playing against different players etc'. There are solutions to all of these problems (generate a permutation for the unseen subgroup on all player's lists, you can also add a timestamp to the question to ensure a 'long' time between repeats). I know it's not ideal and i know that there are details to work out. But i believe that this is a core issue for any trivia game and a great game needs to give the very best possible solution.

One final point, and i may be way off on this one. I think if i knew that i was running out of questions or if there was some way of indicating to me that i saw most of what's available, it would encourage me to get the question packs. It might be nice if this was done automatically (you only have 200 questions left, why not try the XYZ expansion).

* - yes, yes, i know *technically* its statistical lie. But what better way to fight faulty statistical intuition than faulty statistical intuition?

Monday, March 23, 2009

Amazing!!! The Future of cell phones is here now!!!!

Check this out, it’s this amazing invention! The MODU!
It’s a cell phone, right?

And, get this – it comes in different shapes!!!!

Its so cool and innovative!!!!
I mean, think of the possibilities: you can have like , a yellow slider pone, or like an angular little phone, or this tiny thing with no numbers on it, or like a crazy psychedelic phone with like really small buttons!!!

They will make millions! Billions even! Of possibly dollars!
And you will never believe the specs! Its 2.5 Gen (like the amazing non 3g version of the iphone 1.0)
It has Bluetooth (like the iphone)
It doesn’t have a built in GPS (like the iphone non-3g)
And it has 2 Gig of flash (less (thus lighter) then the cheapest version of the first iphone)!!!
You know, it amazingly also costs like half of what the iphone costs, plus you get 2 jackets! So it’s like 4 times better! Actually you can use the modu without the jacket, so its like 6 times better! So its even mathematically proven to be superior! With numbers!

And if that’s not enough, they have a touch screen. But unlike the silly iphone, it’s not going to do things when you touch the screen, only when you touch the buttons. I mean, the iphone hardly HAS any buttons, the modu has 7 buttons on the tiny version alone! It’s like, obviously if you want to do something you click the BUTTONS.


To show how amazing and cool the modu is, I have made this table of comparison.
Using this table you can clearly see the superiority of the Modu!


Amazing Modu

Silly Iphone

Jackets

4

0

Buttons

7

2

Guinness world records

1

0

Waste battery on WiFi

0

-1

Waste battery on GPS

0

-1

Can become a car radio

1

0

Total awsomness

>1,000,000*

0

* - math is for silly iphone geeks.





Oh, full disclosure - i have one of those silly iphone things.

Thursday, March 19, 2009

War of the Worlds

H.G Wells got the title right. Indeed there is a war going on. A War between Worlds. War between the world of man and the aliens that live amongst us.

This is the story of one man’s struggle in a battle against the odds to defeat the invaders from another world.

It all started years ago when I was living in an apartment not very far from the botanical gardens in Jerusalem. i suspected nothing when I moved in. There was no sign. No declaration of war. No warning shot. They always came at night, just as I was getting to sleep. They waited, sticking to the walls, biding their time. Suddenly – bang! One of them would create a diversion. I did not realize this at the time, but they wanted to get me out of the protection of the covers. They wanted me to bring back the light so they could mark their target.

As soon as the light came on they would start flying around it, circling it in widening and narrowing circles. Looking for an opening to strike. When the light was off again they would send their kamikaze fighters to crash into me as I was trying to hide. There was nothing I could do, they were too many.

I decided to beat them at their own game, they will not outwit me with their mind games. I will prepare a trap for them! I opened a window, and lured them out with the porch light. As soon as they got out I would shut the window and turn off the light.

This worked for a while, but they finally figured out my little ruse. Instead of all going at once they would send a scout. If he got trapped they would immediately counter attack, smashing into everything!

Then I tried keeping the window shut all the time. They really didn’t like that. I was sitting in my room one day, minding my own business, when suddenly I was hit in the back of the head. In the middle of the day no less!

I tought maybe i should try and reason with them: “Try to see it my way” I said, “Do I have to keep talking ‘till I can’t go on?”

They circled the lamp to show their agreement, so I continued:

“Think of what I’m saying, We can work it out, and get it straight or say good night”.

They obviously didn’t like the idea of night, as one of them did a flyby as a warning. I figured they must be angry about something. Perhaps because they were only here for a short time. Maybe they feared night time as every night brought them closer to their inevitable demise. I thought it was worth a shot , so i looked them strait in the eyes and in a calm and direct manner I told them:

“life is very short, and there’s no time for fussing and fighting my friend”.

This has to stop”. I was shocked! They can talk! Moths can talk!

“what do you mean” I said hesitantly.

It’s bordering on copyright infringement”.

“huh?” I was baffled.

The Beatles song. Listen, we’re from the RIAA.

“The RIAA??”

We are here to monitor file-sharing activity.

“Shouldn’t you be monitor internet traffic then?” For some reason this seemed like the proper response.

We tried that for a while, but they told us we should get out more, do some field work

“Field work?” this was getting stranger by the minuet.

Packet sniffing”.

“Packet sniffing?”

We have a very keen sense of smell, we are very small, and we can get into many places. Naturally, we are the best candidates for the job”. They sounded very proud.

"I see." i really didn't. "Well, why here then?"

"We heard reports about music coming from this location"

"Mmmmm... ok, But music is not illegal right?"

"You are replicating Copyrighted materials"

"No i am not, i am just listening to music!"

"So you admit it! The analog replication of digital music is prohibited under copyright law"

"But..But.....um...I am pretty sure listening to music is protected under fair use"

"Many do. They are wrong."

"So you're saying i am not allowed to listen to music?"

"Under U.S Copyright law making ten copies or more is considered a felony"

"So i can listen to a song ten times?"

"Technically nine, ten would be a felony."

"And this doesn't seem ridiculous to you?"

"We are talking Moths working for the RIAA, what do you think?"

Tuesday, March 17, 2009

On the importance of Garbage Collection

Update (21/10/2011):
It's been more then 2 years and it seems Infragistics have done nothing about this. They made a very idiotic design decision to sacrifice a fundamental behavior of managed code and then insist on not fixing it. Reader Jarrett posted an update that extends the fix below for win7 and Infragistics v10.3 and possibly 11.1 - I've added it to the code below.
Thanks Jarret!

---------

About two years ago we found a nice UI package for WinForms called NetAdvantage by infragistics.
A very nice pack, lots of useful controls and not too expensive. Maybe a bit slow, but this is not a problem in most applications.

For a while all was good and well, we built our application and our clients were happy.
Then one day - disaster!
Our application started crashing!
This was after a rather long development cycle where we added support for many new features in the hardware (this was a management application for specialized hardware).
Worse yet, we only started noticing it in QA. The reason was that it only happened after sending configuration to the hardware about 10-15 times without restarting the app - something we almost never do in dev.

Well, when your app crashes after repeated anything its very natural to suspect a memory leak. So i carefully watched memory consumption while calling send configuration. Memory consumption was increasing on task manager, but this is to be expected in managed environments (the simple explanation is that new memory is allocated as long as possible before old memory is reacquired. the actual explanation is not very simple :) ) . Since the machine had 2 gigs of memory and the app only grew from about 150 MB to 200 MB before crashing i figured it was something else.

What i did notice during my exhilarating time with Task Manager was that User Objects were growing rapidly. Being originally of the java persuasion i was unfamiliar with these User Objects. Turns out it was to do with windows handles and the silly way win32 api does UI.
It also turns out that windows has a limit of about 10,000 open handles. That seemed like a lot to me and i didn't understand how we could even approach this limit so fast. Sure, we have a lot of complex UI elements, but still - firefox was no.2 in the object count on my machine and only had 600 handles. Our app had~3,000 just after startup. This didn't seem likely.

The thing was handle leak and memory leak were very similar under managed environment. we used the excellent dot Tracer to locate the source of our leak. After a few hours staring at rather complicated object graphs it turned out that the leak came from...well...i guess my opening was a dead giveaway... - Infragistics Controls!

Anyone who is a developer in a managed environment is well aware of the crimes associated with keeping references to One's object when they have been removed from scope. It's very easy to do it by accident. a Hashmap that wasn't cleared correctly, an errant thread that keeps holding your objects or misunderstood relationships with event handler. All these and more were explored during my search for the leak. All these were not the case with Infragistics.

No - they did it on purpose.
Huh? you say. How, or why, would anyone do this on purpose?
The short answer is "i don't know". The longer answer is that they wanted a mechanism that will allow them to change the look and feel if the user changed the windows theme while the program was running. To do that they hooked into some theme change events and maintained links to every control. The short answer still holds tho , because its a really bad excuse. As i pointed out to Infragistics, you can easily use WeakReference to completely solve this problem.

During this ordeal i was talking to Mr. Vince McDonald, the manager of dev support at Infragistics. it took me a very long time and many lengthy emails and an almost religious debate until i finally got him to admit it was indeed a design flaw. He informed me that "..we will not be able to apply any changesfor it as part of a hotfix" as "..any such changes would have a very high chance to destabilize our current systems". he also promised that "..changes we may make can only safely be done as part of a volume release".
Well, this sounded reasonable to me so i decided to wait with this post. However 3 volumes have been released since my original conversation with him and the problem has not been fixed.

Despite a complete lack of support from Infragistics, we were finally able to resolve the issue ourselves. We had to use a rather nasty trick to bypass their mechanisms.
Basically we reflected their objects and forcefully cleaned all the references.
The code to resolve the problem is posted below.
Important note - This fix was prepared for v7.3 and may work with 10.3 (Thanks Jarrett) I dont know if it will work for any other version. I Suspect it might, and i would appreciate it if you tried it on a different version and it worked for you.


using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Infragistics.Win;
using System.Reflection;
using Infragistics.Win.AppStyling;
using System.Diagnostics;
using Snoops.UI;
using System.Collections.Specialized;
using System.Collections;

namespace CleaningServices
{

///  IMOPORTANT NOTICE:
///  THIS HACK WORKS ONLY WITH Infragistics V7.3
///  AND POSSIBLY 10.3 (Thanks Jarrett)
///  IT WAS CREATED FOR THIS VERSION ONLY.
///  IF IT WORKS WITH ANY OTHER VERSION, ITS BY CHANCE ALONE.
///
///
/// <summary>
///  ReleaserControl is a special control designed to rid our code of the ugliness introduced by using the Infragistics UI Package.
///  Unfortunately someone in Infragistics made the "Design Descision" (according to their support personal) to turn all their UI objects into unmanaged object.
///  They acheived this by strong binding every control to static events held by static classes deep within the infrastructure.
///  As a result, if a UI class holds an infragistics control within it's Controls list, it will never get garbage collected.
///  Infragistics controls NEVER get garbage collected, unless Dispose is explicitly called on the control.(the Dispose method releases the even bind).
///
///  WTF??? you say, well, yes. since every control holds a strong reference to Parent, and the control itself is held
///  by a static event handler, your controls will not get collected when they get out of scope, if they hold an infragistics control.
///  this will naturally cause a memory leak. this in itself is not the worst of it. since all controls hold a Windows Handle,
///  your app will crash with the lovely "Cannot Create Window Handle" exception somewhere around 10,000 objects.
///
///  So, how did we solve this problem? well, we didnt REALLY solve it. we did a hack.
///  this seems to work for our current usage of the package, and i did not notice any unexpected behavior in the UI controls.
///  the limitation of this fix is that it was created for the Infragistics package v7.3 and might not work for any other version.
///  that's the way hacks go i'm afraid..
///
///  What does our hack hack do? well, it forces unregistration of infragistics controls from all the static places we could find them binding to.
///  calling the InfragisticsCleaner.ClearEventBinding(); causes all events for all controls to be unregistered, allowing them to get GCed as they should.
///  the price we pay is that some windows events will not be handled this way,(like changing themes) , but we are willing to live with that.
///  There might be other implications..we dont know.
///
///  for ease of use we added the ReleaserControl that extends UserControl. all it does is add an event handler
///  which calls the InfragisticsCleaner.ClearEventBinding(); method whenever a control is added.
///  extend this class in your user control to allow your controls to get GCed again.
///
///  a once in a while thread calling the ClearEventBinding method would probably work just as well, but it might not get called
///  exactly when you need it...
///
/// </summary>

public class ReleaserControl : UserControl
{
public ReleaserControl() : base()
{
this.ControlAdded += new ControlEventHandler(ReleaserControl_ControlAdded);
}
void ReleaserControl_ControlAdded(object sender, ControlEventArgs e)
{
InfragisticsCleaner.ClearEventBinding();
}
};
public class InfragisticsCleaner
{
private static StaticPropertyHolder[] properyHolders = new StaticPropertyHolder[]
{
new StaticPropertyHolder(typeof(StyleManager), "styleChangedDelegate", "StyleChanged"),
new StaticPropertyHolder(typeof(Office2007ColorTable), "colorSchemeChanged", "ColorSchemeChanged"),
new StaticPropertyHolder(typeof(Office2007ColorSchemeChangedNotifier), "colorSchemeChanged", "ColorSchemeChanged"),
new StaticPropertyHolder(typeof(RoleSelectionUI),"queryComponentRoleDelegate","QueryComponentRole"),
new StaticPropertyHolder(typeof(XPThemes), "themeChangedDelegate", "ThemeChanged") 
};

public static void ClearEventBinding()
{
foreach (StaticPropertyHolder holder in properyHolders)
holder.ClearEvents();
AcessibleTextManagerCleaner.CleanDictionaries();
}

class AcessibleTextManagerCleaner
{
ListDictionary[] dictionaries;
static AcessibleTextManagerCleaner cleaner;
//initialize the static cleaner instance.
static AcessibleTextManagerCleaner()
{
String[] propertNames = new String[]{ "SubclassList", "ControlList", "EditorList" };
cleaner = new AcessibleTextManagerCleaner(GetAccesibleTextManagerType(), propertNames);
}
public static void CleanDictionaries()
{
foreach (ListDictionary dictionary in cleaner.dictionaries)
dictionary.Clear();
}
private AcessibleTextManagerCleaner(Type accessibleTextManagerType, String[] dictionaryPropertyNames)
{
//retrieve the singleton instance.
PropertyInfo instanceField = accessibleTextManagerType.GetProperty("Instance", BindingFlags.NonPublic | BindingFlags.Static);
object instance = instanceField.GetValue(null, new Object[0]);
//get the properties
dictionaries = new ListDictionary[dictionaryPropertyNames.Length];
for (int i = 0; i < dictionaryPropertyNames.Length; i++)
dictionaries[i] = ReflectListDictionary(dictionaryPropertyNames[i], instance, accessibleTextManagerType);
}
//get the dictionaries to clear.
private static ListDictionary ReflectListDictionary(String propertyName, Object instance,Type type)
{
PropertyInfo instanceField = type.GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance);
ListDictionary list = (ListDictionary)instanceField.GetValue(instance, new Object[0]);
return list;
}

private static Type GetAccesibleTextManagerType()
{
//we need the infragistics assembly that holds our type (its a private type so we cant access it directly)
Assembly infragisticsAssm = Assembly.GetAssembly(typeof(EditorWithMask));
Type[] types = infragisticsAssm.GetTypes();
Type accessibleTextManagerType = null;
//search through the assembly until we get what we want.
foreach (Type t in types)
{
if (t.Name.IndexOf("AccessibleTextManager") != -1)
{
accessibleTextManagerType = t;
break;
}
}
return accessibleTextManagerType;
}

};
class StaticPropertyHolder
{
EventInfo eventInfo;
FieldInfo field;

public StaticPropertyHolder(Type type, String delegateFieldName, String eventName)
{
this.field = type.GetField(delegateFieldName, BindingFlags.Static | BindingFlags.NonPublic);
eventInfo = type.GetEvent(eventName);

}
public void ClearEvents()
{
Delegate eventDelegate = field.GetValue(null) as Delegate;
if (eventDelegate != null)
{
Delegate[] invocationList = eventDelegate.GetInvocationList();
foreach (Delegate del in invocationList)
{
eventInfo.RemoveEventHandler(null, del);
}
}

}

};


};
}