iFreeCell 1.1

May 9, 2010

Just submitted an updated version of iFreeCell.

Changes include:

  • High scores: iFreeCell now keeps track of previous scores and can sort them by number of moves or game duration.
  • Accelerated all card animations (except dealing, which was ok) by a factor 2: previous animations was just too slow
  • Minor UI fixes, the deck in portrait is now (more or less) centered.

I’m now waiting for Steve’s blessing, app approval took 2 days last time, so I’m guessing it shouldn’t be any longer.

Next changes should include:

  • Minor tweak letting player take advantage of multiple empty foundations when moving big columns. Say player wants to move 7 cards, has 3 empty cells and 2 empty foundations. Currently, you have to move 4 cards to the first empty foundation, then the remaining 3 to the other foundation and move the first 4 on the last 3. Even it’s technically accurate, it’s not what I would call the best user experience (as my girlfriend keeps repeating each she wishes she could do it).
  • Solitaire. This is going to be a big one, and will most likely require re architecting the applications. Indeed, the game has been written kind of quick (I wanted out the door early), and even though I’ve made a clean up pass on it, the API is still very “free cell”-ish instead of “card game”-ish. Plus this will require adding a bunch of things, a navigation controller, flippable cards and some artwork (I guess that’s going to be the tough part… :D). So I might very well break it down in 2 updates. Meh. Whatever. It’s not like I have 10 000 users anyway… So far, two. And they didn’t pay for it 😉

Edit:

Ok, so the update was refused. Considering how I implemented the high score UI, nothing shocking actually, I should have been expecting it… Funny thing is I have around 150 customers. Somehow unexpected.
Anyway, I should hopefully submit another update by the end of the day, with a correct High Score implementation, a fix for the random  crash (my bad, I forgot a retain statement….) and most likely the minor tweak mentioned above. Oh yeah, and fix that lousy icon I have on the app store.

I’m aiming to get the update out for the european release of the iPad, hoping I’ll get a sales boost.

Advertisements

Thoughts about flash

May 7, 2010

Given the recent events surround flash, I just felt like expressing a few ideas on flash (or mostly flex, since that’s what I know well). I’m not Steve Jobs, so don’t expect anything ground breaking here.

For those who have been living in a cave the last 2 months, let’s sum it up:

  • Apple products don’t support flash. Some (including me) hoped that the flash player would show up on the iPad.
  • Instead of that, Jobs issued an open letter on flash, explaining why it’s a piece of shit on apple platforms
  • Recently, Microsoft issued the same kind of statements. Wrapped in corporate speech, but still. We should get them a reality distorsion field like Jobs’ for christmas, they could use it 🙂
  • Google acquired On2 and it is suspected they might start competing with Adobe on the web video player (flash main reason of success for the last 10 years)
  • The whole content industry seems to be tired of having to support flash, realized it could skip Adobe with the iphone and seems willing to do that for desktops too now that HTML5 is out there and that MS announced full support with IE9.

Adobe could have worked out those issues had they reacted correctly and some time ago.
How?
Well, for a starter, fixing the performance issues of the Flash player would have been a good start. And I’m not talking about the access to hardware acceleration for video playback. I’m talking about general performance.

For example, I’ve been playing with flex effects recently, I was trying to get a slide transition for the view stack, something simple, like the iPhone does when you’re swiping through your application pages.
Well, the iphone does this smoothly, on an small arm processor and very little RAM. Same thing for the iPad on 1024*768 resolution. Windows Flash player renders this just correctly on a core2duo 2.5GHz, for a movie around 800*600, with around 60% of the cpu used. It’s choppy on the mac flash player, same kind of horsepower… After testing, flash player on the latest imac 3GHz core2duo runs slower than the windows version on a  … P4 2GHz… T’oh! Oh, and it took me 4 days of experimenting pretty much everything and optimizing the thing to get it running half decently….

