View Single Post
Old 12-05-2012, 12:00 AM   #2
camlorn
Member
 
Join Date: Aug 2011
Posts: 144
camlorn is on a distinguished road
Re: Really struggling with qsort (sorted areas list)

Well, problem is, we aren't on your codebase, but:

All right, before I start gicving out answers, you have one major problem. You have to be passing a parameter, unless this is c++--most mud codebases aren't, so I'm going to assume it isn't. What you have really isn't going to work, not easily--you can hack it together, but...I'll come back to that in a moment. This applies to diku derivatives, mostly. If you're using something else, you need to say what. No matter what you're using, please come back and say what.

Your first loop is almost correct, however, move the last line to be the third part of the for expression, as in:
for ( pArea1 = area_first; pArea1 != NULL ; pArea1 = pArea1->next )
{
if (pArea1->security>4)
count++;
}

The count++ only gets executed if security is greater than 4. In your old implementation, the mud would definitely crash if there was a security 4 area, as it would get stuck on it--because the advancing logic is in an else, the if becomes true (we're on a security 4 or greater area), the else doesn't get executed. The loop then happily goes around again, with the same pArea1, and does the same thing, never executing the reassignment. In c, = is legal anywhere, and I do mean anywhere: a=b=c is legal, but don't use it. if(a=b) is legal, setting a to whatever b is and making sure a is nonzeero, and a common trap is using = in if instead of ==. The third part of the for expression is to advance the loop. If you aren't assigning something to a variable (via the increment ++ or decrement -- operators, or the = sign), the loop won't "advance", and is likely to become infinite. Don't use the last line of the for loop for advancement even though you can, it will eventually cause you problems, and the for loop provides the third expression for that purpose.

Now, there's a couple problems I need to address before getting to the part about displaying and putting this in an array. Well, just one. But it's major.

To who?

Your function is taking no parameters. His wasn't really real code, it was more of an example. You need to make this a command: typically, you're going to have a function taking a CHAR_DATA* ch and a char* args...go look at another command, to see what the function needs to look like, and add an entry to the table in interp.c. It should look like this, most likely.
do_sortedareas(CHAR_DATA* ch, char* args)...
And a corrisponding entry in merc.h. I'd recommend going and writing a joke command, call it joke perhaps, that simply sends a message. The function you want is called send_to_char.

Now, this is where I get to discourage you with scary things. I suspect you don't know much c, as you said new and all, and you are jumping off a cliff by going straight to mud hacking. Good luck--this has been done before, but here's the scary stuff, and I see much wikipedia in your future. Have you worked through a good c tutorial? To the end? If not, go do that sometime (not necessarily now, and make sure it is *not* c++, though writing your mud in c++ instead is not a bad idea at all).

There's a thing. It's called a hashtable. Muds liked to use them, and this may not work. It probably will, but sometimes, the mud does stupid things like deciding that a linked list of 50 areas needs to be in a hashtable too. Your code will probably be the problem, but if you are absolutely, absolutely sure that your code is absolutely correct, it is possible that iterating through areas in the "expected" way isn't right for your codebase. You will know this is the problem if no matter what you do it abstanantly refuses to give all areas. Most codebases will allow this to work fine, but do be aware that it almost certainly won't work on rooms, mobs, or objects, because they are typically in the hashtable (It's that stuff, that scary stuff, probably in db.c, with the % operator, and a few other places). When this was first written, muds took up entire mainframes, and every single line had to be hand optimized, etc. Moving on now.

To put things in an array, first be aware that this is horrible. There is a reason I dislike c: we don't get the stl, which makes doing what you want to do maybe 3 lines. I could probably even do it in two. But they're cryptic-ish.

You must:
Make an array that is garenteed to be large enough to hold all areas always. Typically, you #define a MAX_AREAS in merc.h, somewhere in the thousands.
or:
Dynamically allocate an array with malloc.

For simplicity, we are going to assume that you are a sane person and that you don't care about the wasted space of the first approach.



First, you need a line like this:
AREA_DATA *sorted_areas[MAX_AREAS];

And this one for displaying later:
char* buf[MAX_STRING_LENGTH];
Both, probably, at the top of your function.

And then, instead of your counting loop, you need this, which is admittedly a bit scary. We're going to assume you've declared pArea1 at the top of your function, as well as count:
AREA_DATA *pArea1 = first_area;
int count = 0;
And the loop fragment.
for(;pArea1!=NULL;pArea1=pArea1->next) {
if(pArea1->security >= 4){
sorted_areas[count] = pArea1;
count++;
}
}

At this point, you've got a variable called count which is equal to the highest index in the array that contains an area (the actual count of areas is count+1--remember that arrays start at 0), an array with pointers to all your areaas, and the ability to sort. Add 1 to count:
count+1;
Call the sort function, as you did:
qsort(sorted_areas,
count,
sizeof(sorted_areas[0]),
compare_area);


Next, the displaying. This is actually simple, if you know about sprintf, which I shall not go into here. It would take up a lot of time, and google is your friend. So is sprintf, as a mud coder.

The lloop is simply something like.
for(int i = 0; i != count;i++) {
sprintf(buf, "name:%s minlevel:%i maxlevel:%i\n",
sorted_areas[i]->name, sorted_areas[i]->minlevel, sorted_areas[i]->maxlevel);
send_to_char(buf, ch);
}

I have not tested this, and leave it to you to put it together. Do note the following:
-without being a coder on your codebase, I can't test this anyway.
-I may have gotten send_to_char parameters backwards. I do that a lot.
-Trial and error is also your friend. This is close to what you want.
-It is late. I may and probably have made mistakes.
-I will not provide the full function. On the one hand, aren't easy answers nice? On the other, I should have given all the pieces above, including 99% of the code you need, I can't write the function without looking at your codebase (not and garentee it works), learning experiences are good, and it is late. I may also have structure member names wrong--again, can't verify this without your codebase. But this should get you almost all the way there.

Last edited by camlorn : 12-05-2012 at 12:07 AM.
camlorn is offline   Reply With Quote