MudBytes
» MUDBytes Community » Language Discussions » Ruby » Need some refactoring help.
Pages: << prev 1, 2 next >>
Need some refactoring help., Simple mapping system.
Chris Bailey
Wizard




Group: Members
Posts: 602
Joined: Sep 13, 2008

Go to the bottom of the page Go to the top of the page
#1 id:36272 Posted Oct 13, 2009, 5:05 pm

So, I've made about a million mapping systems now, and I've run into the same problems with each one. I've decided that it might help if I make this one as efficient as possible as I go along, instead of trying to "fix" it afterwards. So, the only thing this has in place is a basic structure for the "dungeon/area", an some basic structures for each "room/sector" in the dungeon. It does not take into account the display of players, npcs or items.

Code (text):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
 
MAP_WIDTH  = 15  # The width of the map.
MAP_HEIGHT = 15  # The height of the map.
 
# Basic sector type.
class DungeonSector
  attr_accessor :passable, :view, :type
  def initialize
    @passable = true   # Can you walk across this sector?
    @view     = " "    # How the sector is displayed.
  end
end
 
# A floor sector
class FloorSector < DungeonSector
  def initialize(type=:cement)
    @type     = type   # A generic type.
    @view     = case type
    when :cement
      "."
    end
  end
end
 
# A wall sector
class WallSector < DungeonSector
  def initialize(type=:cement)
    @passable = false
    @type     = type
    @view     = case type
    when :door
      "$"
    when :cement
      "#"
    end
  end
end
 
# The dungeon structure.
class Dungeon
  attr_accessor :map, :name, :level
  def initialize
    @map   = Array.new(MAP_WIDTH) { Array.new(MAP_HEIGHT)}    # A 2D Array
    @name  = "New Dungeon"    # The name of the dungeon.
    MAP_HEIGHT.times do |y|
      MAP_WIDTH.times do |x|
        @map[x][y] = FloorSector.new
      end
    end
  end
 
  def view
    buf = String.new     # A buffer to hold the string.
    # Iterates through the 2 dimensional array "map" and dumps the "view"
    # of each sector, in order, into the buffer.
    15.times do |y|
      buf << "\r\n" if y > 0
      15.times do |x|
        buf << @map[x][y].view
      end
    end
    return buf  # Return the string created from the map.
  end
end
 
.........................
If what Proust says is true, that happiness is the absence of fever, then I will never know happiness. For I am possessed by a fever for knowledge, experience, and creation.

David Haley
Wizard






Group: Members
Posts: 6,874
Joined: Jun 30, 2007

Go to the bottom of the page Go to the top of the page
#2 id:36273 Posted Oct 13, 2009, 5:10 pm

What exactly is the question here? What are the kinds of problems you've consistently run into?
.........................
-- d.c.h --
BabbleMUD Project (custom codebase)
Legends of the Darkstone (head coder)
http://david.the-haleys.org
.........................

Chris Bailey
Wizard




Group: Members
Posts: 602
Joined: Sep 13, 2008

Go to the bottom of the page Go to the top of the page
#3 id:36274 Posted Oct 13, 2009, 5:13 pm

I should have elaborated on that. I was just seeing if there was any particular problem with this portion before I delved into the real issues. The first problem that comes to mind is when adding color to the "view" of each sector. It will change a string like ".", into "#w.". This seems like a non-issue at first, but even with a map size of 15x15, this quickly turns into a string of 15*15*3 (675) characters. Since this map is displayed to EACH player, EVERY time they move or type look, it gets to be a lot. Especially if I decide to increase the size of the map. I came up with a way of causing color to bleed across identically colored sectors, but it was a hack. Any advice on how to handle this large strings properly?
.........................
If what Proust says is true, that happiness is the absence of fever, then I will never know happiness. For I am possessed by a fever for knowledge, experience, and creation.

David Haley
Wizard






Group: Members
Posts: 6,874
Joined: Jun 30, 2007

Go to the bottom of the page Go to the top of the page
#4 id:36275 Posted Oct 13, 2009, 5:21 pm

It's hard to talk about general problems without having the whole context.

Do you display the entire map each time, or only a window onto it?
If it's the entire map, things are easier because you can make a pass on it (preprocessing it if you will) and do "line-length compression" on the colors. In other words, when the color changes, store a color code at that point, and don't store another one until (a) the line ends or (b) the color changes.

If you're doing a window at a time, you can't do the one-time pass approach (unless I suppose you store the compressed window for each possible window, but that can be silly depending on how big your world is and how many possible windows there are). It would still be pretty easy to only emit a color code if you need to, for example by simply keeping track of the previous color on this line and emitting if and only if the new tile's color is different. This will be only marginally more CPU intensive (it's just comparisons, after all!) but will give you the same memory savings.
.........................
-- d.c.h --
BabbleMUD Project (custom codebase)
Legends of the Darkstone (head coder)
http://david.the-haleys.org
.........................

