codemonkey like you

But seriously.

Jason Morrison left thoughtbot today. I’ll miss him, but I’m sure he’ll have a kickass time in Asia.

I’ll eat a waffle for you, buddy.

My First Game (using Ray, a Ruby DSL)

Ray is a Ruby DSL for creating games that looks totally sweet. This blog post will walk you through how to make a game with it. I just discovered Ray about half an hour ago, so we’ll see how this goes.

First, install the gem’s external dependencies. I’m on OSX, so I do this:

brew install glew libsndfile

Then, I typed in an example program. I find that it’s much more helpful to type stuff in than to copy and paste. It sticks in your mind more. For example, the first time I ran the following program, I left out the require 'rubygems' line and it choked, saying it couldn’t find ray.

require 'rubygems'
require 'ray'

Ray.game 'my game', :size => [800, 800] do
  register { add_hook(:quit, method(:exit!)) }

  scene :some_scene do
    # Exit when q is pressed
    on :key_press, key(:q){ exit! }

    @text = text "Hello world!", :angle => 30, :at => [100, 100], :size => 30
    render do |win|
      # You ask the target to draw each object.
      win.draw @text
    end
  end

I couldn’t think of a game to make, so I turned to Whitacker Blackall’s wonderful and funny post about his first steps in programming and game creation. And then: of course, pong!

These are my initial thoughts on the design, stream-of-consciousness style.

OK, looking at Whitaker’s screenshot, the main visual elements are:

  • 2 paddles (maybe I can make a paddle method so I don’t have to type the same code twice)
  • a ball
  • A score
  • The ability to pause the game, with a status indicator (my first thought is a global hook for the space bar, which I’m 99% sure is possible, since I did it with q)
  • A dashed line going down the middle of the screen
  • A black background with white objects, except for the dashed line, which is gray

Interactivity / Event bindings:

  • Key bindings for the left paddle that move it up & down
  • Key bindings for the right paddle that move it up & down
  • Need to update score when the ball goes past a paddl
  • The ball moves (!) and bounces off paddles (!!!)
  • Need to check for when ball hits the paddle (and rebound it at the correct angle!)
  • Pausing is optional, I’ll do it if I feel like it

First Steps

Let’s make a black background. Yep, that simple. I’m keeping the skeleton I created above, especially the press-q-to-quit binding, because otherwise it’s hard to quit. Turns out Ray has a black background by default, so that’s easy.

Progress so far: https://gist.github.com/1087755

Making the Paddle

Let’s do something a bit harder: make a white oval pong paddle. Looks like Ray::Polygon.ellipse is what I want. Since I know I’m going to have more than one paddle, I’m going to make a paddle method. It’s kind of unclear what the first 3 arguments to ellipse do, but right now I think that the initial array is the size ([height, width] in pixels) and the other two numbers are y-pos and x-pos. Let’s try it…and I get a weird blob. Fiddling with the numbers doesn’t tell my anything, so let’s go into the source:

git clone https://github.com/Mon-Ouie/ray.git

(Side note: This project’s documentation is a bit lacking. Right now the non-github homepage is good at getting you excited (clearly :)) and gives a broad overview, but it’s light on details. It’s version 0.1.1, though, so this level of documentation is OK – for such an early version, getting people excited enough to, say, blog about it is a huge step.) Anyway, `git grep Ellipse` gives…nothing? What the heck? Oh – it’s lowercase `ellipse`. Oops. Anywyay, here’s what we want, in ext/polygon.c:

    @param [Ray::Vector2] center The center of the ellipse
    @param [Float] rx Horizontal radius
    @param [Float] ry Vertical radius
    @param [Ray::Color] color The color of the ellipse

So the first param is a Ray::Vector2 (in lib/vector.rb) which is the center of the ellipse, and the other two number params are the horizontal and vertical radius…lets’s try it. Here’s what I tried:

Ray::Polygon.ellipse([400, 400], 400, 40, Ray::Color.white)

No dice. It still gives me a weird blob in the upper left corner, even though

Ray::Polygon.circle([400, 400], 100, Ray::Color.white)

does what I think it should do: gives a circle with radius 100 centered at (400, 400). The weird scaling factor of the ellipse is throwing me off, I think.

This is taking too long. I’m going to use a rectangle instead – rounded corners aren’t essential right now. Thankfully, the rectangle initialization parameters are much easier to figure out, and I quickly have two paddles on screen:

Paddles on screen

We have paddles!

Gist of what I’ve got so far: https://gist.github.com/1087793
You’ll notice that I use descriptive variables instead of comments – this is directly attributable to reading Martin Fowler’s Refactoring at work. Also, it turns out I was right, I could make a re-usable paddle method.

Let’s make a ball

