Beginner help - txt dungeon

Hi. I have tried to learn other programming languages before and ruby
was the first one that really stuck. Anyways, I own both Prgramming
Ruby & Beginning Ruby. The later has a tutorial for making a text
dungeon. I expanded the example in the book to accept commands from a
user and load new maps from a txt file. I am now trying to build in an
inventory system, and smashing my face into the rocks. I can’t even
come up with an acceptable way to do it. I also want my items to load
from a text file. My end goal is to have a text dungeon maker. Where
you have 2 or 3 text files (or even one I guess) that my engine will
create an entire dungeon from. Any help on an inventory system would be
great as I don’t even know where to start.

The rooms.txt is pretty simple syntax (if thats what I would call it).
On one line you put a room.

reference~ Name #The player sees this~description~ #The next 8 places
seperated by “~” are connections, they are split up into pairs and
stored in a hash. The first part of the pair is input from the user and
the second is returned.

Working example:

cavecell~ Cave cell~a small cell in the side of a cave wall. The gate
on the north side is open.~north~cellblocka1~south~n~east~n~west~n~

cellblocka1~ Cell Block A~a long corridor full of jail cells. To the
south is an open cell. The corridor runs east and west, and seems to go
on for quite
sometime.~north~n~south~n~east~cellblocka2~west~cellblocka0~

cellblocka2~ Cell Block A~a long corridor full of jail cells. The
corridor runs east and west, and seems to go on for quite
sometime.~north~n~south~n~east~cellblocka0~west~cellblocka1~

cellblocka0~ Cell Block A~a long corridor full of jail cells. The
corridor runs east and west, and seems to go on for quite
sometime.~north~n~south~n~east~cellblocka1~west~cellblocka2~

This just loops back on itself. An “n” returned is impassable.

I’m not familiar with the example you are following. However, you may
find my adventure game tutorial useful…?

http://www.bitwisemag.com/2/Adventures-In-Ruby
http://www.bitwisemag.com/2/Adventures-In-Ruby-Part-2
http://www.bitwisemag.com/2/Adventures-In-Ruby-Part-3

best wishes
Huw

SapphireSteel Software
Ruby and Rails In Visual Studio
http://www.sapphiresteel.com

Huw C. wrote:

I’m not familiar with the example you are following. However, you may
find my adventure game tutorial useful…?

http://www.bitwisemag.com/2/Adventures-In-Ruby
http://www.bitwisemag.com/2/Adventures-In-Ruby-Part-2
http://www.bitwisemag.com/2/Adventures-In-Ruby-Part-3

best wishes
Huw

SapphireSteel Software
Ruby and Rails In Visual Studio
http://www.sapphiresteel.com

Your tutorial looks interesting and easy to follow. I am going to work
my way through it over the next days. My program is attached to my
original post. Thanks for the help.

I read your comments and some questions did in fact come up. You
commented on my file opening system. I agree with your reasoning, as it
is very hard to work with. The reason I made it that way is because it
was simple to code. I do not know how I would seperate it the way you
suggested.

The next comment was on my find_room method.
“You are using an Array as a Hash. The following line could just be:”
@rooms[reference] # using a Hash”

I am confused by this. Maybe some more explaination. The next comments
are on my command system. I figured there had to be a much better way
to do this, but it was the first thing I had written without help or
examples. I however do not know what “case” means. A link to some
explanation might help. Your suggestions on the inventory definitely
helped keep my train of thought on the tracks that lead to resultopia.

On Feb 8, 2008, at 11:05 PM, Jonathon Hartoon wrote:

I have tried to learn other programming languages before and ruby
was the first one that really stuck.

Welcome to Ruby.

Anyways, I own both Prgramming Ruby & Beginning Ruby. The later has
a tutorial for making a text dungeon. I expanded the example in the
book to accept commands from a user and load new maps from a txt file.

Excellent work. Modifying code like this is a terrific first step.

