Droplet - End of Day 2

A quickie progress update and screenshot of my RubyWeekend game, Droplet.


What's working:

  • You can click to make a new plant at the nearest point on the circle.
  • The plants grow a bit when you press spacebar.
  • The plants grow and create new branches based on rules.

What's not:

  • The plants are ignoring their color rules.
  • The plants are “leaning”.
  • The plants are jaggy and slow to draw (when complex). I'll probably have to stop using Gamebox's “thick line” method (draw_line_s), and either use regular lines (maybe antialiased) or roll my own code to draw branches. OpenGL would be really nice right now…
  • The plant rules are a bit simplistic and rigid.
  • No sound yet.

The contest period is nearly half over (39:30 hours left as of this writing). I'm going to try to fix the color and leaning issues, then head to bed. The focus tomorrow will be on sound/music.

Update 03:52: Fixed the color and leaning issues. Both were just stupid little mistakes. Here's an updated screenshot:


Droplet Thoughts (Day 2)

I'm calling my RubyWeekend #3 game “Droplet”. I will not proceed to ramble about it to help my planning. And you get to read the results, you lucky person you!

  • I'm setting aside the animals/people aspect for the competition. It's just going to be about the plants.
  • I'm going to use Garage Band's built-in instruments to create the music sound effects for the game. I am in love with Garage Band.
  • I'll be using Gamebox. It seems pretty cool so far.
  • Since the game takes place on the inside surface of a circle, I'll need to do some trigonometry to calculate the positions and angles of plants around that circle. After a bit of thought on this, I've decided I'll make a PivotActor that represents the center of the circle and contains the math code to calculate the positions of plants given an angle, and also calculate the point on the circle nearest to the mouse cursor.

I'll update this post with more thoughts as I have them.

RubyWeekend #3 Game Concept

RubyWeekend #3 kicked off about 8 hours ago, and I've been pondering game ideas since then. The theme is “A Tiny World”. I was having trouble coming up with something, but I think I've finally got a solid base for a game. It's still a bit vague, and I haven't figured out how I'll turn it into a proper game, with an objective and challenge and such. Right now it's just kind of a neat idea for a toy. (Which, to be honest, I find more interesting to create, but I should at least try to make it somewhat game-ish for the competition.)

Continue reading “RubyWeekend #3 Game Concept”

99% Pure Functional Programming

In my recent adventures in Haskell and Scheme, I was immersed in the concept of functional programming. Haskell in particular has a strong relation with the notion of pure functions, i.e. functions without side effects. A pure function does nothing except calculate and return some value based on the input parameters.

I like pure functions, and I try to write them where I can. But Haskell is billed as a “purely functional programming language”. This perplexed me. How could there be an entire programming language that was purely functional? Or, rather, how could you use such a language to actually do anything useful?

Continue reading “99% Pure Functional Programming”

Fun (and not-so-fun) with Haskell and Scheme

Lately I've been poking around at some new-to-me programming languages, Haskell and Scheme. I don't expect to use either of them in a serious, practal project (except maybe Scheme for scripting GIMP), but they are both “weird” enough that it's fun to learn them and expand my horizons.

Continue reading “Fun (and not-so-fun) with Haskell and Scheme”

Git tip: Fix a mistake in a previous commit

Here's a handy tip that shows off one of the little conveniences that makes me love Git.