This is not going to be a moving ball, just a white circle in the center of the screen. This went much faster (maybe 30 seconds):

def ball
  Ray::Polygon.circle([WIDTH/2, HEIGHT/2], BALL_RADIUS, Ray::Color.white)
end
Paddles and a ball

We now have a ball.

Here’s the gist: https://gist.github.com/1087812

A Score to Settle

Now we draw the score. This is just to get the text in place.

Pong has a score now

You’ll note that I’m using “left” and “right” as the respective scores – this was so I could be sure that the text was placed correctly, since using “0″ for both wouldn’t show a difference. I expect the scores to be tracked by variables later, maybe with a redraw_scores method. I also expect to change @left_score to @left_score_text, but we’ll get to that later.
Here’s the gist: https://gist.github.com/1087824.

That Dotted Line

I like the dotted line, and it’s the last static element remaining, so let’s do it. I expect it to be pretty difficult to do a dotted line, so I’ll do a regular line. First, I’ll try this:

def middle_line
  Ray::Polygon.line([WIDTH/2, HEIGHT/2], [WIDTH, HEIGHT], HEIGHT, Ray::Color.white)
end

I thought that the parameters were ([initial_x, initial_y] [final_x, final_y], length, color) but it looks like I was wrong, since I got this:

Misshapen pong line

A misshapen line

But then I realized that I was right about the parameters, but wrong about which ones to put in. This worked:

def middle_line
  line_width = 5
  line_x_pos = center_x_pos
  Ray::Polygon.line([line_x_pos, 0], [line_x_pos, HEIGHT], line_width, Ray::Color.white)
end
Pong has a line down the middle now

Pong has a line down the middle now

And here’s the gist: https://gist.github.com/1087851. You’ll notice that I refactored pixels_[left,right]_of_center a bit.

Action!

Let’s try adding our first interactive piece: moving a paddle up and down with the keyboard. I know that I want the methods to be Lispy, like this:

def move_paddle_up(paddle)
  # ...
end