Chris Bailey
Wizard




Group: Members
Posts: 602
Joined: Sep 13, 2008

Go to the bottom of the page Go to the top of the page
#5 id:36276 Posted Oct 13, 2009, 5:28 pm

DH - I am processing the entire map for each view. I had considered processing only what the player has "seen" so far, but with such a small map, what's the point? I suppose I could put that color hack back in, it did make a difference. Let me put it in there and see what ya think.
.........................
If what Proust says is true, that happiness is the absence of fever, then I will never know happiness. For I am possessed by a fever for knowledge, experience, and creation.

Chris Bailey
Wizard




Group: Members
Posts: 602
Joined: Sep 13, 2008

Go to the bottom of the page Go to the top of the page
#6 id:36278 Posted Oct 13, 2009, 5:46 pm

Non tested, but I think this will have that effect.

Code (text):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
def view
    buf = String.new     # A buffer to hold the string.
    # Iterates through the 2 dimensional array "map" and dumps the "view"
    # of each sector, in order, into the buffer.
    last_color = @map[0][0].view[0..1]
    15.times do |y|
      buf << "\r\n" if y > 0
      15.times do |x|
        if @map[x][y].view[0..1] == last_color
          buf << @map[x][y].view[2]
        else
          last_color = @map[x][y].view[0..1]
          buf << @map[x][y].view
        end
      end
    end
 
.........................
If what Proust says is true, that happiness is the absence of fever, then I will never know happiness. For I am possessed by a fever for knowledge, experience, and creation.

Scandum
Wizard






Group: Members
Posts: 1,400
Joined: Aug 8, 2006

Go to the bottom of the page Go to the top of the page
#7 id:36280 Posted Oct 13, 2009, 6:16 pm