In Subversion, if you made a mistake in one of your commits — too bad. At best, you might be able to edit the revision log, if your repository was configured to allow that (Sourceforge repositories aren't).

In Git, as long as you haven't pushed upstream yet, it's trivial to change the commit log, or even the actual commit contents!

Continue reading “Git tip: Fix a mistake in a previous commit”

Revision numbers considered harmful

When using Subversion for vertion control, I was always conscious of revision numbers when committing. It was as if there was a limited supply of revision numbers, and I didn't want to waste them making tiny commits. So, I'd often bend over backwards to make sure the change was significant enough to be “commit-worthy”.

It's an awful habit, to be sure, but I know I'm not the only one. I recently had one of the programmers I manage (a very bright kid, if still a bit green) apologize to me for committing 20 revisions in a single day, as if it was wasteful or inconsiderate to make frequent commits! I think you become less concerned about “wasting” commits as you get more experienced, but it was still always in the back of my mind.

Not so with Git. The reason is simple: Git doesn't use incremental revision numbers. Instead, it uses a long string of digits and letters which is totally meaningless to a human being. (Getting technical, it's based on a SHA1 hash of this commit and previous commit(s), or some such thing. But it's non-obvious to a human what the connection between 2499051dca30def85f5433c08519adea56a12a14 and its parent aaaa83fc4e9737b41a5c52b16e946b34dab63ede is.)

Since the commit identifier is totally meaningless to me, I don't pay attention to it (except in the rare cases where I need it, such as checking the diff for that commit). And because it's not a number that gets larger the more I commit, I don't feel like I'm “wasting” numbers by commiting often — sometimes several times per minute.

Yet another way Git and other distributed version control systems assuage our obsessive-compulsive tendencies and promote good habits.

Migrating projects to Git

I've been using Git for a few weeks now, and it is friggin awesome. It is both the bees knees and the cat's pajamas. I love the local commits, the branching, the stashing, the lightweightness of it. It has improved my workflow a lot. I'm not afraid to make lots of small commits anymore, because I'm doing everything in branches (so I don't mess up ‘trunk’), and I'm doing it locally (so no one would even notice if I messed up ‘trunk’, anyway).

So now, I want to use it for all my personal projects! The trouble is, they're all in a Subversion repository. That is, one Subversion repository, with a dozen or so projects in it. Eep! Fortunately, it's a piece of cake to migrate specific directories from a Subversion repository, into their own Git repositories! You don't have to migrate the whole thing and then trim it down, which is what I worried I might have to do.

I followed Jon Maddox's invaluable guide, and it worked like a charm. You can even convert the Subversion user names to Git's name & email style. Joy!

Now the only trick is to set up public access to the repositories that I want. I'm on shared hosting, so I fear that git-daemon is infeasible, and I don't feel like putting every little project up on Github. I'll probably have to fall back on HTTP access, which I hear is considerably slower. Ah well, such is life.

P.S. Yes, I'll probably migrate + Githubbify Rubygame eventually, but there are a number of issues to sort out first.

Snippet: Hash#with_only, #merge_existing

Here are some potentiall useful one-liner methods for extracting and merging only parts of Hashes. I was surprised to find out that Hash didn't already have built-in methods to do these things. Maybe they're considered so obvious that they don't need to be built-in, but I think the readability gain is worth it.

class Hash

  # Return a copy of the receiver with only the given keys.
  #   >> {:a => 1, :b => 2, :c => 3}.with_only(:a, :c)
  #   => {:a => 1, :c => 3}
  def with_only( *keys )
    reject { |k,v| not keys.include?(k) }

  # Return a copy of the receiver without the given keys.
  #   >> {:a => 1, :b => 2, :c => 3}.without(:a, :c)
  #   => {:b => 2}
  def without( *keys )
    reject { |k,v| keys.include?(k) }

  # Like #merge, but only accepts keys that the receiver already has.
  #   >> {:a => 1, :b => 2}.merge_existing({:a => 0, :c => 0})
  #   => {:a => 0, :b => 2}
  def merge_existing( other )
    merge( other.with_only(*self.keys) )

  # Like #merge_existing, but modifies the receiver.
  def merge_existing!( other )
    merge!( other.with_only(*self.keys) )

  alias :update_existing :merge_existing!


Snippet: Range#compare

Here's a little idea that popped into my head for enhancing the Range class in Ruby:

class Range
  def compare( value )
    if member?( value )
    elsif value <= self.begin
    elsif value >= self.end

Then you can perform broad comparisons, like so:

def try_compare( x, r=(1..10) )
  case r.compare x
  when -1
    "#{x} is below the range #{r}"
  when 1
    "#{x} is above the range #{r}"
  when 0
    "#{x} is inside the range #{r}"


>> try_compare( 3 )
"3 is inside the range 1..10"
>> try_compare( -1 )
"-1 is below the range 1..10"
>> try_compare( 11 )
"11 is above the range 1..10"

I haven't decided whether this is useful, or just daft.