Columned Displays?

Posted by Davion on Sun 23 Apr 2006 07:15 PM — 10 posts, 38,911 views.

Canada #0
Just wondering if you have a good way to column a list? Ie.

[ look] [ find] [ jog] [ jump]
[ scan] [ run] [ dash] [dance]


I've been trying to toy with for_each, but I can't quite figure it out.

Davion
USA #1
What you need to do is first figure out how many columns you will need/have. Then, for each column, you'd figure out what the widest element of that column is. Once you have that maximum width, you can print out each element to fit into that width. I'm not sure if for_each would actually work in this case, since you're not doing the same thing to each element.
Canada #2
*nodnod* Thanks! Actually kept toying with it after I posted and just finished :) Here's what I go


class cmdDisplay
{	int iLength;
	String str;
	public:
	cmdDisplay() : iLength(0) { str.Empty(); };
	void operator()(CmdType *cmmd )
	{	iLength++;
		cmmd->Display(str, iLength);
	}
	void SendCmds(Entity *en)
	{	en->Send("%s", *str);
	}
};

void Interpreter::doCmdList(Entity *en, String &arguments)
{	for_each(en->interp->cmdList.begin(),
		 en->interp->cmdList.end(),
		 cmdDisplay() ).SendCmds(en);
	return;
}
void CmdType::Display(String &rhs, int length)
{	char buf[10000];
	sprintf(buf, "[%-10s]", &(*name));
	rhs << buf;
	if( !(length % 4 ) ) rhs << "\n\r";
}




Excuse the horrible hacking of Display :) I haven't quite finished my string lib, so it's a bit... strange atm :). Seems to work very nicely though!

Davion
USA #3
Oh yeah. I forgot about function objects and how they let you do the "same" operation every time. *bonk self* I'm curious; have you tested it and is it working? Looks good to me... Of course, you're giving the same width to every column, which makes things easier.
Canada #4
Looks like it! The most any of my interpreters have is 4 commands, so I dropped columning down to two, and it worked fine!


command
[create ][setpasswd ]
[login ][command ]
>


The MudObject stuff in one of the prior threads helped a lot!

Davion
USA #5
Very good. The STL is really quite amazing when you look at it like this. Look at what you were able to do in so relatively few lines of code. Then think how much it would have been in straight C, and how less elegant it would have been. Bah! :-)

And yes, Nick's guides are excellent; very useful material. Some of them are for the intermediate-level coder, but if you know enough to understand the guides the potential for useful learning is immense.
Canada #6
Look at what you were able to do in so relatively few lines of code.

This statement really nudged me. Soo! I went for it

void doDisplay(CHAR_DATA *ch, char *argument)
{    std::list<CmdType *>::iterator i;
     char buf[MSL];
     for(int n = 0, i = ch->interp->begin(); i != ch->interp->end() ; ++i, ++n)
     { sprintf(buf, "[%-10s]", (*i)->name);
       send_to_char(buf,ch);
       if(!(n % 4) )
            send_to_char("\n\r", ch);
     }
}


Just typed that out dunno if it compiles, but that does the same thing in like 1/4 the lines of code. So. I figured, if I'm going to use this, I might as well make it worth while. I switched up my display function to->

template <class T>
class DisplayList
{	int iLength;
	String str;
	public:
	DisplayList() : iLength(0) { str.Empty(); };
	void operator()(T *node )
	{	iLength++;
		node->Display(str, iLength);
	}
	void Send(Entity *en)
	{	en->Send("%s", *str);
	}
};


Now, as long as the type class has a Display() method, it will display it. I understand it's dangerous to assume Display exists, but I don't think I'll be using this on classes where it lacks a Display method. This now seems a bit more practical, rather than writing a new one for each different kind of node.

Davion
Amended on Sun 23 Apr 2006 09:37 PM by Davion
Australia Forum Administrator #7
Very nice!

Strictly speaking, in this line:


cmdDisplay() : iLength(0) { str.Empty(); };


You don't need to do "str.Empty();", because when you define:


String str;


... the constructor is called which I assume initialises it to an empty string (it does for the string class, but you are using String).

However you are correct in initializing iLength because that is a "raw integer" (not a class) and hence is not initialized.

USA #8
I think I read somewhere that some implementations actually will initialize all member variables, including primitives like integers, when you call the new operator. After all, by definition, when you 'new' something, it will initialize all objects in there; I think somebody took that a step further and had it initialize the primitives as well. Since the default constructor for integers is zero, you'd end up with zeroes.

But that's probably non-standard behavior, so don't rely on it... :)
Quote:
I understand it's dangerous to assume Display exists, but I don't think I'll be using this on classes where it lacks a Display method
Oh, don't worry about that... the compiler will happily barf at you if you try to. :P
Canada #9
I think I read somewhere that some implementations actually will initialize all member variables, including primitives like integers, when you call the new operator. After all, by definition, when you 'new' something, it will initialize all objects in there; I think somebody took that a step further and had it initialize the primitives as well.

Never thought of that.


#include <iostream>

class Foo
{       public:
                int bar;
                Foo(){}
};


int main()
{       int i;
        Foo boo;
        std::cout << boo.bar << std::endl << i << std::endl;
        return -1;
}


Output


0
1073831104


Seems all those initializers are redundant! Thanks!

Davion