RCRPG/Ruby: Difference between revisions

From Rosetta Code
Content added Content deleted
No edit summary
Line 18: Line 18:
Direction commands:<pre>north, south, east, west, up, down</pre>Type these in order to go in a certain direction. There must be a hole in the wall in that direction. All directions are aliased by their first letter (ie. you can go south by just typing s). In order to go up, you must have a ladder in your current room. In order to go down, the room below you must have a ladder in it.
Direction commands:<pre>north, south, east, west, up, down</pre>Type these in order to go in a certain direction. There must be a hole in the wall in that direction. All directions are aliased by their first letter (ie. you can go south by just typing s). In order to go up, you must have a ladder in your current room. In order to go down, the room below you must have a ladder in it.


Attack:<pre>attack &lt;''direction''&gt;</pre>Break a hole in the wall in the specified direction. You must have a sledge equipped to do this.
Attack:<pre>attack &lt;direction&gt;</pre>Break a hole in the wall in the specified direction. You must have a sledge equipped to do this.


Take/Drop:<pre>take &lt;item&gt;
Take/Drop:<pre>take &lt;item&gt;

Revision as of 04:47, 28 April 2010

RCRPG/Ruby is part of RCRPG. You may find other members of RCRPG at Category:RCRPG.

This Ruby version of RCRPG implements a text interface.

Language Idioms

This program illustrates some of the interesting aspects of Ruby:

  • object-oriented programming
  • open classes
  • regular expression matching
  • built-in data structures: hashes and arrays
  • higher-order functions like map and select, using blocks

Objective

The objective of the game is to find your way to the exit (which is located at 1, 1, 5).

Commands

Direction commands:

north, south, east, west, up, down

Type these in order to go in a certain direction. There must be a hole in the wall in that direction. All directions are aliased by their first letter (ie. you can go south by just typing s). In order to go up, you must have a ladder in your current room. In order to go down, the room below you must have a ladder in it. Attack:

attack <direction>

Break a hole in the wall in the specified direction. You must have a sledge equipped to do this. Take/Drop:

take <item>
drop <item>

Pick up an item in the room, or drop an item from your inventory. View Inventory:

inventory

Equip an item:

equip <item>

Create an alias:

alias <old command> <new command>

Make it so that whenever you type new command it means the same thing as old command.

Code

<lang ruby>require 'matrix'

class Vector

 # add a pretty method to Vector for serialization
 def pretty
   @elements.join(",")
 end

end

class Room

 attr_accessor :name, :items, :links
 def initialize name, items, *links
   @name, @items, @links = name, items, links
 end

end

Directions = {

 "north" => Vector[ 0,  1,  0],
 "south" => Vector[ 0, -1,  0],
 "east"  => Vector[ 1,  0,  0],
 "west"  => Vector[-1,  0,  0],
 "up"    => Vector[ 0,  0,  1],
 "down"  => Vector[ 0,  0, -1]

}

Items = [:sledge, :ladder, :gold]

$aliases = {

 "n" => "north",
 "s" => "south",
 "e" => "east",
 "w" => "west",
 "u" => "up",
 "d" => "down",
 "i" => "inventory",
 "inv" => "inventory",
 "a" => "attack",
 "q" => "quit"

}

$player = {

 :inventory => {
   "ladder" => 0,
   "sledge" => 0,
   "gold" => 0
 },
 :equipped => nil,
 :position => Vector[0, 0, 0]

}

$rooms = {

 "0,0,0" => Room.new("start", [:sledge])

}

  1. creates a new room in the world

def create_room where, from

 random_items = Items.select { rand > 0.75 }
 $rooms[where] = Room.new(where, random_items, from)
 $rooms[from].links << where

end

  1. returns the room that the player is currently in

def current_room

 $rooms[$player[:position].pretty]

end

  1. action - displays the characters inventory

def inventory

 puts "You have:"
 non_empty = $player[:inventory].select { |obj, q| q > 0 }
 if non_empty.empty?
   puts "- nothing."
 else
   non_empty.each do |item, quantity|
     if quantity > 1
       puts "- #{item} x #{quantity}"
     else
       puts "- #{item}"
     end
   end
 end
 
 if $player[:equipped]
   puts "Equipped: #{$player[:equipped]}"
 end

