[SOLUTION] Lisp Game (#49)

Discussion in 'Ruby' started by Markus Koenig, Oct 2, 2005.

  1. Again a fun quiz! I remember reading this tutorial too.

    This is my solution, which uses Highline (version 1.* recommended). My
    approach was far more rewrite-based. Unfortunately, I didn't come up
    with a nice game-action "macro".

    The user interface is the same as the Lisp program's, but omitting the
    parens. BTW, why does Highline lose when EOF is encountered? I really
    miss the Ctrl-D...

    Anyway, I noticed one could cheat in my game:

    >> take bucket
    >> instance_variable_set @bucket_filled foobar
    >> splash bucket wizard


    Voila. ;)

    Markus

    ======

    #! /usr/bin/env ruby


    require 'highline/import'
    require 'set'


    # This is a kind of room, including a garden.
    class Room
    def initialize(description, *items)
    @description = description
    @directions = Hash.new
    @direction_gateways = Hash.new
    @inventory = Set.new(items)
    end

    def look
    puts @description
    @direction_gateways.each do |dir, gateway|
    puts "There is a #{gateway} going #{dir} from here."
    end
    @inventory.each do |item|
    puts "You see a #{item} on the floor."
    end
    end

    def define_direction(dir, gateway, where)
    @directions[dir] = where
    @direction_gateways[dir] = gateway
    end

    # returns the place a direction leads to
    def get_direction(dir)
    @directions[dir]
    end

    def have?(item)
    @inventory.include? item
    end

    def drop(item)
    @inventory.add item
    end

    def take(item)
    @inventory.delete item
    return item
    end
    end

    # Define the rooms with items in them.
    $livingroom = Room.new("You are in the living-room of a wizard's
    house.\n" +
    "There is a wizard snoring loudly on the couch.", :bucket)
    $attic = Room.new("You are in the attic of the abandoned house.\n" +
    "There is a giant welding torch in the corner.")
    $garden = Room.new("You are in a beautiful garden.\n" +
    "There is a well in front of you.", :chain, :frog)

    # Connect the rooms.
    $livingroom.define_direction :west, :door, $garden
    $livingroom.define_direction :upstairs, :stairway, $attic
    $attic.define_direction :downstairs, :stairway, $livingroom
    $garden.define_direction :east, :door, $livingroom


    # This is the guy you control.
    class Apprentice
    # texts that are shown at The End
    ENDGAME_WIN =
    "The wizard awakens from his slumber and greets you\n" +
    "warmly. He hands you the magic low-carb donut -\n" +
    "You win! The End."
    ENDGAME_LOSE =
    "The wizard awakens and sees that you stole his frog.\n" +
    "He is so upset he banishes you to the netherworlds -\n" +
    "You lose! The End."
    ENDGAME_EXIT =
    "The wizard awakens, puling disappointedly,\n" +
    " Premature disassociation is the root\n" +
    " Of all eval."

    def initialize
    @location = $livingroom
    @inventory = Set.new([:"whiskey-bottle"])

    @chain_welded = false
    @bucket_filled = false
    end

    # *** Commands for exploring the house ***

    def exit
    # show the wizard's wisdom
    puts ENDGAME_EXIT

    # if this was plain "exit", we had infinite recursion...
    Kernel.exit
    end
    alias quit exit

    def look
    @location.look
    end

    def walk(dir)
    if @location.get_direction(dir)
    @location = @location.get_direction(dir)
    @location.look
    elsif @location == $garden and dir.to_s.hash == -781591621
    # well, how do you get here?
    puts 'You see a maze of twisty little passages,'
    puts 'all alike. But you can\'t go there.'
    else
    puts "You can't go #{dir}."
    end
    end
    alias go walk

    # *** Commands for handling items ***

    # note: have? does not print anything
    def have?(item)
    @inventory.include? item
    end

    def have(item)
    puts have?(item)
    end

    def drop(item)
    if have? item
    @location.drop item
    @inventory.delete item
    puts "You are no longer carrying the #{item}."
    else
    puts "You do not have that."
    end
    end

    def take(item)
    if @location.have? item
    @inventory.add @location.take(item)
    puts "You are now carrying the #{item}."
    else
    puts "I see no #{item} here."
    end
    end
    alias pickup take

    def inventory
    if @inventory.empty?
    puts 'You are carrying no items.'
    else
    inventory_text = @inventory.to_a.join(', ')
    puts "You are carrying: #{inventory_text}"
    if have? :bucket and @chain_welded
    puts 'The chain is welded to the bucket.'
    end
    if have? :bucket and @bucket_filled
    puts 'The bucket is filled with water.'
    end
    end
    end

    # *** Game actions ***

    def weld(subject, object)
    if @location == $attic and have? :chain and have? :bucket and
    subject == :chain and object == :bucket
    @inventory.delete :chain
    @chain_welded = true
    puts 'The chain is now securely welded to the bucket.'
    else
    puts 'You cannot weld like that.'
    end
    end

    def dunk(subject, object)
    if @location == $garden and have? :bucket and
    subject == :bucket and object == :well
    if @bucket_filled
    puts 'The bucket is already filled.'
    elsif @chain_welded
    @bucket_filled = true
    puts 'The bucket is now full of water.'
    else
    puts 'The water level is too low to reach.'
    end
    else
    puts 'You cannot dunk like that.'
    end
    end

    def splash(subject, object)
    if @location == $livingroom and have? :bucket and
    subject == :bucket and object == :wizard
    if not @bucket_filled
    puts 'The bucket has nothing in it.'
    elsif have? :frog
    puts ENDGAME_LOSE
    Kernel.exit
    else
    puts ENDGAME_WIN
    Kernel.exit
    end
    else
    puts 'You cannot splash like that.'
    end
    end
    end


    # Create the apprentice.
    $apprentice = Apprentice.new
    $apprentice.look


    # Provide a user interface.
    loop do
    # read a line
    command = ask('>> ') do |question|
    # try to use Readline (only Highline 1.0.0 and above)
    if question.respond_to? :readline=
    question.readline = true
    end
    end

    # run the command
    begin
    commandwords = command.split.map {|x| x.downcase.to_sym}
    $apprentice.send *commandwords unless commandwords.empty?
    rescue ArgumentError, NoMethodError
    puts 'I do not understand.'
    end
    end
    Markus Koenig, Oct 2, 2005
    #1
    1. Advertising

  2. Re: Lisp Game (#49)

    Markus Koenig wrote:

    > The user interface is the same as the Lisp program's, but omitting the
    > parens. BTW, why does Highline lose when EOF is encountered? I really
    > miss the Ctrl-D...


    Hmm... not exactly sure why this doesn't work. I'll try to dig through
    HighLine and figure this out if I get some time this week, if James
    doesn't beat me to the punch, that is :)
    Gregory Brown, Oct 3, 2005
    #2
    1. Advertising

  3. Re: Lisp Game (#49)

    Gregory Brown wrote:

    > Markus Koenig wrote:
    >
    >> The user interface is the same as the Lisp program's, but omitting the
    >> parens. BTW, why does Highline lose when EOF is encountered? I really
    >> miss the Ctrl-D...

    >
    > Hmm... not exactly sure why this doesn't work. I'll try to dig through
    > HighLine and figure this out if I get some time this week, if James
    > doesn't beat me to the punch, that is :)


    This is what I get from HighLine 1.0.1:

    [...]
    /usr/lib/ruby/site_ruby/1.8/highline/question.rb:362:in `send':
    undefined method `strip' for nil:NilClass (NoMethodError)
    from /usr/lib/ruby/site_ruby/1.8/highline/question.rb:362:in `remove_whitespace'
    from /usr/lib/ruby/site_ruby/1.8/highline.rb:527:in `get_line'
    from /usr/lib/ruby/site_ruby/1.8/highline.rb:545:in `get_response'
    from /usr/lib/ruby/site_ruby/1.8/highline.rb:155:in `ask'
    from lispgame.rb:221
    from lispgame.rb:219:in `loop'
    from lispgame.rb:219

    In question.rb:362 the result of readline (highline.rb:528) or gets
    (highline.rb:533) is stripped. I guess the cleanest thing to do is just
    to raise EOFError if any of these methods returns nil.

    This wasn't that hard :)

    Regards,
    Markus
    Markus Koenig, Oct 3, 2005
    #3
  4. HighLine Issue (was Re: Lisp Game (#49))

    On Oct 2, 2005, at 7:36 PM, Markus Koenig wrote:

    > Gregory Brown wrote:
    >
    >
    >> Markus Koenig wrote:
    >>
    >>
    >>> The user interface is the same as the Lisp program's, but
    >>> omitting the
    >>> parens. BTW, why does Highline lose when EOF is encountered? I
    >>> really
    >>> miss the Ctrl-D...
    >>>

    >>
    >> Hmm... not exactly sure why this doesn't work. I'll try to dig
    >> through
    >> HighLine and figure this out if I get some time this week, if James
    >> doesn't beat me to the punch, that is :)
    >>

    >
    > This is what I get from HighLine 1.0.1:
    >
    > [...]
    > /usr/lib/ruby/site_ruby/1.8/highline/question.rb:362:in `send':
    > undefined method `strip' for nil:NilClass (NoMethodError)
    > from /usr/lib/ruby/site_ruby/1.8/highline/question.rb:
    > 362:in `remove_whitespace'
    > from /usr/lib/ruby/site_ruby/1.8/highline.rb:527:in `get_line'
    > from /usr/lib/ruby/site_ruby/1.8/highline.rb:545:in
    > `get_response'
    > from /usr/lib/ruby/site_ruby/1.8/highline.rb:155:in `ask'
    > from lispgame.rb:221
    > from lispgame.rb:219:in `loop'
    > from lispgame.rb:219
    >
    > In question.rb:362 the result of readline (highline.rb:528) or gets
    > (highline.rb:533) is stripped. I guess the cleanest thing to do is
    > just
    > to raise EOFError if any of these methods returns nil.


    Hello Markus.

    I'm very interested in understanding this problem and fixing it
    correctly. Could you please show a trivial HighLine script and how
    you are trying to use it, so I can wrap my head around this?

    Thanks.

    James Edward Gray II
    James Edward Gray II, Oct 3, 2005
    #4
  5. Re: HighLine Issue (was Re: Lisp Game (#49))

    Hello James,

    I really appreciate your and Greg's work. It's nice to see what can
    evolve from a simple quiz idea. :)

    > I'm very interested in understanding this problem and fixing it
    > correctly. Could you please show a trivial HighLine script and how
    > you are trying to use it, so I can wrap my head around this?


    I think HighLine's methods should either raise EOFError or return nil
    if EOF is reached, but I'm not sure which one would be nicer. Maybe a
    hybrid approach, like IO#gets and IO#readline?

    The trivial script, if the methods return nil:

    require 'highline/import'
    loop do
    name = ask("What's your name?")
    if response.nil? or response == 'exit'
    puts 'Goodbye, dear friend.'
    exit
    else
    puts "Hello, #{name}!"
    end
    end

    I expect this program to behave like most Unix shells - quietly quit
    when one presses Ctrl-D (EOF). But this would print a stack trace, as
    shown earlier.

    Thanks,
    Markus
    Markus Koenig, Oct 6, 2005
    #5
  6. Re: HighLine Issue (was Re: Lisp Game (#49))

    On Oct 6, 2005, at 4:11 PM, Markus Koenig wrote:

    > Hello James,
    >
    > I really appreciate your and Greg's work. It's nice to see what can
    > evolve from a simple quiz idea. :)


    Thanks for the kind words.

    >> I'm very interested in understanding this problem and fixing it
    >> correctly. Could you please show a trivial HighLine script and how
    >> you are trying to use it, so I can wrap my head around this?
    >>

    >
    > I think HighLine's methods should either raise EOFError or return nil
    > if EOF is reached, but I'm not sure which one would be nicer. Maybe a
    > hybrid approach, like IO#gets and IO#readline?
    >
    > The trivial script, if the methods return nil:
    >
    > require 'highline/import'
    > loop do
    > name = ask("What's your name?")
    > if response.nil? or response == 'exit'
    > puts 'Goodbye, dear friend.'
    > exit
    > else
    > puts "Hello, #{name}!"
    > end
    > end
    >
    > I expect this program to behave like most Unix shells - quietly quit
    > when one presses Ctrl-D (EOF). But this would print a stack trace, as
    > shown earlier.


    I've added this to our TODO. It will be addressed in the next
    version of HighLine.

    James Edward Gray II
    James Edward Gray II, Oct 9, 2005
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. ekzept
    Replies:
    0
    Views:
    357
    ekzept
    Aug 10, 2007
  2. Jim Menard

    [SOLUTION] Lisp Game (#49)

    Jim Menard, Oct 2, 2005, in forum: Ruby
    Replies:
    9
    Views:
    97
  3. Brian Schröder

    [Quiz] [Solution] Lisp Game

    Brian Schröder, Oct 3, 2005, in forum: Ruby
    Replies:
    2
    Views:
    109
    James Edward Gray II
    Oct 5, 2005
  4. Louis J Scoras
    Replies:
    13
    Views:
    306
    Dave Burt
    Oct 5, 2005
  5. Sean O'Halpin

    [Solution] Lisp Game #49

    Sean O'Halpin, Oct 6, 2005, in forum: Ruby
    Replies:
    0
    Views:
    166
    Sean O'Halpin
    Oct 6, 2005
Loading...

Share This Page