⚠️ Warning: This is a draft ⚠️
This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.
If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.
{{collection|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==
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]) } # 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 # returns the room that the player is currently in def current_room $rooms[$player[:position].pretty] end # 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 # 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 # 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 # 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 # 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 # 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 # 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 # 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 # the main game loop while true display_info print "> " process_cmd gets.chop.downcase end