You can probably further optimize the color compression. You can keep track of the bold/dim status, and if the status is dim, and you want to change the color from dim blue to dim green, all you need is: \e[32m rather than: \e[0;32m or some muds going as far as: \e[0;32;40m.

Given you seem to use some kind of internal color code system, I'd suggest getting rid of the hack and writing a decent low level color translator that handles compression, so it can be reused by other functions.
.........................
TinTin++ Mud Client - I can't believe it's not butter!

Chris Bailey
Wizard




Group: Members
Posts: 602
Joined: Sep 13, 2008

Go to the bottom of the page Go to the top of the page
#8 id:36281 Posted Oct 13, 2009, 6:25 pm

Scandum - Will do
.........................
If what Proust says is true, that happiness is the absence of fever, then I will never know happiness. For I am possessed by a fever for knowledge, experience, and creation.

David Haley
Wizard






Group: Members
Posts: 6,874
Joined: Jun 30, 2007

Go to the bottom of the page Go to the top of the page
#9 id:36285 Posted Oct 13, 2009, 10:18 pm

At some point, being overly clever here can be offset by the relatively simple (and with plenty of benefits elsewhere) addition of MCCP. If you're going to compress, you might as well just compress. It probably won't be as good as a very specialized color compression algorithm, but it'll affect the entire MUD, and might add up to far more savings in the long run. You can combine it with a relatively straightforward color compression algorithm, too.

Now that we've "solved" this issue :wink: what are some of the others you were running into?
.........................
-- d.c.h --
BabbleMUD Project (custom codebase)
Legends of the Darkstone (head coder)
http://david.the-haleys.org
.........................

Runter
Wizard






Group: Members
Posts: 1,850
Joined: Jun 1, 2006

Go to the bottom of the page Go to the top of the page
#10 id:36287 Posted Oct 13, 2009, 10:26 pm

Chris Bailey said:
I should have elaborated on that. I was just seeing if there was any particular problem with this portion before I delved into the real issues. The first problem that comes to mind is when adding color to the "view" of each sector. It will change a string like ".", into "#w.". This seems like a non-issue at first, but even with a map size of 15x15, this quickly turns into a string of 15*15*3 (675) characters. Since this map is displayed to EACH player, EVERY time they move or type look, it gets to be a lot. Especially if I decide to increase the size of the map. I came up with a way of causing color to bleed across identically colored sectors, but it was a hack. Any advice on how to handle this large strings properly?


I thought this same exact discussion took place 6 months ago? :P  (Even with solutions specifically with Ruby in mind.)

If you decide on using a string filter on your map output there are examples already posted on this forum.  In a Ruby specific implementation I would suggest using regular expression blocks or writing your own C iteration implementation to extend Ruby.  They're both very fast when compared to a pure Ruby implementation. 
.........................
CoralMud project

For once you have tasted flight Ruby you will walk the earth with your eyes turned skywards,
for there you have been and there you will long to return. --
                                              Leonardo Da Vinci Yukihiro Matsumoto

Last edited Oct 13, 2009, 10:33 pm by Runter
Chris Bailey
Wizard




Group: Members
Posts: 602
Joined: Sep 13, 2008

Go to the bottom of the page Go to the top of the page
#11 id:36288 Posted Oct 13, 2009, 10:34 pm

Runter - You are right, I completely forgot what came of it. =(

DH - The next issue involves tracking information about each room/sector on the map. There are a lot of small things I'm adding into this one like doors, traps, things that may be climbed or jumped over, etc.. I'm not sure if I should store all of this information inside each sector, or perhaps just store the coordinates of these special things in on the map itself and overlay it? I know it sounds odd, I just want to make this as efficient as possible, the whole map thing is just a huge resource vacuum for me =(
.........................
If what Proust says is true, that happiness is the absence of fever, then I will never know happiness. For I am possessed by a fever for knowledge, experience, and creation.

Runter
Wizard






Group: Members
Posts: 1,850
Joined: Jun 1, 2006

Go to the bottom of the page Go to the top of the page
#12 id:36289 Posted Oct 13, 2009, 10:37 pm

Chris Bailey said:
Runter - You are right, I completely forgot what came of it. =(

DH - The next issue involves tracking information about each room/sector on the map. There are a lot of small things I'm adding into this one like doors, traps, things that may be climbed or jumped over, etc.. I'm not sure if I should store all of this information inside each sector, or perhaps just store the coordinates of these special things in on the map itself and overlay it? I know it sounds odd, I just want to make this as efficient as possible, the whole map thing is just a huge resource vacuum for me =(


Overlaying it isn't a bad idea, but I can tell you what is a bad idea:  Having tons of unused variables within pure Ruby.  That translates to a ton of inefficiency. 

But typically I think over thinking within a higher level language defeats the purpose of the language itself unless it's absolutely vital.  You might remember this thread.
.........................
CoralMud project

For once you have tasted flight Ruby you will walk the earth with your eyes turned skywards,
for there you have been and there you will long to return. --
                                              Leonardo Da Vinci Yukihiro Matsumoto

Last edited Oct 13, 2009, 10:40 pm by Runter
Chris Bailey
Wizard




Group: Members
Posts: 602
Joined: Sep 13, 2008

Go to the bottom of the page Go to the top of the page
#13 id:36290 Posted Oct 13, 2009, 10:45 pm

Oh yeah! Runter - I've been out of it for awhile, I forget things easily :P
.........................
If what Proust says is true, that happiness is the absence of fever, then I will never know happiness. For I am possessed by a fever for knowledge, experience, and creation.

David Haley
Wizard






Group: Members
Posts: 6,874
Joined: Jun 30, 2007

Go to the bottom of the page Go to the top of the page
#14 id:36307 Posted Oct 14, 2009, 12:23 pm

Runter correctly points out that you don't want lots of stuff hanging around even if null because that can be inefficient. For example, you wouldn't want an overlay per type of thing, nor would you want a slot for each type of thing on each sector type. The optimal solution depends on what exactly your constraints are: can multiple things be overlaid on a single square, or just one? How many of these do you have (what is their frequency)? Do they change? etc.

One thing you can do that would be not-horrible would be to have a single "extra data" on each sector type. This would be nil if there is no extra data, and point to some kind of object if there is data. If you can have several things on each square, it could have one slot per thing, or be a list of things. If you can only have one extra thing, it would be just the thing itself. This way, you save especially for the multiple-thing-case, because although you have a flat overhead on each sector, you only incur the extra overhead of storing the slots if you actually have stuff there.

You could also specialize your sector class to have a version with extra stuff and a version without extra stuff; this could let you eliminate the overhead entirely on squares that don't have extras. If the extras can move around, you will have to juggle between sector class types, which can be annoying and perhaps even defeat the purpose.

-------
Oh, and by the way... just to indulge in some silliness to mark the occasion......

Dav-eta! What does the scanner say about the post count?!

http://img49.imageshack.us/img49/6564/overfivethousand.jpg
.........................
-- d.c.h --
BabbleMUD Project (custom codebase)
Legends of the Darkstone (head coder)
http://david.the-haleys.org
.........................

Last edited Oct 14, 2009, 12:24 pm by David Haley
Chris Bailey
Wizard




Group: Members
Posts: 602
Joined: Sep 13, 2008

Go to the bottom of the page Go to the top of the page
#15 id:36321 Posted Oct 14, 2009, 9:09 pm

LOL @ 5000.

How about I just whip up a little method that will add and remove these "Extras" from an array in the sector. If there is nothing, the array will not exist, and it will grow as you add things to it. I could remove things in such a way as not to make the array sparse as things are moved around and stuff.
.........................
If what Proust says is true, that happiness is the absence of fever, then I will never know happiness. For I am possessed by a fever for knowledge, experience, and creation.

Pages:<< prev 1, 2 next >>
Tags
[+]

Valid XHTML 1.1! Valid CSS!