Or something else, really stupid: make the flash player multi threaded, god damnit. I’m sick of my UI freezing up because an event processing is heavy on CPU. Or just because my ResultHandler is processing 40KB of AMF3. I don’t care if there’s no multithread API, I just want the flash player not to freeze on something stupid… I’m tired of seeing my CPU monitor going crazy all day long.

Some might argue that the flash player is a plugin, so it can’t run decently. The AIR player has the same issues, and it’s a regular application, so I guess the problem is deeper than that.
And when you see how Adobe has been struggling to release flash products recently (flex4 had over a year delay, we’ve been hearing about player 10.1 for more than a year now, Catalyst is still beta), I’m not sure they will be able to pull that kind of magic.

Open sourcing the flash player could have helped. It did great for the JVM, and even if they wouldn’t have had any contributions (the product is so complex I doubt they would ever have had anything actually), it would at the very least calmed down the open source community who is eager to see flash die. We could have had better browser integration, and hopefully see fixes for the security issues.
But unfortunately, it’s a process that will take them years to accomplish (it took sun something like 18 months to open source the jdk + JVM), so even if they do it know, flash might very well be dead (or confined to advertisement) by the time it is open sourced.

But no, I don’t think that’s going to happen. I’ve lost faith in Adobe. They’re moving slowly. Way too slowly for a company getting hammered by Apple on the mobile space, Google with it’s blazing fast V8 and soon Microsoft with IE9.

Jobs utterly hates Flash and Apple has proven that a web without flash is possible.
Microsoft is saying in substance “We asked Ballmer to write an open letter with his thoughts on flash, it ended up in a pile of broken chairs in his office. We don’t really like it, but since our clients (or at least some of them) still want it, we can’t say openly what’s our thoughts on it. Sorry about that adobe, we’ll give you a hand until IE9 is out and takes over IE8/7, after that, uh… Farewell, so long, and thanks for all the fish!”

It was fun while it lasted. It’s a shame a good framework like Flex is dying due to poor VM performance and lack of openness from its creator. I’ve had fun writing flex code, but I guess those days are over. Tired of struggling to get halfway decent performances.

Back to J2EE and Cocoa now.

MediaInfo Cocoa sources available

May 3, 2010

I’ve just moved my SVN from my local machine to the google project’s. You’ll find two projects in there, one for the library, the other for the UI.

Open them in XCode, build Lib first, GUI next and you should be good to go.

I’ve also uploaded an RC1 to the downloads page.

We’re getting closer to a release, still working out a few details with Jerome from MediaInfo though.

iFreeCell

April 20, 2010

I just submitted iFreeCell to the AppStore. Yay!!!
My first iPad app, hopefully soon on the store. 1 buck, cheap!
My main concern is the name of the game though, I just hope apple won’t be too hung up on the iSomething kind of name. Anyway, not much I can do now except wait and think about a plan B in case it goes pear shaped.

Edit: forgot the screen shots…

Flexlib 2.5 is out!

March 28, 2010

I’ve just released the new flexlib 2.5, that comes with flex4 support.

Yay!

The major change in this release is the flex4 compatibility, I’ve sneaked in one or two patches for known bugs, but nothing worth noting.

Now the long work of fixing all known issues in the bug tracker can start.

http://code.google.com/p/flexlib/

Enjoy!

Flexlib and flex4

March 21, 2010

It works!

Still a few issues are left, nothing tough to fix.

Checkout the project homepage http://code.google.com/p/flexlib/

A new swc should be released soon (I guess as soon as the few broken components get fixed), for now you’ll have to do a fresh subversion checkout to get the flex4  compatibility.

Enjoy!

Edit: It didn’t work for long, released flash builder comes with a few api changes that break the current codebase. Expect those to be fixed by this evening. Hopefully.

Eclipse MacOS and line numbers

March 21, 2010

Just figured this thing out at work the other.

Eclipse ganymed (and galileo too if I got it right) has a weird bug on mac when running it on an secondary monitor: line numbers, breakpoints and pretty much anything that shows up in the gutter do not show up. Annoying.

