DroidLife – Conway’s Game of Life for Android

2009/10/27

icon

device-1

Gosper's Glider Gun in progress

I just posted a new Android app to the market: DroidLife, an implementation of Conway’s Game of Life. CGoL is a simulation (zero-player game) of cellular life (don’t confuse it with Milton Bradley’s Game of Life, a board game). The app bundles many interesting seeds, and allows users to download thousands of others and run them as well. Seeds are just initial simulation states, and more specifically are simply a set of one or more points on a grid representing live cells. There are around 4 “standard” seed file formats. DroidLife understands the most common / simple of those, Life 1.06. The most complete repository of seed files can be found on LifeWiki.

I was initially motivated to write this app as it was the topic of an interview question, for which I was only able to give a mediocre answer. One thing is for sure, if anyone ever asks me about CGoL again in my life, I have enough information to bore them for hours. I also saw it as a chance to get my feet wet with some trivial graphics on Android. Credit to “MrSnowFlake” for putting together this game template (bump) thread, based on Android’s Lunar Lander sample, which helped me get started. Without it my ramp up time would have been much greater.

Depending on my time, here are a few things I’d like to add to the app,

  1. Read other file formats: RLE, PlainText, Life 1.05
  2. Save game state to file
  3. Seed editor: define you own seeds
device-2

A b1s12 world seeded with a single cell

Advertisements

httpmon – HTTP Server Monitor

2009/10/23

icon

device-1I just published a new application to the Android Market: httpmon. In a nutshell, it allows you to monitor the status of any number of HTTP servers. A monitor is made up of 1) a request which describes how to contact the server, 2) one or more conditions that must hold true to consider the server “valid”, and 3) zero or more actions to take if the server is “invalid”.

This was another learning exercise. I wanted to play around with how I would structure an extensible object model in Android. The app source is structured so that the conditions and action class trees are easily extensible at both the model and view level to add new types of conditions and actions. I’m quite happy with how well it came out in that regard. None of this is probably visible from using the app however.

I hope that at least some people find this useful, as I’m looking forward to receiving input for new types of conditions and actions.

Supported conditions,

  • ping
  • response time
  • response code
  • content contains (substring, wildcard, or regex match)
  • header container (substring, wildcard, or regex match)

Supported actions,

  • notification (alert sound, flash, and / or vibrate)
  • send SMS

I wanted to have a “send email” action, but it turns out that there is no way to send an email programmatically, on behalf of the user, with Android. I am not sure why they would let an app send an SMS on behalf of the user, but not an email. An SMS seems more dangerous actually. Of course, I could have used JavaMail, but that means gathering an SMTP server and port, and supporting credentials. Most users will lack the will or the way to set that up I think.


Intercepting BACK in an Activity

2009/10/23

I couldn’t find anything good explaining this, so I’ll post here. The pattern is that you have a parent activity that lists objects, and a sub activity that allows editing those objects. If the user hits the BACK key, we want to save their work and pass it back to the parent activity. All you need to do is override Activity.onKeyDown() as such,

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
  if (keyCode == KeyEvent.KEYCODE_BACK) {
    if (save()) {
      return super.onKeyDown(keyCode, event);
    } else {
      return false;
    }
  }
  return super.onKeyDown(keyCode, event);
}

The semantics are that if you return true, then the normal flow of the BACK key continues. Here, we call super.onKeyDown() to let the default implementation process the key press as it normally would by calling super.onKeyDown() instead of just returning true directly. If you return false, then the flow stops, and the back key is canceled. In the code above, save() might implement some logic to validate the data, and set up to return a value to the parent activity by calling setResult() with an intent,

private boolean save() {
  if (validate()) {
    Intent intent = new Intent();
    intent.putExtra("org.jtb.some.data", mData);
    setResult(Activity.RESULT_OK, intent);
    return true;
  }
  return false;
}

Android Market and the Developer Problem

2009/10/18

Android market has a lot of serious problems (that were not fixed in donut), but I want to focus on just one here: the lack of connection between the developer and application users.

Users can interact with the developer in 3 ways: by rating the app, by leaving comments, and by emailing them directly. The comment / rating system is completely anonymous, there is no way for the developer to interact with users that leave comments and feedback.

Why is it important for a developer to be able to interact with a user? Most Android apps are not published by large scale software producing companies. In most cases it’s one person, without a team of testers ensuring the application’s correctness across many different devices and several different Android OS releases. Developers rely on user feedback to find and fix problems with their apps. It is nice when users use the developer’s email to report problems, but more often than not the developer gets comments like “force closed, uninstalled” with no way to get any details from the user.

This problem can be fixed, with some rather harsh stipulations applied to market downloads. When a user downloads an app, they should implicitly agree to open a communication channel with the developer. Specifically, a “receipt” should be provided to the developer for every download (free or paid). This receipt should include details of the user … including their email, device info, date installed, date uninstalled, etc. If the user doesn’t like this, they can choose to not download the (free) application.

I suspect most people would object to this with privacy concerns, but to that I say too bad. Free software should never be truly free. Instead, “free” software just means you may compensate developers with non-monetary forms of payment, such as,

  1. Providing feedback on features, usability.
  2. Sending crash logs.
  3. Or even, fixing bugs directly.

If the user is truly leaching in that they aren’t willing to provide any of the above, it’s of no consequence to the app developer if they decide not to run the app. It’s a frustrating experience for developers to work hard on an app and publish it, for free, only to receive negative, or vague comments. A developer-friendly market stimulates more application development, which is benefits users in the long run.

This all goes for free apps. For paid, or ad-supported apps, I believe it is up to the developer to provide some level of correctness without user involvement.


Reverse a Linked List, Java

2009/10/09

Reviewing for interview questions, I ran across this. Most solutions you’ll find are in C, and that can be easily adapted … however, the C-ness sometimes gets in the way of spotting the subtleties. Here is the function in Java,

static void Node reverse(Node head) {
Node current = head;
Node newHead = null;
while (current != null) {
Node tmp = current;
current = current.next;
tmp.next = newHead;
newHead = tmp;
}
return newHead;
}

So how does it work? In a nutshell, we always have 2 lists: 1) the remaining portion of the original list pointed to by current, and 2) the new list pointed to by newHead. Each iteration strips the head element from the original list, and adds it to the head of the new list.

  • line 5 saves the current loop pointer, this will be our new head at the end of each loop.
  • line 6 advances the current loop pointer one past the head, but remember we saved the old current pointer in tmp at line 5.
  • line 7 assigns the next pointer of our new head (tmp) to the previous head pointer. The first time through the loop, this is null, and we’ll have a new list containing one item.
  • line 8 permanently tracks our new head by moving it out of the temporary loop var.

I can’t imagine it gets better than this. No new allocations, and O(n).