[QUIZ] Lisp Game (#49)

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

···

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

There's been quite a bit of discussion lately about how much Ruby is and isn't
like Lisp. While I've known of Lisp for some time now, I have never really
taken the time to play with it until just recently. I started with this great
tutorial:

  http://www.lisperati.com/casting.html

Of course, just reading it didn't tell me all about the differences between Ruby
and Lisp, so I decided to translate it to Ruby. That taught me a lot, so I
thought I would share.

This week's Ruby Quiz is to translate the game built in the above tutorial into
the equivalent Ruby.

The tutorial is very interactive, so you should probably target irb as your
platform. (I did.) Don't worry about the prose here, we're just translating
the code from the tutorial.

I would say there are probably two extremes for how this can be done. You can
basically choose a direct command-for-command translation or decide to keep the
premise but translate the code to typical Ruby constructs. I think there's
merit to both approaches. I took the direct translation route for instance, and
I had to do a fair bit of thinking when I hit the section on Lisp's macros. On
the flip side, I think it would be great too wrap all the data in Ruby's objects
and use the tutorial to show off concepts like Ruby's open class system. So aim
for whatever approach interests you.

Holy crap, this looks cool. Very interested in seeing what comes out of it.

···

On 9/30/05, Ruby Quiz <james@grayproductions.net> wrote:

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

There's been quite a bit of discussion lately about how much Ruby is and isn't
like Lisp. While I've known of Lisp for some time now, I have never really
taken the time to play with it until just recently. I started with this great
tutorial:

        http://www.lisperati.com/casting.html

Of course, just reading it didn't tell me all about the differences between Ruby
and Lisp, so I decided to translate it to Ruby. That taught me a lot, so I
thought I would share.

This week's Ruby Quiz is to translate the game built in the above tutorial into
the equivalent Ruby.

The tutorial is very interactive, so you should probably target irb as your
platform. (I did.) Don't worry about the prose here, we're just translating
the code from the tutorial.

I would say there are probably two extremes for how this can be done. You can
basically choose a direct command-for-command translation or decide to keep the
premise but translate the code to typical Ruby constructs. I think there's
merit to both approaches. I took the direct translation route for instance, and
I had to do a fair bit of thinking when I hit the section on Lisp's macros. On
the flip side, I think it would be great too wrap all the data in Ruby's objects
and use the tutorial to show off concepts like Ruby's open class system. So aim
for whatever approach interests you.

Here is my solution, which is basically Jame's solution, but split into
a few files.

You can optionally turn on and off the method_missing trick by choosing
to require or not require "interactive"

adventure.rb (general game functions / direct translation with a couple
extra aliases):

http://stonecode.org/organizations/unh.rb/code/meetings/2005.09.29/adventure.rb

interactive.rb (method missing trick)

http://stonecode.org/organizations/unh.rb/code/meetings/2005.09.29/interactive.rb

game.rb (The wizard game)
http://stonecode.org/organizations/unh.rb/code/meetings/2005.09.29/game.rb

I take no credit for Jame's code, just figured I'd share this for those
of you who wanted to play with what james made without cutting up the
Lisp / Perl file.

Here is my solution, which is basically Jame's solution, but split into
a few files.

You can optionally turn on and off the method_missing trick by choosing
to require or not require "interactive"

adventure.rb (general game functions / direct translation with a couple
extra aliases):

http://stonecode.org/organizations/unh.rb/code/meetings/2005.09.29/adventure.rb

interactive.rb (method missing trick)

http://stonecode.org/organizations/unh.rb/code/meetings/2005.09.29/interactive.rb

game.rb (The wizard game)
http://stonecode.org/organizations/unh.rb/code/meetings/2005.09.29/game.rb

I take no credit for Jame's code, just figured I'd share this for those
of you who wanted to play with what james made without cutting up the
Lisp / Ruby file.

I think the fun of these games ( especially when they first came out ) was
that it didn't seem like you were interacting with a computer. Thus some of
the fun is ruined when you have to type 'bucket-of-water' instead of 'bucket
of water'. The limited 'world' of this game also seemed contrived to fit the
program rather than having the program fit the 'world'.
I decided to go pure Ruby instead of writing Ruby methods to handle the LISP
formulas. I didn't think the original LISP was very readable, and so any
Ruby interpretation of it would be equally obfuscated.
So here is a short version with no ( that's right! zero ) added classes.
Just a big multi dimensional array to hold the data and a few methods to
implement the game.
Neat features include natural language handling: Try typing 'weld the bucket
to the chain' or 'dunk the drunken wizard with a bucket of water'. Also has
more detailed error messages that are particular to the verb. This adds
realism to the game, and is hard to get when all the verb methods are joined
into one generic method like in the LISP program. This generalization of
methods is almost always a good programming technique, but it takes away
from the realism in this particular type of game, so I avoided it. I also
gave each player a pet rock for added enjoyment.

#the wizard of 3 rooms
$map = [ ["living room","you are in the living-room of a wizard\'s house.
there is a wizard snoring loudly on the couch.",
            ["bottle of Jack Daniels","bucket"],
            [["west","door","garden"],["upstairs","stairway","attic"]]],
        ["garden","you are in a beautiful garden. there is a well in front
of you.",
            ["chain","frog"],
            [["east","door","living room"]]],
        ["attic","you are in the attic of the abandoned house. there is a
giant welding torch in the corner.",
            ,
            [["downstairs","stairway","living room"]]] ]
$location = "living room"
$knapsack = ["pet rock"]
$Commands = %w{look inventory get walk weld fill dunk }

def look(command)
    myroom = $map.assoc($location)
    print "#{myroom[1]}\n"
    myroom[2].each{|item| print "There is a #{item} on the floor\n"}
    myroom[3].each{|route|
        print "There is a #{route[1]} going #{route[0]} from here\n"
    }
end
def inventory(command)
    if $knapsack.length == 0
        print "you have nothing in your knapsack\n"
    else
        $knapsack.each{|item| print "you have a #{item} in your knapsack\n"}
    end
end
def get(command)
    if command.length < 2
        print "get what?\n"
    else
        command.shift
        object = command.join(" ")
        if $map.assoc($location)[2].include?(object)
         $knapsack << object
         $map.assoc($location)[2].delete(object)
         print "you now have a #{object}\n"
     else
         print "you can't get #{object}\n"
  end
    end
end
def walk(command)
    if command.length <2
        print "pacing..\n"
    elsif (route = $map.assoc($location)[3].assoc(command[1])) == nil
        print "you can't go #{command[1]} from #{$location}\n"
    else
        $location = route[2]
        look(["look"])
    end
end
def go(command)
    walk(command)
end
def weld(command)
    if not command.include?("chain") or not command.include?("bucket")
        print "I don't understand!, Weld what to what?\n"
    elsif $location != "attic"
        print"There is no welder here\n"
    elsif $knapsack.include?("chain") and $knapsack.include?("bucket")
        $knapsack.delete("bucket")
        $knapsack.delete("chain")
        $knapsack << "bucket on a chain"
    else
        print"You need a bucket and a chain to do that\n"
    end
end
def fill(command)
    if $location != "garden"
        print"There is no water here\n"
    elsif not command.include?("bucket")
        print "I don't understand!, What do you want to fill?\n"
    elsif $knapsack.include?("bucket")
        print "The water is to far down to reach with the bucket\n"
    elsif $knapsack.include?("bucket on chain")
        $knapsack.delete("bucket on chain")
        $knapsack << "bucket of water on chain"
        print"You now have a bucket of water on a chain\n"
    elsif $knapsack.include?("bucket of water on chain")
        print"The bucket is already full\n"
    else
        print"You have nothing to fill\n"
    end
end
def dunk(command)
    if not $knapsack.include?("bucket of water on chain")
        print"you have no water\n"
    elsif not command.include?("wizard")
        print "splash\n"
    elsif $location != "living room"
        print "There is no wizard here\n"
    elsif $knapsack.include?("frog")
        print"The wizard is awoken. He sees you have stolen his frog. He
banishes you to Siberia\n"
        print"You Lose\n"
        abort
    else
        print"The wizard is awoken. He gives you the low carb donut (Yum!)
and you live happily ever after\n"
        print"You Win\n"
        abort
    end
end

STDOUT.flush
command = ["look"]

while command[0] != "end"
    if $Commands.include?(command[0])
        eval command[0] + "(command)"
    else
        print "Huh?\n"
    end
    print "?"
    STDOUT.flush
    input = gets
    command = input.split(" ")
    puts command
end

···

Thanks. It's a James Original Ideas(tm) and we all know those can be a little rocky. :wink:

Seriously, I hope people will give it a try. It's a beginning Lisp tutorial, so you don't need to know it going in. It didn't take me much longer to do than it did to read the tutorial itself. Besides all that, it's downright fun code to play with.

Interesting Fact: My translation was used at a .rb group meeting last night to expose Ruby neophytes to the language and I hear it went well.

James Edward Gray II

···

On Sep 30, 2005, at 7:15 PM, Joe Van Dyk wrote:

Holy crap, this looks cool. Very interested in seeing what comes out of it.

James Edward Gray II wrote:

Interesting Fact: My translation was used at a .rb group meeting
last night to expose Ruby neophytes to the language and I hear it
went well.

It went EXCELLENT!

There is nothing quite like seeing a room full of people's eyes light
up and say... ooh this would be so much uglier in Java / VB / C / Etc.

Even our python guy was like, some of the stuff James did would be hard
to do as elegantly and python. So... eat that, snake charmers!

Anyway, it was a great example and next week's meeting goal will be
porting the tutorial to something object oriented in nature.

Anyway, thanks to James and I certainly encourage anyone to try this
out, because my group loved it!

James Edward Gray II wrote:

Interesting Fact: My translation was used at a .rb group meeting
last night to expose Ruby neophytes to the language and I hear it
went well.

It went EXCELLENT!

There is nothing quite like seeing a room full of people's eyes light
up and say... ooh this would be so much uglier in Java / VB / C / Etc.

Even our python guy was like, some of the stuff James did would be hard
to do as elegantly in python. So... eat that, snake charmers!

Anyway, it was a great example and next week's meeting goal will be
porting the tutorial to something object oriented in nature.

Anyway, thanks to James and I certainly encourage anyone to try this
out, because my group loved it!