end

  1. action - move in a certain direction

def move dir

 if !Directions.key?(dir)
   puts "Unknown direction '#{dir}'."
   return
 end
 new_pos = $player[:position] + Directions[dir]
 target_room  = $rooms[new_pos.pretty]
 if !current_room.links.include?(new_pos.pretty)
   puts "You can't go that way."
 elsif dir == "up" and !current_room.items.include?(:ladder)
   puts "You can't go up without a ladder in the room."
 elsif dir == "down" and !target_room.items.include?(:ladder)
   puts "You can't go down that way, there is no ladder in that room."
 else
   $player[:position] = new_pos
   if new_pos.pretty == "1,1,5"
     puts "You win!"
     exit
   end
 end

end

  1. action - pick up an item off the floor

def take what

 if current_room.items.include?(what.to_sym)
   $player[:inventory][what] += 1
   current_room.items.delete what.to_sym
   puts "Picked up the #{what}."
 else
   puts "There is no #{what} in this room."
 end

end

  1. action - equip something

def equip what

 what = what.to_s.downcase
 if !%w[sledge].include?(what)
   puts "You can't equip a #{what}."
 elsif $player[:inventory].key?(what) and $player[:inventory][what] > 0
   puts "You have equipped the #{what}."
   $player[:equipped] = what
 else
   puts "You don't have any #{what}s."
 end

end

  1. action - attack in a certain direction

def attack dir

 if !Directions.key?(dir)
   puts "Unknown direction '#{dir}'."
   return
 end
 target_pos = ($player[:position] + Directions[dir]).pretty
 if $player[:equipped] != "sledge"
   puts "You must equip a sledge to attack."
 elsif current_room.links.include?(target_pos)
   puts "There is already a pathway in that direction."
 else
   puts "You create a path #{dir}."
   if $rooms.key?(target_pos)
     $rooms[target_pos].links << $player[:position].pretty
     current_room.links << target_pos
   else
     create_room target_pos, $player[:position].pretty
   end
   # see if sledge breaks
   if rand < 0.1
     puts "Your sledge has broken."
     $player[:inventory]["sledge"] -= 1
     $player[:equipped] = nil
   end
 end

end

  1. action - drop an item

def drop what

 what = what.to_s.downcase
 if !%w[sledge ladder gold].include?(what)
   puts "You can't drop a #{what}."
 elsif $player[:inventory].key?(what) and $player[:inventory][what] > 0
   puts "You have dropped a #{what}."
   $player[:inventory][what] -= 1
   current_room.items << what.to_sym
 else
   puts "You don't have any #{what}s."
 end

end

  1. this is the main routine for processing a command typed into the game

def process_cmd cmd

 case cmd
 when "exit", "quit"
   exit
 when /^(#{Directions.keys.join "|"})$/
   move $1
 when /^attack (#{Directions.keys.join "|"})$/
   attack $1
 when /^drop ([\w\s]+)$/
   drop $1
 when /^take ([\w\s]+)$/
   take $1
 when "inventory"
   inventory
 when /^equip ([\w\s]+)$/
   equip $1
 when /^alias (\w+) (\w+)$/
   $aliases[$2] = $1
 else
   if $aliases.key? cmd[/^\w+/]
     process_cmd cmd.sub($~.to_s, $aliases[$~.to_s])
   else
     puts "Invalid command: '#{cmd}'"
   end
 end

end

  1. displays info about the room we are in

def display_info

 puts "You are at (#{$player[:position].pretty})."
 room = $rooms[$player[:position].pretty]
 if room.items.size > 0
   puts "You see: #{room.items.map(&:to_s).join(", ")}."
 end
 if room.links.size > 0
   puts "There are openings " + room.links.map { |link|
     link = Vector[*link.split(",").map(&:to_i)]
     Directions.index(link - $player[:position])
   }.join(", ") + "."
 end

end

  1. the main game loop

while true

 display_info
 print "> "
 process_cmd gets.chop.downcase

end</lang>