I am now trying to build in an inventory system, and smashing my
face into the rocks. I can’t even come up with an acceptable way to
do it.

Actually, you are already very close…

Attachments:
http://www.ruby-forum.com/attachment/1409/Dungeon.rb

I’ve added some comments to try and give you new ideas. Read through
and see if I’ve helped. If not, come back with more questions.

We will get you there. Don’t give up! :wink:

James Edward G. II

def case_example(input)
case input
when “one”
1
when “two”
2
else
?> “unknown”

end
end
=> nil

case_example “one”
=> 1

case_example “two”
=> 2

case_example “three”
=> “unknown”

Hope that helps.

James Edward G. II

That is rather simple. Maybe I will leave the array being used as a
hash for another time. At the moments the funtionality remain intact.
Thx again for the help.

On Feb 11, 2008, at 7:17 PM, Jonathon Hartoon wrote:

I read your comments and some questions did in fact come up. You
commented on my file opening system. I agree with your reasoning,
as it
is very hard to work with. The reason I made it that way is because
it
was simple to code. I do not know how I would seperate it the way you
suggested.

It is a bit harder. Save that for when you have learned a bit more.

The next comment was on my find_room method.
“You are using an Array as a Hash. The following line could just be:”
@rooms[reference] # using a Hash”

I am confused by this. Maybe some more explaination.

class Room

?> end
=> nil

