Well, how far did you get?  I'm stuck on level 28 myself.

As those of you who have now built Sokoban know, the game is quite trivial to
implement.  Here's a very brief solution from Dennis Ranke:

	class Level
	  def initialize(level)
		@level = level
	  end
	
	  def play
		while count_free_crates > 0
		  printf "\n%s\n\n> ", self
		  c = gets
		  c.each_byte do |command|
			case command
			  when ?w
				move(0, -1)
			  when ?a
				move(-1, 0)
			  when ?s
				move(0, 1)
			  when ?d
				move(1, 0)
			  when ?r
				return false
			end
		  end
		end
		printf "\n%s\nCongratulations, on to the next level!\n", self
		return true
	  end
	
	private
	
	  def move(dx, dy)
		x, y = find_player
		dest = self[x+dx, y+dy]
		case dest
		  when ?#
			return
		  when ?o, ?*
			dest2 = self[x+dx*2, y+dy*2]
			if dest2 == 32
			  self[x+dx*2, y+dy*2] = ?o
			elsif dest2 == ?.
			  self[x+dx*2, y+dy*2] = ?*
			else
			  return
			end
			dest = (dest == ?o) ? 32 : ?.
		end
		self[x+dx, y+dy] = (dest == 32) ? ?@ : ?+
		self[x, y] = (self[x, y] == ?@) ? 32 : ?.
	  end
	
	  def count_free_crates
		@level.scan(/o/).size
	  end
	
	  def find_player
		pos = @level.index(/@|\+/)
		return pos % 19, pos / 19
	  end
	
	  def [](x, y)
		@level[x + y * 19]
	  end
	
	  def []=(x, y, v)
		@level[x + y * 19] = v
	  end
	
	  def to_s
		(0...16).map {|i| @level[i * 19, 19]}.join("\n")
	  end
	end
	
	levels = File.readlines('sokoban_levels.txt')
	levels = levels.map {|line| line.chomp.ljust(19)}.join("\n")
	levels = levels.split(/\n {19}\n/).map{|level| level.gsub(/\n/, '')}
	
	levels.each do |level|
	  redo unless Level.new(level.ljust(19*16)).play
	end

Dennis decided to keep the levels in their text format and lean on Ruby's text
processing strengths.  This probably doesn't make for the prettiest of
solutions, but it is short.

Level.play() is the primary interface for the code above.  It handles one level,
start to finish, returning true if the level was solved and false if it was
restarted.  It checks for a level being solved by looping until
Levels.count_free_crates() returns 0.  That method simply scan()s for "o"
characters, returning a count.  When a player enters a move command, work is
handed off to the game-play routine Level.move().

The first step to performing a move is to find the player.  Level.find_player()
uses a combination of index() and simple math to locate a "@" or "+" character. 
(Note:  This is a weakness of Dennis' solution.  It only works for levels 19
characters wide and smaller.)  Once found, move() checks the square in front of
the player.  If it's a wall, it disallows the move and if it's open, the player
moves.  The special case is when there is a crate in front of the player.  When
found, move() looks farther forward to ensure that the path is clear and if it
is, both crate and player are moved.  All this testing and swapping is handled
with Level.[]() and Level.[]=(), which function as expected.

For a more abstract OO solution, check out the code sent in by Dave Burt.

So, as I've said and we've now seen, implementing Sokoban is pretty easy stuff. 
Extra features weren't too popular, but some did allow for a way to restart
levels.  That is pretty critical in Sokoban, where you can easily get yourself
stuck.  Dave Burt's solution includes a debugging mode that allows you to feed
the game engine pure Ruby.  My solution also provided Undo, Save, and Load.  I
think a level editor and a solver would make interesting additions.

Let's talk about one more thing though.  Interface.  To a game, interface is
critical.  Dennis Ranke's and Dave Burt's games read line-oriented input,
requiring you to push enter/return to send a move.  While they do allow you to
queue up a long line of moves, this tires my poor little fingers out, especially
on involved levels.

That begs the question, why did they use this approach?

Portability, would be my guess.  Reading a single character from a terminal
interface can get tricky, depending on which operating system you are running
on.  Here's how I do it on Unix:

	def read_char
		system "stty raw -echo"
		STDIN.getc
	ensure
		system "stty -raw echo"
	end

Here's one way you might try the same thing on Windows:

	def read_char
		require "Win32API"

		Win32API.new("crtdll", "_getch", [], "L").Call
	end

If you want your game to run on both, you may need to write code to detect the
platform and use the proper method.  Here's one way you might accomplish that:

	begin
		require "Win32API"
		
		def read_char
			Win32API.new("crtdll", "_getch", [], "L").Call
		end
	rescue LoadError
		def read_char
			system "stty raw -echo"
			STDIN.getc
		ensure
			system "stty -raw echo"
		end
	end

That doesn't cover every platform, but I believe it will work with Windows and
most Unix flavors (including Mac OS X).  That may be enough for some purposes.

Other submissions dealt with this differently.  G.Durga Prasad's solution used
Curses.  Curses is standard Ruby, but unfortunately not so standard in the
Windows world.  A great advantage to this approach was being able to use the
arrow keys, which makes for the best interface, I think.

I believe Florian Gross also used the arrow keys, but his solution doesn't seem
to support my platform.  He used the Ruby/Gosu game library to build a graphical
Sokoban.

Thomas Leitner provided another Curses solution in addition to one that requires
FXRuby, a Ruby interface to the FOX GUI library.  Thomas's submission is also a
brilliant piece of AI, since it knew to tell me "You are the greatest player in
history!!!"

My own solutions either relied on a Unix terminal or a Ruby/OpenGL library being
installed.

Interface work can get neck deep in external dependancies pretty quick it seems.
 Since games are largely defined by their interface, that can make for some
complex choices.  Maybe we should hope for a Swing-like addition to the Ruby
Standard Library sometime in the future.

My thanks to the game writers and game players.

Look for our second contributed quiz topic tomorrow morning, this time by Jamis
Buck...