The bug is apparently in the carbon version of SWT. Seems to be fixed in 3.6, but flex developers won’t care about that, since flex/flash builder only runs on ganymede.

Hopefully, some guy here http://www.quilix.com/node/75 “backported” the patch from 3.6 to galileo and ganymede. Apparently, he just extracted the relevant .class from the JFace jar and included them in ganymede/galileo’s jars, in the plugin folder. The guy is so kind, he evens provides the patched jars. Yay.

I’ve been using his patch for about 2 weeks now, didn’t notice any major issue. I just had to restart eclipse once, no big deal.

Hopefully, someday, flash builder will run on 3.5+. I’d love to use the cocoa version of eclipse. Someday. After flex4 gets released.

Flex tech articles: DataCollection

March 4, 2010

Okay, so I’ve decided to start my series of articles with the data collection.

If you’ve worked with LCDS, then you’re familiar with the concept: client side fetches an ArrayCollection from the server, user interacts with it, clicks on submit and the client sends the updated data back to the server. Not the complete collection, only updates.
In case you’re dealing with big collections of massive objects, you might not want to send all the collection up the wire, but only the changes
The reasons are pretty obvious:

  • Network performance. AMF3 is efficient, but if you’re dealing with a few thousand users sending up data that is for 95% noise, well you got room for improvement here. Let’s not even mention xml transfer…
  • Server CPU ressource.  Even though BlazeDS/LCDS does a really great job at serializing/marshalling data, you still have some overhead marshalling your objects. Instantiating objects is never cheap on CPU, sucks up memory and gives the GC more work. Just like the network issue: with a loaded service, you got a lot of room for improvment here.
  • Server code maintainability: if it gets the raw collection, the server will have to figure by himself what has been updated. This will translate in a bunch of database select to get the original object back from the data layer (hopefully from the ORM cache, though), turning those SQLs into Objects (more allocations) and eventually, a big chunk of boiler plate code, comparing existing with the new one. Only then can you get to you business logic.

All this work, for what? Finding that you have to delete one object? Boy, that’s a lot of useless work here…
Wouldn’t you like to only send up the updates?

You could try to do this manually. Not sure you want to open that can of worms.
You’ll have to let UI manage its own collection of deletes/updates/adds, group all of those together and send it back to the server. It could be hard to do depending on the UI, your code is not necessarily reusable. But, knowing flex’s propertyChange and collectionChange events, you could automate everything.

What’s the idea here?
Pretty simple. ArrayCollection is a clever class that dispatches events whenever it is updated (add, remove, update, sort etc.). Well, the idea then is to simply listen to those events and build up automatically a list of updates.

Let’s start with the base, we’re going to need a class to store each individual change. Let’s call it ChangeObject.

This class is merely a placeholder: instance of the changed object, it’s status (added, deleted, updated) and a list of the properties updated.
That’s pretty simple, it would look like this:

public class ChangeObject extends EventDispatcher
{
  public static const DELETED:int = 0;
  public static const UPDATED:int = 1;
  public static const ADDED:int = 2;
  public var status:int;
  public var oldVersion:Object;
  public var newVersion:Object;
  public var changedPropertyNames:ArrayCollection = new ArrayCollection();
  public function ChangeObject() 
  {
  } 

  public function isAdded():Boolean
  {
    return newVersion != null && oldVersion == null;
  }

  public function isRemoved():Boolean
  {
    return oldVersion != null && newVersion == null;
  }

  public function isUpdated():Boolean
  {
    return oldVersion != null && newVersion != null;
  }
}

Allright. That was the simple part. Now we want a collection that can create those. Let’s just create a subclass of ArrayCollection and make it encapsulate all the cleverness we need. Everything is encapsulated and since DataCollection is a subclass of ArrayCollection, we can treat it just like a regular collection.
The DataCollection should be listening to itself, for collectionChange events. Those events are pretty damn useful, they tell the nature of the change, the object that’s been updated, and the property that’s been updated (if relevant). Check out CollectionEvent asdocs for more details.
Well, as soon as we trap those events, we’re almost done: we know what has happened and to whom. We’re just left with some ChangeObject creation.
What we have so far in our DataCollection:

