Please check out Corporate Expanse: From the Cradle !

Member Discussions

terms



[Previous] [Next] [Post] [Reply] [Topics] [Summary] [Search]


1. Help make this more random please Wed Jan 11, 2006 [9:39 PM]
MPVMUD
jaker_1976@hotmail.com
member since: Mar 5, 2005
Reply
This following code is to help make splitting of eq popped so players can dice the item so they do not fight over the item.

I am having a a bit of problem making this code random.

This is the object of the code below:

If the item is in the persons pfile as in inventory or if they are wearing it you may dice it.

So say they are wearing a ring of ice.
command: dice ring

player sees:
... You grab some dice from your belt pouch and roll them on the ground for a ring of ice.

...The winner is: Thanatos.

person in room will see:
Thanatos gets some dice from a belt pouch and rolls the dice on the ground for a ring of ice.

...The winner is: Thanatos.

So here is my problem: With the following code the same person will or could roll the same name 5 to 6 times in a roll. Can someone take it and make it more random or help explain to me how to make it more random.

do_random_split (CHAR_DATA * ch , char *argy)
{
DESCRIPTOR_DATA *d;
char arg[SML_LENGTH];
char buf[5000];
int i,x;
ROOM_DATA *troom;
static ROOM_DATA *first;
CHAR_DATA *mob,*victim;
SINGLE_OBJECT *obj;
DEFINE_COMMAND('dice', do_random_split, POSITION_DEAD, 0, LOG_NORMAL,'This does a random split between people in a room to replace 0 high')
i=1;
if (IS_MOB(ch) || !ch->desc)
return;

one_argy (argy, arg);
if (arg[0] == '\0')
{
send_to_char ('Dice a split on what?\n\r', ch);
return;
}
troom=ch->in_room;
if ((obj = get_obj_inv (ch, arg)) == NULL)
{
send_to_char ('You can't find it.\n\r', ch);
return;
}

mob=NULL;


for (mob = troom->more->people; mob != NULL; mob = mob->next_in_room)
{
i++;
}



x=number_range(1,i)-1;
if (x in_room;
for (mob = troom->more->people; mob != NULL; mob = mob->next_in_room)
{
if (i !=x)
{
i++;
continue;
}
else
break;

}
if (mob->desc == NULL)
{
do_random_split(ch,argy);
return;
}
if (IS_PLAYER(mob) && LEVEL(mob) > 90 && LEVEL(ch) < 91)
{
do_random_split(ch,argy);
return;
}

sprintf(buf,'\x1B[0;37m... You grab some dice from your belt pouch and roll them on the ground for %s\x1B[0;37m.\n\r',obj->pIndexData->short_descr);
send_to_char(buf,ch);
act ('\x1B[1;34m$n \x1B[0;37mgets some dice from a belt pouch and rolls the dice on the ground for $p\x1B[0;37m.\n\n\r', ch, obj, ch, TO_NOTVICT);
sprintf(buf,'\n\r\x1B[0;37m...The winner is:\x1B[1;34m %s\x1B[37;0m. \n\r',
mob->desc == NULL ? 'Nobody' : RNAME(mob));
for (d = descriptor_list; d; d = d->next)
{
if (d->connected == CON_PLAYING
&& d->character->in_room == ch->in_room)
{
send_to_char (buf, d->character);
}
}

return;
}

Sorry for how messy. Thanks in advance


2. RE: Help make this more random please Wed Jan 11, 2006 [10:21 PM]
Lyanic
Lyanic@gmail.com
member since: Dec 26, 2005
In Reply To
Reply
Ok, I'm too lazy to actually read through that code, but it seems like you're trying to reinvent the wheel. You do know about the random functions already available in libraries right? Also, if you want something really random, you could try researching Knuth's random algorithm.
- Lyanic, Creator/Designer/Administrator
The 7th Plane (7thplane.net 8888)


3. RE: Help make this more random please Wed Jan 11, 2006 [11:24 PM]
MPVMUD
jaker_1976@hotmail.com
member since: Mar 5, 2005
In Reply To
Reply
Well I see TMC will not let the code be shown it takes out about 4 lines and moves part of one to the end of another heh.

I guess if anyone is willing to give me a hand and look over the code email me and I will email a copy of the code to you so you can look it over.


4. RE: Help make this more random please Thu Jan 12, 2006 [7:09 AM]
Kastagaar
Email not supplied
member since: Jul 29, 1999
In Reply To
Reply
Unrelated to your problem, here's a hint for posting code in these forums.

First, wrap it in <pre> and </pre> tags.

Next, ensure any empty line actually has a space at its beginning.

Third, replace any lt; with &lt; (INCLUDING the semicolon) and any & with &amp; (also including the semicolon).

Finally, when previewing, copy the contents of your post into your buffer (ctrl-a, ctrl-c), preview, go BACK, paste if necessary, edit if necessary, repeat if necessary and then post. This prevents half of what you've just done being removed. And also stops quotes being turned into apostrophes.

Thus, your code will actually look something like:


do_random_split (CHAR_DATA * ch , char *argy)
{
DESCRIPTOR_DATA *d;
char arg[SML_LENGTH];
char buf[5000];
int i,x;
ROOM_DATA *troom;
static ROOM_DATA *first;
CHAR_DATA *mob,*victim;
SINGLE_OBJECT *obj;

DEFINE_COMMAND("dice", do_random_split, POSITION_DEAD, 0, LOG_NORMAL,"This does a random split between people in a room to replace 0 high")

i=1;

if (IS_MOB(ch) || !ch->desc)
return;

one_argy (argy, arg);

if (arg[0] == '\0')
{
send_to_char ('Dice a split on what?\n\r', ch);
return;
}

troom=ch->in_room;

if ((obj = get_obj_inv (ch, arg)) == NULL)
{
send_to_char ('You can't find it.\n\r', ch);
return;
}

mob=NULL;

for (mob = troom->more->people; mob != NULL; mob = mob->next_in_room)
{
i++;
}

x=number_range(1,i)-1;

if (x in_room; /* YOU HAVE A TYPO HERE */

for (mob = troom->more->people; mob != NULL; mob = mob->next_in_room)
{
if (i !=x)
{
i++;
continue;
}
else
break;
}

if (mob->desc == NULL)
{
do_random_split(ch,argy);
return;
}

if (IS_PLAYER(mob) && LEVEL(mob) > 90 && LEVEL(ch) < 91)
{
do_random_split(ch,argy);
return;
}

sprintf(buf,'\x1B[0;37m... You grab some dice from your belt pouch and roll them on the ground for %s\x1B[0;37m.\n\r',obj->pIndexData->short_descr);
send_to_char(buf,ch);
act ('\x1B[1;34m$n \x1B[0;37mgets some dice from a belt pouch and rolls the dice on the ground for $p\x1B[0;37m.\n\n\r', ch, obj, ch, TO_NOTVICT);
sprintf(buf,'\n\r\x1B[0;37m...The winner is:\x1B[1;34m %s\x1B[37;0m. \n\r',

mob->desc == NULL ? 'Nobody' : RNAME(mob));

for (d = descriptor_list; d; d = d->next)
{
if (d->connected == CON_PLAYING && d->character->in_room == ch->in_room)
{
send_to_char (buf, d->character);
}
}

return;
}



My advice? Use comments to explicitly state what you think your algorithm is doing. Then check that your code actually does that. The errors become apparent.

(Comment added by Kastagaar on Thu Jan 12 9:10:37 2006)

Of course, that should be replacing any < with &lt;.
There are two ways of constructing software: to make it so simple that there are obviously no errors, and to make it so complex that there are no obvious errors.


5. RE: Help make this more random please Thu Jan 12, 2006 [9:04 AM]
thsgrn
thsgrn@yahoo.com
member since: Sep 13, 2000
In Reply To
Reply
I should probably point that anything truely random can in fact produce the same result multiple times in a row, and if repeated often enough, WILL.


6. RE: Help make this more random please Thu Jan 12, 2006 [10:10 AM]
Keriwena
Email not supplied
member since: Jun 25, 2001
In Reply To
Reply
The other side of what thsgrn said is, a random choice is "fair" the first time, and "fair" in the long run, but on the second and third trials, most people don't think it's fair if the previous winner gets an equal chance to win again.

You could code this, or simply ask the last winner to step out of the room when dividing small piles of loot among large groups. When the second winnner steps out, the first goes back in.

Or, have a spell that "poof!", splits the pile and drops into random inventories all at once. Then players can trade things around like the prizes in a grab bag.


7. RE: Help make this more random please Thu Jan 12, 2006 [5:44 PM]
welcor
Email not supplied
member since: Mar 9, 2000
In Reply To
Reply
Try this on for size:

void do_random_split (CHAR_DATA * ch , char *argy) 
{
  int plr_count = 0, plr_win = 0;
  char arg[SML_LENGTH];
  CHAR_DATA *winner;
  
  DEFINE_COMMAND("dice", do_random_split, POSITION_DEAD, 0, LOG_NORMAL,"This does a random split between people in a room to replace 0 high")
  
  if (IS_MOB(ch) || !ch->desc)
    return;
    
  one_argy (argy, arg);
  
  if (arg[0] == '\0') {
    send_to_char ("Dice a split on what?\n\r", ch);
    return;
  }
  
  /* this only searches inventory */
  if ((obj = get_obj_inv (ch, arg)) == NULL) {
    send_to_char ("You can't find it.\n\r", ch);
    return;
  }
  
  /* count players in room */ 
  for (winner = ch->in_room->more->people; winner; winner = winner->next_in_room)
    if (IS_PLAYER(winner))
      plr_count++;
  
  do {
    plr_win = number_range(1, plr_count);
    // or try this for more load on your processor :
    // plr_win = ((number_range(0, plr_count *1000)) % plr_count) +1;
  
    for (winner = ch->in_room->more->people; winner; winner = winner->next_in_room)
      if (IS_PLAYER(winner) && plr_count-- == plr_win)
        break;
    
  } while (LEVEL(WINNER) > 90 && LEVEL(ch) < 91);
  
  /* winner can now be announced */
  
}


8. RE: Help make this more random please Fri Jan 13, 2006 [5:03 AM]
Keriwena
Email not supplied
member since: Jun 25, 2001
In Reply To
Reply
// plr_win = ((number_range(0, plr_count *1000)) % plr_count) +1;

Would someone please explain this to me? I've seen it before in the MUSH Manual, but intuitively, I don't understand why the third digit would be smoother than the first two (I think he meant to divide by 1000).


9. RE: Help make this more random please Fri Jan 13, 2006 [8:16 AM]
eiz
eiz@codealchemy.org
member since: Dec 24, 2002
In Reply To
Reply
So here is my problem: With the following code the same person will or could roll the same name 5 to 6 times in a roll. Can someone take it and make it more random or help explain to me how to make it more random.

Assuming you haven't (stupidly) modified the RNG present in your codebase - something Merc-derived, so it would be the additive generator from Knuth - you should be fine. Some people think that they can make a random number generator by just tossing in a bunch of arithmetic, but this does not work and you should never do it. If you suspect your RNG is behaving badly, there are a variety of tests you can use (chi-square distribution, arithmetic mean, serial correlation, spectral test, etc). However, much more likely is that you simply don't understand that when the range is small, the likelihood of getting the same result repeatedly is fairly significant.

If you are using a linear congruential generator, make sure your number_range function isn't extracting the low-order bits, which aren't particularly random.

If you have broken your RNG by screwing around with it, the best replacement you will find is the Mersenne Twister. To my knowledge, there is no higher quality PRNG in existence (although the additive method is faster).


10. RE: Help make this more random please Fri Jan 13, 2006 [8:29 AM]
shasarak
Email not supplied
member since: Dec 10, 2004
In Reply To
Reply
Sounds to me like you want to make this highly non-random: in a genuinely random system the chances of person A winning is exactly the same the second time round as it was the first. You want to explicitly prevent the same person winning twice - this makes it less random.

Make a collection of all the people involved. (It could be an Array if you're using C). If there are six people then the first winner will be picked by choosing a random number from 1 to 6 (or 0 to 5). You then remove that person from the collection (or, in C terms, construct a new array of five elements which doesn't contain the previous victor. Then choose a new winner by generating a number from 1 to 5 (or 0 to 4). And so on.
Please do not feed the troll.


11. RE: Help make this more random please Fri Jan 13, 2006 [3:59 PM]
BorgDrone
Email not supplied
member since: Feb 15, 2005
In Reply To
Reply
How can you use a chi-square distribution to test if your random number generator is incorrect? I'm just curious.


12. RE: Help make this more random please Fri Jan 13, 2006 [5:01 PM]
welcor
Email not supplied
member since: Mar 9, 2000
In Reply To
Reply
// plr_win = ((number_range(0, plr_count *1000)) % plr_count) +1;

Would someone please explain this to me?


Instead of calulating a random number between 1 and plr_count (which, as eiz stated above, due to a small range, might generate similar results more often), I calculate a random number between 0 and plr_count*1000. This gives a larger range, thus eliminating this error source. After this, I reduce the result through division, see below.

I've seen it before in the MUSH Manual, but intuitively, I don't understand why the third digit would be smoother than the first two (I think he meant to divide by 1000).

The % operator returns the modulus:
13/5 = 2
13%5 = 3 (which is : 13 - (2*5))

In this case, it returns 0-(plrcount-1). Since the algorithm needs a number between 1 and plr_count, I add one.



13. RE: Help make this more random please Fri Jan 13, 2006 [9:11 PM]
eiz
eiz@codealchemy.org
member since: Dec 24, 2002
In Reply To
Reply


14. RE: Help make this more random please Sat Jan 14, 2006 [4:24 AM]
Keriwena
Email not supplied
member since: Jun 25, 2001
In Reply To
Reply
Duh. Wow. Cool. Thanks. :)

For any other dummies trying to follow this, the answer is he's dividing, but he's throwing the dividend away and using the remainder, so he's really reducing the number by subtraction.

Note the number he's dividing by doesn't really matter. It could be a random number. Hmmmm....


15. RE: Help make this more random please Sat Jan 14, 2006 [5:32 AM]
eiz
eiz@codealchemy.org
member since: Dec 24, 2002
In Reply To
Reply
All you're doing is repeating the work done by number_range (which takes the output from a 31-bit RNG, number_mm, and reduces it to the given range).

(Comment added by eiz on Sat Jan 14 7:47:46 2006)

Just to clarify, the probability of choosing a random number n from the range [1,max] is 1/max, which obviously approaches 1 as max gets smaller. Thus there is no "error" to eliminate. Doing a random shuffle of the group (or whatever) is, as shasarak pointed out, probably a better idea.

(Comment added by eiz on Sat Jan 14 7:57:19 2006)

Correction: Merc's RNG is 25 bits. Don't ask me why. It has a pretty awful initialization function, too.


16. RE: Help make this more random please Sat Jan 14, 2006 [6:23 PM]
welcor
Email not supplied
member since: Mar 9, 2000
In Reply To
Reply
Oh, you're looking at code? I wasn't. For all I knew number_range() was having difficulties, and weren't random "enough" when dealing with small ranges - after all, that's what you wrote. Or at least what I read into what you wrote.

I've never looked at the RNG behind number_range().
I guess I should.


(Comment added by welcor on Sat Jan 14 20:56:16 2006)

Well, looked at it. Strange implementation, if you ask me, but sound as far as I can tell (I'm more used to circlemuds' implementation of William S. England's pseudo-RNG - not so complicated, and "random enough" for us).
To the OP:
Just use "number_range(1, plr_count)" - it appears as random as the other statement.


17. RE: Help make this more random please Tue Jan 31, 2006 [10:39 AM]
seronis
seronis@columbus.rr.com
member since: Apr 14, 2003
In Reply To
Reply
OK i read a few of the mentioned articles about RNGs and the overhead they list for given PRNGs seems to be quite huge. I have a RNG i wrote a couple years ago that only has 2 integers of overhead in the class and seems to have a fairly good dispersal.

I tested it by filling buckets of various sizes to make sure its distribution was good for most arbitrary ranges and also did sequence tests to see how many times the same number could be given in a row and tests for how often the exact same series of numbers could repeat before the pattern was again different.

The bucket test resulted in the distribution of any given result being within +-10% of what its 'odds' suggested which was fine with me.

The test for repeating a given result too many times turned out that in 1 billion iterations the same number was never repeated more than 6 times in a row.

And the test i ran for how often a sub sequence could be repeated returned very few hits. Dont remember its exact results but it was within what i deemed good levels at the time. (note: these tests were done asking for results in the range 1-100)

Now what im interested in is how can i go about doing any more intensive tests? When i ran my RNG in the sequence test i remember the initial pattern never repeated so i know its period is at LEAST a billion iterations long. But id like to get some 'test' function that can do a more strenuous job and see how well it manages.

The formula itself is just some basic multiplication and addition using PI values that i tweaked untill the results looked random enough to me. It wasnt researched so probably isnt very professional.

Can anyone help me with testing its limits out?

(Comment added by seronis on Tue Jan 31 12:42:22 2006)

NOTE:

my formula also doesnt have any visible pattern as to distribution of even/odd numbers even with the smallest ranges.

I did tests using ranges as low as various RPG dice or even coin fliping and didnt notice a pattern. But it may have other weaknesses and id like to work these out if they exist.


18. RE: Help make this more random please Wed May 3, 2006 [9:26 PM]
renius
perryrs@auburn.edu
member since: Oct 2, 2005
In Reply To
Reply
I know this is a kinda old thread, and I don't know too much code, but here is an idea that works very well on the mud I play. Have a command called 'random' that is kind of like a social. Then pretty much it displays a number from 1 to 100. Everyone in the form does this and the highest random wins and takes first pick. The second highest takes second, ect. ect. ect. This helps alot to settle arguments over who gets what, and with class specific pieces if there is not another person of that class you automaticaly get it.


19. RE: Help make this more random please Wed May 3, 2006 [9:53 PM]
Vopisk
Email not supplied
member since: Jul 25, 2003
In Reply To
Reply
The idea behind this thread is more, how to build a better mousetrap.

You are using what all these people are referring to when they say RNG (Random Number Generator) when you call that random routine. What the OP was asking about is how to modify a random number generator in such a fashion as to actually limit the true randomness of the system, whereby, he would in fact limit duplicate results.

Now, if I were approaching the situation, I would say probably the best idea is to do something like a previous poster said and keep track of who is in the "split" and who has already "won" and if we roll their number again, we re-roll until someone who hasn't "won" yet does. We keep repeating this pattern until the loot is evenly distributed amongst everyone, resetting once all involved parties have won and looping until all the loot in question is distributed.

My two cents, something to chew on,

Vopisk




[Previous] [Next] [Post] [Reply] [Topics] [Summary] [Search]