rooms = {:some_room => Room.new, :another_room => Room.new}
=> {:another_room=>#Room:0x58c0dc, :some_room=>#Room:0x58c0f0}

rooms[:some_room]
=> #Room:0x58c0f0

I however do not know what “case” means. A link to some
explanation might help.

def case_example(input)
case input
when “one”
1
when “two”
2
else
?> “unknown”

end
end
=> nil

case_example “one”
=> 1

case_example “two”
=> 2

case_example “three”
=> “unknown”

Hope that helps.

James Edward G. II

Looking through that, there are a few things that jump out:

  1. You’ve got a bunch of rooms that you reference by symbols, and you
    are storing them in an Array. You might want to look into changing
    this to a Hash keyed by the reference. This would change
    Dungeon#find_room from:

def find_room(reference)
@rooms.detect { |room| room.reference == reference }
end

to:

def find_room(reference)
@rooms[reference]
end

(Really, since find_room is only called within Dungeon, you can
probably do without the method in that case, and just replace
find_room(reference) calls with @rooms[reference])

  1. You are doing your own file handling, which may be a good way to
    learn Ruby’s generic file handling facilities. On the other hand, you
    may also want to try using the standard YAML library (discussed in
    Chapter 9 of Begging Ruby: From Novice to Professional) to store your
    rooms. It stores and loads arbitrary Ruby objects very simply in a
    format that is easy to create/edit by hand, and if you keep expanding
    what your program does (and what it loads and stores), it’ll be easier
    to expand than updating a custom format with each change.

  2. The Dungeon#command method uses a series of independent if
    statements, where only one of them can be true. There are several
    improvements possible with this. The smallest change would be to use
    an if […] elsif […] elsif […] end idiom instead of if […] end
    if […] end etc. The next would be to use a case statement, like
    this:
    case input
    when “west”

    when “east”

    when “north”

    when “south”

    when “look”

    when “inventory”

    end

You could also consider, though this is more advanced, having a
@commands instance variable that is a Hash keyed by the name of
commands with values that are procs that are called for each command.
Then to process a command, you could just do @commands[command].call.

  1. Your initialize method for Dungeon calls create and run at the end.
    You might want think about to pulling those out of initialize, and
    letting “create” take a parameter identifying the file name to use.
    Then you would use Dungeon.new.create(“file.txt”).run to load and run
    a dungeon. Only do this if you might ever want to create a blank
    dungeon without loading structure from a file, or to load the
    structure without running the dungeon.

On Feb 16, 9:22 am, Christopher D. [email protected] wrote:

Looking through that, there are a few things that jump out:

  1. You’ve got a bunch of rooms that you reference by symbols, and you
    are storing them in an Array. You might want to look into changing
    this to a Hash keyed by the reference.
    […]

Actually, an array makes sense to me. Can you explain the advantages
of a Hash? With an array, the array can later be made to a Singleton
which could be iterated through.

-Thufir

On Sat, 09 Feb 2008 14:05:25 +0900, Jonathon Hartoon wrote:

I am now trying to build in an
inventory system, and smashing my face into the rocks.

Well, one approach would be to use a database. By using a db from the
get go you get the advantage of, well, organizing your data. Then, you
just connect to the db.

If you’re using text files that’s more fragile because one small change
will cause other things to break.

I kinda, sorta, had thoughts along your line for a game, but was using
_why’s poignant ruby for inspiration :slight_smile:

It’s a bit rough (I don’t do anything with the creatures once they’re
created), but the db part, for me, looks like:

require ‘rubygems’
require ‘fileutils’
require ‘active_record’
require ‘creature’
require ‘dragon’
require ‘instantiate’
include Instantiate

system(“rm dwemthys.db”)

ActiveRecord::Base.logger = Logger.new(STDERR)
ActiveRecord::Base.colorize_logging = true

ActiveRecord::Base.establish_connection(
:adapter => “sqlite3”,
:dbfile => “dwemthys.db”
)

ActiveRecord::Schema.define do
create_table :creatures do |table|
table.column :type, :string
table.column :life, :integer
table.column :strength, :integer
table.column :charisma, :integer
table.column :weapon, :integer
end
end

99.times do |index|
creature = Instantiate.randomCreature
p creature
creature.save
end

http://dwemthys.googlecode.com/svn/trunk/db_crud_create.rb

HTH,

Thufir

On Feb 16, 10:03 pm, “Christopher D.” [email protected] wrote:

Since the main use is lookup by reference, and hash is designed for
keyed access, hash would seem to be the natural container to use. I’m
not sure I quite get what you are saying about iterating through a
singleton instead, could you explain a little more?
[…]

There’s one set of rooms, which may have sub-sets, of course. But,
for the set of rooms you may want to iterate through each room for
whatever reason. Putting the rooms into a Singleton allows such
iteration in an inherently thread-safe way.

Admittedly, I don’t really understand Hash that well.

-Thufir

On 15/02/2008, Thufir [email protected] wrote:

system(“rm dwemthys.db”)

do you really want to call ‘system’, which calls a shell, which executes
the
‘rm’ program?
Why not just use File.unlink()?

-Thomas


Thomas P.
[email protected]
[email protected]
Büro: 030 - 830 353 88
mobil: 0176 - 75 03 03 04
Privat: 030 - 49 78 37 06

http://www.thopre.com/

Since the main use is lookup by reference, and hash is designed for
keyed access, hash would seem to be the natural container to use. I’m
not sure I quite get what you are saying about iterating through a
singleton instead, could you explain a little more?

On Feb 17, 2008 5:48 PM, Thufir [email protected] wrote:

iteration in an inherently thread-safe way.
I’m not sure I follow you. As far as I understand it, singletons
refer to templates (the singleton classes) that allow instances of a
class to have unique behavior if need be. It seems to me that
instances of a Room would not need that. The only way I can currently
imagine why one would need that is if the behavior of a single
instance of a room changes during runtime.

Admittedly, I don’t really understand Hash that well.

It’s just key/value pairs (where the key or the value can be any
object).

Todd

On Feb 20, 2008, at 2:19 PM, Thomas P. wrote:

do you really want to call ‘system’, which calls a shell, which
executes the
‘rm’ program?
Why not just use File.unlink()?

whats the difference between File.delete and File.unlink?

_______________________________|

  • Ari
    I just bought another case of RockStar. Expect architectural changes.

On Thu, Feb 21, 2008 at 8:10 AM, fedzor [email protected] wrote:

whats the difference between File.delete and File.unlink?

None: they are defined to refer to the same function in the code:
rb_define_singleton_method(rb_cFile, “unlink”, rb_file_s_unlink,
-2);
rb_define_singleton_method(rb_cFile, “delete”, rb_file_s_unlink,
-2);

Aliased, if you like. Still, `unlink’ is the preferred terminology, I
think.
(besides, that’s the name used for the C function [rb_file_s_unlink])

Arlen

On Thu, 21 Feb 2008 06:41:54 +0900, Huw C. wrote:

at: ‘Your destination’ put: ‘Mornington Crescent’.
Yes, that’s much more readable than mapping integers around :slight_smile:

Ok, I’m starting to see the advantages to Hash!

-Thufir

I understand your thoughts about singletons. In a sense, each game might
be represented by a singleton. In my own simple Ruby adventure game
system (mentioned earlier in this thread) I have three classes -
Adventure (the game itself), Implementor (the thing that ‘controls’ the
nitty-gritty details of the game) and the Map - all of which have only
one instance. I haven’t myself implemented them as singletons as I
couldn’t see any obvious benefit in doing so and I tend to think that
singletons reduce the clarity of the class hiererchy so I don’t use them
habitually.

I have also opted for an array for simplicity. A map can easily be
created by having numbered rooms and attributes indicting the rooms to
which they adjoin e.g.

1 – 2
|
3 – 4

In the above, room 1’s east attribute is 2, its south attribute is 3
etc.

The attraction of a hash is that the key would not need to be a number -
it could actually the name of a room { :east => :dungeon, :south =>
:cave } and so on.

In fact, I wrote a simple example of a game framework in Smalltalk that
uses exactly this method:

map at: ‘Station 1’ put: ‘Belsize Park’;
at: ‘Station 2’ put: ‘Chalk Farm’;
at: ‘Station 3’ put: ‘Camden Town’;
at: ‘Your destination’ put: ‘Mornington Crescent’.

http://www.bitwisemag.com/copy/programming/smalltalk/smalltalk2.html

This has some attractions of readability (names not numbers) but I’m not
really convinced it is more practical than a simple indexed array. The
secret is to draw out a map on a sheet of paper first, give all the
rooms numbers, draw lines showing the exits and then create the array
with all the correct numbers as attributes to show which room number is
in which direction.

best wishes
Huw

SapphireSteel Software
Ruby and Rails In Visual Studio
http://www.sapphiresteel.com

On Feb 22, 2008, at 3:52 AM, Thufir wrote:

overly complicating what’s meant to be an exercise).
If you’re using a hash, put whatever exits you want! use the user’s
input as a basis for indexing the hash.

Don’t necessarily make different rooms under different classes for
dealing with exits only. Use different classes for things like…
gravity…

Ari
-------------------------------------------|
Nietzsche is my copilot

On Thu, 21 Feb 2008 06:41:54 +0900, Huw C. wrote:

This has some attractions of readability (names not numbers) but I’m not
really convinced it is more practical than a simple indexed array. The
secret is to draw out a map on a sheet of paper first, give all the
rooms numbers, draw lines showing the exits and then create the array
with all the correct numbers as attributes to show which room number is
in which direction.

Well, just thinking aloud:

There may be different worlds/planets dimensions in the game. So that
maybe you might have (forgive my poor ruby syntax pls):

class earthRoom < room
def special_earth_method
end
end

and then a marsRoom class, etc?

You wouldn’t want to be able to go from an earthRoom to marsRoom under
normal circumstances, I expect.

Also, some rooms might have north, south, east, west but other rooms
might have no directions, but perhaps a secret door, or “pull
candlestick” or “go out” or similar.

While the intention at this stage is to get something workable, I, for
one, would like to know how to keep options open down the road (without
overly complicating what’s meant to be an exercise).

-Thufir