public class DataCollection extends ArrayCollection implements IExternalizable
{
  private var _changes:ArrayCollection;
  public function get changes():ArrayCollection
  {
    return _changes;
  }
  public function set changes(value:ArrayCollection):void
  {
    _changes = value;
    if (changes != null)
    {
      _changes.sort = new Sort();
      _changes.sort.fields = [new SortField("status", false, false, true)];
    }
  }
  public function DataCollection(source:Array=null)
  {
    super(source);
    changes = new ArrayCollection();
  }
}

A simple extension of array collection, with an extra attribute holding the changes.
Notice the sort: this will sort changes: deletes first, then updates, then adds. Our server will like this order, because it’s the order that will prevent us from database contraint violation. Indeed, this server will want to process updates in this order, otherwise you might run into some DB constraint violation. For example if the user removed an object, then created another one that is the same, according to business logic. If you have a unique constraint for that column in your table, you must delete the old one first, then create the new one. The same applies for updates and adds.
Also, notice the IExternlizable interface. It is required, we’ll see why later.

Now that we have basic infrastructure, how do we create those objects?
Easy!
Whenever a collection change event comes in, check the kind (event.kind, an “enum”).
For adds:

  • Search in changes for a ChangeObject that has the current object as a “delete”: it means the user has removed the object from the collection, then has put it back in. That results in no logical change on the collection. We will then have to remove that “delete” change object from the list of changes.
  • If we can’t find this ChangeObject, the object is really new, we just have to instantiate the ChangeObject, set the relevant fields and add it to the changes collection.

For deletes:

  • Just like adds, we are first going to look for existing “add” changes objects. If we find one, the object has been added, then deleted: no logical change. We just remove the object from the changes list.
  • Otherwise, the object has really been deleted. Create the change object etc.

For updates:

  • Create our change object if it doesn’t already exist and mark it as “updated”. If the ChangeObject already existed, don’t change the status to “updated”. Indeed, if it was added, the change is still a logical “add” to the collection. Indeed, the server doesn’t know about this object yet, and could not care less that the user created it, then updated. We just want to treat this as a new object.

And that’s it! The code looks like this:

switch (event.kind)
{
  case CollectionEventKind.ADD:
  for each (var addedObj:Object in event.items)
  {
    // look for existing change Object
    var addCO:ChangeObject = getChangeObject(addedObj);
    if (addCO == null)
    {
      // not found, hence create it and add it to changes list
      addCO = new ChangeObject();
      addCO.oldVersion = null;
      changes.addItem(addCO);
    }
    else
    {
      // object was previously removed, it is now added again, resulting in no change: remove change object
      if (addCO.status == ChangeObject.DELETED)
      {
         removeChangeObject(addCO);
      }
    }
    addCO.status = ChangeObject.ADDED;
    addCO.newVersion = addedObj;
    }
   break;
 case CollectionEventKind.REMOVE:
   for each (var removedObj:Object in event.items)
   {
     var removeCO:ChangeObject = getChangeObject(removedObj);
     if (removeCO == null)
     {
       removeCO = new ChangeObject();
       changes.addItem(removeCO);
     }
     else
     {
       // if object was recently added, removing it results in no change for this object: drop change object
       if (removeCO.status == ChangeObject.ADDED)
       {
         removeChangeObject(removeCO);
       }
     }
     removeCO.oldVersion = removedObj;
     removeCO.status = ChangeObject.DELETED;
     removeCO.newVersion = null;
   }
   break;
 case CollectionEventKind.UPDATE:
   for each (var propertyChangeEvent:PropertyChangeEvent in event.items)
   {
     var updateCO:ChangeObject = getChangeObject(propertyChangeEvent.source);
     if (updateCO == null)
     {
       updateCO = new ChangeObject();
       updateCO.status = ChangeObject.UPDATED;
       changes.addItem(updateCO);
     }
     // keep track of changed properties
     if (!updateCO.changedPropertyNames.contains(propertyChangeEvent.property))
     {
       updateCO.changedPropertyNames.addItem(propertyChangeEvent.property);
     }
     updateCO.changedProperties[propertyChangeEvent.property] = propertyChangeEvent.newValue;
     updateCO.newVersion = propertyChangeEvent.source;
   }
   break;
  }
  changes.refresh();
  dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, "change", changes, changes));
}

Notice the refresh and the event dispatching. Refresh is to keep the changes collection sorted. Event dispatching is because we might be interested in binding to changes, hence the event dispatching to notify listeners that the data has changed.

Any call to addItem or removeItem will be caught by the collection. Any changes to a bindable object will dispatch a propertyChangeEvent, get caught by the collection which will translate it to a collectionChange event.
We can even modify a object nested a few levels deep into the collection’s object, as long as the changes bubble, the data collection will catch it.
Sadly, change events don’t bubble by default, so you’ll have to implement the bubbling manually. It’s not complex actually, setting up event listeners and dispatching a new property changeEvent. It’s just tedious and boiler platy. I’ll leave that decision up to you.

Okay, so from a high level, the thing is wrapped up. Now we have to synchronize all this.
In the constructor, hook up the event listener by adding this line:

addEventListener(CollectionEvent.COLLECTION_CHANGE, onCollectionChange);

Let’s not forget sending data up the wire. Remember one of the initial issues: network performance. Let’s just not send everything up the wire. Only the changes.
That’s pretty trivial:

override public function writeExternal(output:IDataOutput):void
{
    output.writeObject(changes);
}

See? Only sending changes 🙂

We’ll need a readExternal also, since AMF is not doing the marshalling automagically:

override public function readExternal(input:IDataInput):void
{ 
  var object:Object = input.readObject();
  this.source = object as Array;
}

As usual, make you java side class symmetrical to the Flex version: that should be pretty trivial and I’ll let you implement it.

One thing, that’s important: our read/writeExternal methods are not symmetrical anymore. That is, we’re not reading and writing the same thing. If network turns out not to be an issue, or just for having decent and maintainable code, we can make this symmetrical and send everything up and down the wire.
We still have the knowledge on the server of what changes were made.
If network is an issue and maintainable code is a requirement (I hope it is…), it’s easily fixable: the controller can send back up only the changes attribute instead of the whole DataCollection for example.

I’ll leave it up to you to add convenience getters on changes, per type or per instance, enabling/disabling change tracking (just unhook the event listener) and that kind of stuff.

One last thing: ever looked at removeAll implementation? You’d think we’d get a removed collectionChange event per remove? Nope! We get only one reset event. Which is described as “Indicates that the collection has changed so drastically that a reset is required.” It won’t tell us what happened. A work around this is fairly easy: override removeAll and make it call removeItemAt(0) until the collection is empty. Or we could go down the complex path and try to make sense out of the reset event. I didn’t do it and favored the “removeItemAt(0)” approach, but feel free to let me know if you’ve done it the “right” way.

That’s it for today. See you soon for the next article.

Flexlib and Flex4

March 3, 2010

Well, it seems like flexlib is finally building against flex4. Good news.

I had to put in some ugly conditional compilation variables due to API changes used by the scheduling part of the library, same with the accordion base since it’s using private mx_internal apis, but for most of it, it was pretty simple.

Some polish on the build scripts, a few more tests and that will reach the main trunk. Yay.

Flexlib, once again

March 1, 2010

Sacrebleu!!!

The french insurrection was a total success!!! Flexlib maintainers should be giving SVN commit access  to a handful of motivated developers. flexlib-reborn is therefore born dead. Haha.

Silly jokes aside, that’s actually very good news, forking the project would actually have been quite painful. Back to coding now…