13 Oct, 2009, Chris Bailey wrote in the 1st comment:
Votes: 0
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.

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
13 Oct, 2009, David Haley wrote in the 2nd comment:
Votes: 0
What exactly is the question here? What are the kinds of problems you've consistently run into?
13 Oct, 2009, Chris Bailey wrote in the 3rd comment:
Votes: 0
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?
13 Oct, 2009, David Haley wrote in the 4th comment:
Votes: 0
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.
13 Oct, 2009, Chris Bailey wrote in the 5th comment:
Votes: 0
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.
13 Oct, 2009, Chris Bailey wrote in the 6th comment:
Votes: 0
Non tested, but I think this will have that effect.

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
13 Oct, 2009, Scandum wrote in the 7th comment:
Votes: 0
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: \eYou 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.
13 Oct, 2009, Chris Bailey wrote in the 8th comment:
Votes: 0
Scandum - Will do
14 Oct, 2009, David Haley wrote in the 9th comment:
Votes: 0
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?
14 Oct, 2009, Runter wrote in the 10th comment:
Votes: 0
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.
14 Oct, 2009, Chris Bailey wrote in the 11th comment:
Votes: 0
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 =(
14 Oct, 2009, Runter wrote in the 12th comment:
Votes: 0
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.
14 Oct, 2009, Chris Bailey wrote in the 13th comment:
Votes: 0
Oh yeah! Runter - I've been out of it for awhile, I forget things easily :P
14 Oct, 2009, David Haley wrote in the 14th comment:
Votes: 0
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?!

15 Oct, 2009, Chris Bailey wrote in the 15th comment:
Votes: 0
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.
15 Oct, 2009, David Haley wrote in the 16th comment:
Votes: 0
Do you mean having a linear list of extras, that you'd have to scan when displaying each cell? That seems rather inefficient; you'd be better off with a mapping from cell to extra(s) on that cell. Still, even that can be inefficient if you have enough cells with extras; having a pointer to extras could be better if you have enough.
0.0/16