hoodwink.d enhanced
RSS
2.0
XHTML
1.0

RedHanded

MUD in 15 Lines of Ruby #

by why in bits

This is great. In response to a post about how writing a MUD in Ruby would be “a horrifically complex and lengthy project,” Jon Lambert dropped a 15-line MUD in the response! Now that’s a comeback.

 require 'socket';require 'yaml';def q x;$m.find{|o|o.t==:p&&x==o.n};end
 def a r,t;$m.find_all{|o|t==o.t&&(!r||r==o.l)};end;def g z;a(nil,:p).each{|p|
 p.p z};end;class O;attr_accessor :i,:n,:l,:e,:s,:t;def initialize n,l=nil,t=:r
 @n,@l,@i,@t=n,l,$d+=1,t;@e={};end;def p s;@s.puts(s)if @s;end;def y m
 v=$m.find{|o|@l==o.i};t=v.e.keys;case m;when/^q/;@s.close;@s=nil;
 File.open('d','w'){|f|YAML::dump $m,f};when/^h/;p "i,l,d,g,c,h,q,<exit>,O,R" 
 when/^i/;a(@i,:o).each{|o|p o.n};when/^c.* (.*)/;g "#{@n}:#{$1}" 
 when/^g/;a(@l,:o).each{|q|q.l=@i};when/^d/;a(@i,:o).each{|q|q.l=@l}
 when/^O (.*)/;$m<<O.new($1,@l,:o);when/^R (.*) (.*) (.*)/;$m<<d=O.new($1)
 v.e[$2]=d.i;d.e[$3]=v.i;when/^l/;p v.n;(a(@l,:p)+a(@l,:o)).each{|x|
 p x.n if x.s||x.t==:o};p t.join '|';when/(^#{t.empty? ? "\1" : t.join('|^')})/
 @l=v.e[$1];else;p "?";end;end;end;test ?e,'d'||begin;$d=0;$m=[O.new("Home")]
 end;$m=YAML::load_file 'd';$d=$m.size;z=TCPServer.new 0,4000;while k=z.accept
 Thread.new(k){|s|s.puts "Name";s.gets;l=$_.chomp;d=q l;$m<<d=O.new(l,1,:p)if !d
 d.s=s;while s.gets;d.y $_.chomp;end;};end

A bit of sleuthing on the matter and I’ve discovered that this is a derivative of Jon’s TeensyMud. He has nice, readable versions in his repository, if you like.

If you want to play with this one:

  1. Save the above to teensymud.rb.
  2. Create a YAML file named “d” (for dungeon) with a blank array in it. (Likeso: echo "[]" > d.)
  3. Run teensymud.rb.
  4. Telnet to localhost port 4000.
  5. At Name prompt, enter your name then <Enter>.
Play commands
i displays player inventory
l displays the contents of a room
dr drops all objects in your inventory into the room
g gets all objects in the room into your inventory
k (name) attempts to kill player (e.g. k bubba)
s (message) sends (message) to all players in the room
c (message) sends (message) to all players in the game
q quits the game (saves player)
(exit name) moves player through exit named (ex. south)
OLC
O (object name) creates a new object (ex. O rose)
R (room name) (exit name to) (exit name back) creates a new room and autolinks the exits using the exit names provided.

Please, tell us more, Jon. If you’re feeling nostalgic and want to egg things on, come join ruby-talk this week. The Ruby Quiz will be a MUD client. (extracted from ruby-talk:154208.)

said on 30 Aug 2005 at 13:03

Freakin’ amazing. I love Ruby!

said on 30 Aug 2005 at 16:21

ack! ack! my long dormant mud addiction is in danger of being rekindled

said on 30 Aug 2005 at 16:36

_why, you forgot to escape the < > tags in that text. You should see what it’s doing to Safari.

The page just ENDS before < object name >, same with the main page.

said on 30 Aug 2005 at 16:48

My thanks to you, emphatically greased.

said on 30 Aug 2005 at 16:55

The instructions are longer than the entire code for the MUD .

...and I see you’ve included my bug fix :)

said on 30 Aug 2005 at 17:03

I really want to know how you discovered that.

said on 30 Aug 2005 at 18:32

I’ve been reading MUD Game Programming and implementing its “SimpleMUD” in Ruby rather than C++. Not only is it possible, it’s awesome.

Stuff like Teensy MUD ’s YAML databases and being able to put regexps in a case statement streamlines any MUD . Ruby is well-suited for MUD development.

I’ve even been able to use irb in lieu of OLC !

said on 30 Aug 2005 at 23:43

I learned the C-syntax using LPC .

said on 31 Aug 2005 at 08:56

I discovered it while de-obfuscating the script. I still haven’t executed the thing.

The script is actually remarkably simple – well done, Jon.

Long version: look at the immediate context (with the missing ”=”):

.each{|x| p x.n if x.s||x.t=:o}

Now, that is going to p all x.n, and overwrite x.t with a literal :o. That’s pretty sus already; it makes more sense for that expression just to be a condition. Then, .n is for name, .t is for type, and :o is for object (the kind you can pick up). Finally, this is when/^l/—in response to the look command.

said on 02 Sep 2005 at 16:31

Geeze, what have I unleashed?

said on 02 Sep 2005 at 23:41

Sy: And the funny thing is, you only asked for a client!

said on 14 Sep 2005 at 01:27

Oh there’s no need to create a ‘d’ file just run it. When you quit the world will be saved. A fixed version of the above with Dave’s “medusa” bug fix is at ftp://sourcery.dyndns.org/pub/mud/teensymud/t14k.tgz

I’m up to release 2.4 now around 32K of code. If you don’t have a juvenile sense of humor you may want to steer clear from the larger version.

said on 14 Sep 2005 at 16:33

I don’t get it. Why is this a good thing? I agree it’s not lengthy, but how is that not “horrifically complex” in its readability?

said on 22 Dec 2005 at 09:06

Just plain beautiful.

said on 04 Jan 2006 at 04:19

I created a wiki/forum site for TeensyMud. Not much there, but there is a list of other ruby muds there that I know about.

I call it TeensyWeb (of course). I’m planning to release the site code as well. Since this is my first rails app, I expect there’s a lot of bugs in it.

Comments are closed for this entry.