So let’s try that. It should work, since we can access polygon attributes directly. I ran into some problems trying to call a method defined outside the Ray.game block inside the on :key_press block (something about calling NilClass#arity), but using holding? worked fine. Plus, you can pass :up directly to holding?, while on :key_press requires you to pass in key(:up).

Here’s  the gist: https://gist.github.com/1087881.

Until next time

Well, that’s it for this post. In the next post: boundary detection, and (hopefully) finishing the game. I hope you learned something!

Tumblarity++

I just (re)started my Tumblr here: http://gabebw.tumblr.com/. I’ll be using it for short “today I learned”-style tips. I’ll use this blog for long-form posts.

Saving your work for later in Git

You’re working on a Git repo. Let’s say you’ve got a lot of uncommitted changes on your machine – maybe you’re spiking a new feature. What’s the best way to get those changes – including new files – onto a different machine, without sending over the whole Git repo? Simple:

work_box $ git diff master ORIG_HEAD > spike.patch
[Email the patch to yourself]
other_box $ git apply spike.patch

Git’s diff format will even create missing files. Note that this method won’t work for binary files – you’ll just have to send those to your other box.

Temp files in RSpec

I’ve been hard at work at Chat Stew, the awesome upgrade to Pidgin2Adium. My tests involve creating a lot of temporary files to test various inputs. I had a hard time finding a solution, and figured other people might be having the same troubles I am.

I looked at FakeFS and Construct (test-construct), but neither one does exactly what I want. FakeFS has good RSpec integration, but I want a real filesystem – I just need it to reliably delete files after I’m done with them. Construct is not easy to integrate with RSpec – they have Test::Unit helpers, but for RSpec I tried this (and it failed):
in spec_helper.rb:

RSpec.configure do |spec|
    spec.include Construct::Helpers
end

and the test:

within_construct do |construct|
  construct.file("log.html", "test content")
  it { should do_things_correctly } # etc
end

and that didn’t work. I also thought of Aruba, but that’s Cucumber-only.

So how can I get temp files that:

  • are guaranteed to be deleted when I don’t need them anymore, and
  • preferably have an easy way to specify their content?

As to the first part, Factory Girl has a wonderful bit of code in its (her?) spec: in_directory_with_files(*files). It is run in a context block, and it chdir’s to a tmp directory, creates an empty file for each file passed to the method, runs the specs, and removes the files afterward. It uses before and after blocks to handle creating the files and cleaning up. However, I didn’t want to have to do def self.in_directory_with_files(*files) for every context block, so I factored it out to a module and used a trick from FakeFS (the self.included bit below) to make it work when included in a describe block. I only use one temp file at a time, so my solution also dynamically creates a method called content_for_file which I use to specify that file’s content in it blocks.

Without further ado:

module UsesTempFiles
  def self.included(example_group)
    example_group.extend(self)
  end

  def in_directory_with_file(file)
    before do
      @pwd = Dir.pwd
      @tmp_dir = File.join(File.dirname(__FILE__), 'tmp')
      FileUtils.mkdir_p(@tmp_dir)
      Dir.chdir(@tmp_dir)

      FileUtils.mkdir_p(File.dirname(file))
      FileUtils.touch(file)
    end

    define_method(:content_for_file) do |content|
      f = File.new(File.join(@tmp_dir, file), 'a+')
      f.write(content)
      f.flush # VERY IMPORTANT
      f.close
    end

    after do
      Dir.chdir(@pwd)
      FileUtils.rm_rf(@tmp_dir)
    end
  end
end

Here it is in action:

describe ChatStew::ProgramProtocol do
  # "Percolates" down, so including it in an outer describe block gives the method to all blocks inside it
  include UsesTempFiles

  context "with non-empty file" do
    in_directory_with_file('non_empty_log')

    # You can also put the content_for_file call in an "it" block instead
    before do
      content_for_file("blah")
    end

    it "does things correctly"
  end
end

Python vs Ruby: Naming Conventions for Regexps

I was recently working on a Python project and, since I’m more of a Ruby guy, I went searching for the accepted way to name regexp objects in Python. Turns out, it’s

rChunker = re.compile("chunk_me")

At least, that’s how Django does it.

Of course, Ruby’s regexp literals make the need for a naming convention much less necessary, which is probably why Ruby doesn’t really have a convention (at least, a quick Google search and a grep through the rails source didn’t turn up anything). Since Ruby is all about lower_case_and_underscore, I propose using

re_chunker = /chunk_me/

Pidgin2Adium and the next step

Pidgin2Adium is getting old. It’s certainly useful, and it’s by far the most-used piece of software I’ve created (and the only one people have emailed me about). But it has a couple of problems:

  • It’s based on a PHP script, and it shows. I’ve managed to move it to a more Rubyish, object-oriented program, but parts of the original PHP are still there, particularly the LogFile class.
  • Needs more tests. While it does have tests, they’re not as comprehensive as they could be, and when testing, the C extension needs to be recompiled for each Ruby version I test against (1.8.7, 1.9.1, 1.9.2, etc.), which is annoying. The next version should be written using TDD.
  • Two ways to use it. It’s (1) a library that parses Pidgin log files, and (2) a script that uses that parser to parse files, then writes them out in Adium format. This double functionality means that Pidgin2Adium should be split into 2 projects.

Therefore, I am happy to announce that I am working on a new project: a parser for chat log files (Pidgin, Adium, etc), called Chat Stew. Instead of just parsing Pidgin files, it will parse many programs’ log files, and will have a robust plugin system for 3rd party parsers, which will allow anyone to contribute a parser. This means that Pidgin2Adium 4.0.0 will no longer include a parser; instead, by using Chat Stew, it will become a much simpler, cleaner script with a smaller focus.

Sounds awesome! When will it be ready?

Chat Stew is currently under development, and probably won’t be released until January 2011 (alas, school…). In the meantime, I will continue to improve Pidgin2Adium.

Upcoming post on status of Pidgin2Adium

I’m going to be posting more about the current state of Pidgin2Adium and my plans for its next generation sometime this week or early next week. Stay tuned!

Pidgin2Adium 3.2.1 Released [UPDATED for 3.2.3]

UPDATE: 3.2.1 didn’t fix all of the problems. People should not use 3.2.1 or 3.2.2, since they were minor releases to fix the bug that 3.2.3 finally fixed. All of the information in this post applies to 3.2.3, not 3.2.1 or 3.2.2.

Pidgin2Adium 3.2.1 has been released. Get it now: gem install pidgin2adium.

This release parses more date/time formats than previous versions by using the built-in DateTime.parse command. It falls back to Date._strptime if DateTime.parse fails. This means that it should be faster than previous versions and more liberal in the date formats it parses.

Stupid Ruby Trick: Using a Hash to generate the Fibonacci Sequence

Via http://gist.github.com/173565, which is in turn via Nick Quaranto.

The gist pointed out that Hash.new, with its default values, is good for implementing Fibonacci sequences. So I decided to check:

fib = Hash.new do |hash,key|
  k = key.to_i
  hash[key] = case k
    when 0 then 0
    when 1 then 1
    else hash[k-1] + hash[k-2]
  end
end

This recursive (and memoized!) definition means that you can do fib[18] and get back 2584, plus you get the Fibonacci numbers from F0 (fib[0]) to F17 (fib[17]). Recursively defined Hashes are useful auto-memoized structures.

Follow

Get every new post delivered to your Inbox.