Created
May 24, 2010 17:50
-
-
Save tanzeeb/412189 to your computer and use it in GitHub Desktop.
RPCFN #9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Action | |
attr_accessor :name, :terms, :code | |
def initialize name | |
@name = name | |
@terms = [] | |
end | |
def setup attribute, *args | |
case attribute | |
when :terms | |
@terms += args.first.downcase.split(', ') | |
when :code | |
@code = args.first | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Helper | |
def ended? | |
blackboard[:finished] | |
end | |
def player_in? room | |
current_room.name == room | |
end | |
def player_has? item | |
inventory.include? item | |
end | |
def player_has_nothing? | |
inventory.empty? | |
end | |
def player_inventory | |
Item.list @items.values_at(*inventory) | |
end | |
def room_has? item | |
current_room.items.include? item | |
end | |
def room_inventory | |
Item.describe @items.values_at(*current_room.items) | |
end | |
def room_description | |
[ current_room.description, room_inventory ].join("\n") | |
end | |
def room_summary | |
[ | |
current_room.describe, | |
current_room.visited ? nil : room_inventory | |
].compact.join("\n") | |
end | |
def room_exit? direction | |
current_room.exit? direction | |
end | |
def entrance_room | |
@rooms.values.select do |room| | |
eval( room.exit?(:enter).last ).first | |
end.compact.first | |
end | |
def current_room | |
blackboard[:current_room] | |
end | |
def inventory | |
blackboard[:inventory] | |
end | |
def item_name term | |
Item.find(@items,term) | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Item | |
attr_accessor :name, :terms, :description | |
def initialize name | |
@name = name | |
end | |
def self.list items | |
items.collect { |item| item.terms.first }.join("\n") | |
end | |
def self.describe items | |
items.collect { |item| item.description }.join("\n") | |
end | |
def self.find items, term | |
return if term.empty? || items.empty? | |
items.collect do |name,item| | |
name unless item.terms.grep(/#{term}/i).empty? | |
end.compact.first | |
end | |
def setup attribute, *args | |
case attribute | |
when :description | |
@description = args.compact.join(" ") | |
when :terms | |
@terms = args.first.split(', ') | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Loader | |
TOKENS = [ | |
[/^(\S+)\s?(\S*):/, | |
'"setup :#{$1.downcase}, \"#{$2}\" do |entity|"'], | |
[/^(\s*)$/, | |
'"\n entity\nend\n\n"'], | |
[/^\s{2}(\S+):\s*(.*)$/, | |
'"\n entity.setup :#{$1.downcase}, #{$2.empty? ? "nil" : "\"#{$2}\""}"'], | |
[/^\s*\{\{\{$/, | |
'".to_s + [ nil"'], | |
[/^\s*\}\}\}$/, | |
'"].compact.join(\"\\\n\")"'], | |
[/^\s{4}(.+)$/, | |
'", %`#{$1}`"'] | |
] | |
def load story_path | |
story_file = File.open(story_path).read.chomp.concat("\n ") | |
transform story_file | |
end | |
def transform story | |
story.split("\n").collect do |line| | |
TOKENS.collect do |pattern,replacement| | |
eval replacement if line =~ pattern | |
end.compact.first | |
end.join("") | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
$LOAD_PATH << File.expand_path(File.dirname(__FILE__)) | |
require 'loader' | |
require 'world' | |
class Game | |
include Loader | |
attr_accessor :world | |
def initialize(story_path, options={}) | |
@input = options.fetch(:input) { $stdin } | |
@output = options.fetch(:output) { $stdout } | |
@world = World.new load(story_path) | |
end | |
def play! | |
start! | |
execute_one_command! until ended? | |
end | |
def start! | |
@output.puts @world.start | |
@output.print "> " | |
end | |
def execute_one_command! | |
input = @input.gets | |
output = @world.execute!(input) | |
@output.puts output unless output.empty? | |
@output.print "> " unless ended? | |
end | |
def ended? | |
@world.ended? | |
end | |
end | |
if $PROGRAM_NAME == __FILE__ | |
story_path = ARGV[0] | |
unless story_path | |
warn "Usage: #{$PROGRAM_NAME} STORY_FILE" | |
exit 1 | |
end | |
game = Game.new(story_path) | |
game.play! | |
end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'action' | |
module Player | |
[:north,:south,:east,:west,:enter,:exit].each do |direction| | |
define_method :"do_#{direction}" do |*args| | |
room, guard = room_exit? direction | |
allowed, message = eval guard | |
[ | |
message && message.empty? ? nil : message, | |
allowed ? { | |
:move_to => room, | |
:finished => direction == :exit | |
} : {} | |
] | |
end | |
end | |
def do_look *args | |
[ room_description, {} ] | |
end | |
def do_take *args | |
name = item_name args.join(" ") | |
room_has?(name) ? [ "OK", {:add_inventory => name} ] : [nil,{}] | |
end | |
def do_drop *args | |
name = item_name args.join(" ") | |
player_has?(name) ? [ "OK", {:remove_inventory => name} ] : [nil,{}] | |
end | |
def do_inventory *args | |
[ | |
player_has_nothing? ? "You're not carrying anything" : player_inventory, | |
{} | |
] | |
end | |
def do_quit *args | |
[nil, {:finished => true}] | |
end | |
def add_action action | |
action.terms.each do |term| | |
self.class.send(:define_method, :"do_#{term}") { eval action.code } | |
end | |
end | |
def add_synonyms attribute, args | |
args.each do |synonym| | |
self.class.send(:alias_method, :"do_#{synonym}", :"do_#{attribute}") | |
end | |
end | |
def method_missing method, *args | |
args.empty? ? [nil, {}] : self.send(:"#{method} #{args.shift}", *args) | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Room | |
attr_accessor :name, :title, :description, :exits, :items, :visited | |
GUARDS = { | |
:default => '[true,nil]', | |
:none => '[false,"There is no way to go in that direction"]' | |
} | |
def initialize name | |
@name = name | |
@exits = {} | |
@items = [] | |
@visited = false | |
end | |
def visit! | |
@visited = true | |
end | |
def describe | |
@visited ? "You're #{title}." : description | |
end | |
def exit? direction | |
@exits[direction] || [nil, GUARDS[:none]] | |
end | |
def setup attribute, *args | |
case attribute | |
when :title, :description | |
send :"#{attribute}=", args.compact.join(" ") | |
when :exits | |
args.compact.each do |arg| | |
direction, location = arg.split(' to ') | |
room, guard = location.split(' guarded by:') | |
@exits[direction.to_sym] = [ room, guard || GUARDS[:default] ] | |
end | |
when :objects | |
@items += args.compact | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'room' | |
require 'item' | |
require 'action' | |
require 'helper' | |
require 'player' | |
class World | |
include Helper | |
include Player | |
attr_accessor :rooms, :items, :blackboard | |
def initialize story | |
@blackboard = { :inventory => [] } | |
@rooms = {} | |
@items = {} | |
eval story | |
end | |
def start | |
update! :move_to => entrance_room.name | |
end | |
def execute! command | |
method, args = command.split(' ') | |
message, changes = send("do_#{method}".to_sym, args) | |
[ | |
message, update!(changes) | |
].flatten.compact.join("\n") | |
end | |
def update! changes | |
messages = [] | |
blackboard.merge!(changes) | |
if move_to = blackboard.delete(:move_to) | |
blackboard[:current_room] = @rooms[move_to] | |
messages << room_summary | |
current_room.visit! | |
end | |
if item = blackboard.delete(:add_inventory) | |
blackboard[:inventory] << current_room.items.delete(item) | |
end | |
if item = blackboard.delete(:remove_inventory) | |
blackboard[:current_room].items << inventory.delete(item) | |
end | |
messages | |
end | |
def setup entity_type, name | |
case entity_type | |
when :room | |
@rooms[name] = yield Room.new(name) | |
when :object | |
@items[name] = yield Item.new(name) | |
when :action | |
add_action yield(Action.new(name)) | |
when :synonyms | |
yield self | |
else | |
add_synonyms entity_type, name.split(', ') | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment