15 Oct, 2008, Runter wrote in the 81st comment:
Votes: 0
That's ridiculous because I've said repeatedly that the thing tests more than that. And repeatedly you come back with flawed logic. The reason I didn't "answer" your logic questions is because clearly I believed your logic to be wrong–And it was.

The logic never matched what I suggested. Maybe you just read 2 or 3 words of what I said but I laid out clear explanations of how the system worked top to bottom.
15 Oct, 2008, David Haley wrote in the 82nd comment:
Votes: 0
Umm, look, I asked you if more things were happening, and you kept going on about other things. When asked if the equivalences were correct, you said nothing at all. I mean, seriously, give me some help to work with here. I never said you were wrong in the absolute: I was trying to get you to clarify the confusion. All you had to do was say that my reduction of the function was incorrect and why. I'll point out that the logic was perfectly correct, but based on a misunderstanding of what the function was doing. Again, all the more reason for you to correct that, instead of going off about other things or asserting that I was wrong (yes, I got that already… :wink:) without telling me why.

Here is the initial source of confusion:

DavidHaley said:
Do we agree that:
room_is_private <=> private && some_other_condition(s)

where the details of the other conditions are not relevant at present.

Had that been answered from square one, this would have all gone away.

I think the lesson here is very simple: answering direct questions quickly is the most expedient method of avoiding drawn-out confusion.

Well, that's that, then.
15 Oct, 2008, Runter wrote in the 83rd comment:
Votes: 0
Okay, I'll concede that your logic was correct for an imaginary problem that never existed, was never explained to you in that way, and was disputed repeatedly. I'll give you that.


The fact remains I repeatedly explained how the function worked. I explain the break down of why there should be a is_room_private() and can_room_become_private(). Quix read what I said and even put my words to code. That code he posted is exactly the code that I suggested it represented.

If you didn't get what I was saying over and over. Dunno what to tell you. I never claimed to be a world class word smith. Maybe you did need me to spell it out in a logic table. For some reason I just thought it was easier for someone to understand than an arbitrary table of:

((!A || !B) && (!C || !D) && !E && !F) && (!A && !C)

The whole idea that I wasn't telling you why is remarkable. It's remarkable that you can even claim that when I said exactly what quix posted that, I guess, opened your eyes.
15 Oct, 2008, Runter wrote in the 84th comment:
Votes: 0
Let's go ahead and put it all the things I said that you are saying I didn't say on the table.
I'm sorry I didn't say it in the format you were looking for but all of that is exactly the reason WHY your boolean logic was flawed.

Quote
What I've said about it returning true if the flag is set and more than 1 person is in the room is true, and it also returns true for other reasons completely separate. Which is why time and time again I have said it has nothing to do with only the flag being set. There are other conditions that can constitute a room being private so the call is still needed even with the flag checks. Conditions like ownership of the room. The room being an immortal room, and future additions that could make a room always private.


Quote
The flag is only used to determine if the room can possibly become private by means of 2 people or more being in the room. The flag doesn't mean it's private. The check is_room_private returns true if the room is private.

What does this mean?

It means that if you want to know if the room can ever be private, calling that check isn't enough my friends.

Why is that?

Because even with the flag set the room doesn't have to be private, but it gives it the opportunity to be in the future.
The same thing goes for the solidarity flag.

If those aren't checked for then you may be issuing a room that could become private at a later time. Which for the purpose of the get_random_room() code in rom means it would be wrong without those flag checks.


Quote
And to be totally clear, it can become private from means other than even having any flags set. Ownership of a room, or future additions can cause a room to be private.


Quote
The conditions that make the room private are separate from the fact if a flag is set or not. It's really not that hard to understand. If the flag is set the room MAY be private. If you want to know if the room CAN become private you need to check to see if the flag is set. If it is set it DOES NOT have to be private.

I said the conditions that make the room private are separate from the private flag because they are. A room can be private without having the flag set at all. One of the ways a room becomes private is if it has the flag set and 2 or more people currently occupy it. Another way is if it has the solitude flag set and there is already 1 or more people in it. There's ways for it to be private without either of those flags set. They have absolutely nothing to do with the logic behind the room being private


Quote
the reason it's using is_room_private and also checking for the private flag is because is room private only comes back true when the flag is set AND there are already 2 people in the room. It's basically only calling that to get the other checks in is_room_private and then checking for the private flag because if wants true even if there is nobody in the room. (Same thing goes for solitary, but it's only 1 person allowed in the room.)


Quote
The first check isn't true in all cases. The cases that it isn't true is what requires for this code to have the flag checks. PRIVATE flag only returns true in is_room_private if there are 2 or more people in it. And for the solitary flag if there is 1 or more people in it. Then there's other things in is_room_private like ownership and such. I certainly don't like the way the code is done, but if you removed one call or the other without adding in more code it wouldn't accomplish the same thing. So it's not totally redundant.
15 Oct, 2008, David Haley wrote in the 85th comment:
Votes: 0
If I may make a suggestion to you in good faith and with completely good intentions, it really would have been more efficient to just answer the questions I was asking. As I said, I had no context and was trying to work off of limited information. When I ask the same question more than once, that is a pretty good indication that I am not getting the clarifications that I need to go forward. The fact that Quix's answer was clear but yours wasn't is not surprising to me because he showed me why my reduction was wrong, instead of just saying that I was wrong. Just saying. :shrug:

And sure, giving me the logic table from the getgo when I am looking at only the logic (recall again that I have no context) is a perfect way of clarifying things. :smile: (no sarcasm)


EDIT: I hadn't seen your most recent post when I posted the above. I am sorry but re-reading those words does not make things clearer, especially when I was trying to parse them as answers to different questions. The only reason I understand them now is because I know what code lies behind them. Not sure what else to say. Sorry. :shrug:
15 Oct, 2008, quixadhal wrote in the 86th comment:
Votes: 0
In fixing the random_room junk, I'm of course compelled to fix number_door() as well, and in doing that I'm staring at the random number code itself. Along the lines of it not being 1992 anymore, I suspect the system built-in random number routines are probably pretty decent these days…. apparently Russ did too since the old number_mm code is unused unless you defined OLD_RAND.

However, is there any compelling reason to throw away 6 bits of data? number_mm() currently just returns random() >> 6.

So, instead of a random number from 0 to RAND_MAX (typically INT_MAX, or 2 billion), it returns a random number from 0 to 2^26? That seems weird. I'm tempted to scrap the whole mess and just base everything from random(). I used to use lrand48(), but that's apparently been depreciated in favor of rand() these days.

Opinions? Concerns? Don't care?
15 Oct, 2008, David Haley wrote in the 87th comment:
Votes: 0
It's dangerous to toss 6 bits of data because you don't know what RAND_MAX is. Yes, typically it's INT_MAX, but not necessarily.

It would be much better IMO to have a single random number generator from 0, included, to SOME_MAX, excluded, and then write routines around that to get from 0 to n, etc.
15 Oct, 2008, Runter wrote in the 88th comment:
Votes: 0
I suspect for a codebase the built in random generator is fine. However, random number generation is quite a science. I'm not sure for a lot of people like myself it will be random enough. Back a few years ago when I did some testing I was getting a lot of streaking with the built in.
15 Oct, 2008, Vassi wrote in the 89th comment:
Votes: 0
Runter said:
Back a few years ago when I did some testing I was getting a lot of streaking with the built in.


I've gotten good results with the Mersenne Twister: http://www.math.sci.hiroshima-u.ac.jp/~m... (They have C source for it there). I like it better than the .NET random generator (not counting the Cryptographic rand generator) and is fairly simple to implement.
16 Oct, 2008, quixadhal wrote in the 90th comment:
Votes: 0
I'll take a peek at that one. Here's the comment from the ROM source:

/* I noticed streaking with this random number generator, so I switched
back to the system srandom call. If this doesn't work for you,
define OLD_RAND to use the old system – Alander */
16 Oct, 2008, Lobotomy wrote in the 91st comment:
Votes: 0
I would also suggest making use of the time_seed function that I came across in my prior foray into PRNG implementation (link: here); not just for the Mersenne Twister, but for other PRNG's as well so long as whatever PRNG you use makes use of time as the seed.
16 Oct, 2008, quixadhal wrote in the 92nd comment:
Votes: 0
Hmmmm, dangerous code thingy #27:

merc.h
struct  exit_data
{
union
{
ROOM_INDEX_DATA * to_room;
int vnum;
} u1;
int exit_info;
int key;
char * keyword;
char * description;
};


A union? Were we really THAT desperate for a couple of bytes? Very nasty… if you forget and try to use exit.u1.to_room before you've set the pointer, you get the value stored in vnum AS a pointer **seg fault**. If you forget and try to use exit.u1.vnum after you've set the pointer, you get a random memory address AS the vnum. In the current code, that would get masked to the lower 16 bits and would be some totally random vnum that might or might not exist.

Would anyone object to promoting those fields to normal, seperate entires?

It appears to be the only place a union is used, in the entire codebase.
16 Oct, 2008, Sandi wrote in the 93rd comment:
Votes: 0
If there's only one occurrence, then get rid of it. That's one less page of book on C a newbie will have to read.

As to the rand() concerns, here's my comment (which follows Alander's comment):

/* I find the streaking useful for clustering random events in a more
"natural" way, so OLD_RAND is currently defined in the Makefile - Fallon */

For my next project, the design notes suggest including several random generator filters to provide simple options for lottery players. :)


Perhaps I should mention my "dice" command is designed with a "memory" so it never returns the same number twice in a row. Mathematically correct? No. Meets the player's expectations of "random"? Yes.
16 Oct, 2008, David Haley wrote in the 94th comment:
Votes: 0
Streaking in a random number generator is not necessarily a sign of lack of randomness. You could randomly be getting a streak of numbers, after all. To get a better comparison, you would have to calculate mean, median, mode, frequency counts and standard deviations for the system generator and other number generators over millions upon millions of generated numbers.

The problem, as I was led to believe, with the system generator is that it is fairly easily predictable given a relatively small sequence of generated numbers. So it's not sufficiently "random", but that was from the perspective of defending against an attacker trying to guess your next random number.

EDIT:
Sandi said:
Perhaps I should mention my "dice" command is designed with a "memory" so it never returns the same number twice in a row. Mathematically correct? No. Meets the player's expectations of "random"? Yes.

I don't understand why your players think that is what dice are supposed to do. I've gotten the same number in a row more times than I can count. A probability of 16.6% is very high in the scale of things.
16 Oct, 2008, quixadhal wrote in the 95th comment:
Votes: 0
Actually, splitting the random number generator off into its own file would make it pretty simple to allow the end user to select which one they want. I'll probably change some of the low level function names to be more useful (leaving #defines for those that insist that number_mm is somehow intuitive), and then we can just make #defines to point to the set you want to use.

It might be fun to write a little test suite to try and determine how "streaky" a given PRNG is.

edit: Oh, and as for real dice rolls. Am I the only one who used to spend 15 minutes standing in front of the dice bin at the hobby shop, test-rolling various dice to decide which ones I wanted to buy? Not that they ever performed as well when I needed them to, but having a die that *seemed* to roll consistently low was always good for saving throws.

And yes, I know my DM did exactly the same thing, so it was only fair. :evil:
16 Oct, 2008, elanthis wrote in the 96th comment:
Votes: 0
DavidHaley said:
I don't understand why your players think that is what dice are supposed to do. I've gotten the same number in a row more times than I can count. A probability of 16.6% is very high in the scale of things.


It's fairly common. Humans are pattern creatures. The entirety of our mental faculties are based on pattern recognition. When we notice a pattern – such as a streak of numbers – it stands out to us, and the average person will then assume it is not random.

One of the tests I've seen is to ask a person which of the following series of coin tosees (T for Tails and H for Heads) is most likely to happen:

TTTTTHHHHH
TTHHTTHHTT
THHTTHTTHH
HHHHHHHHHH

The correct answer is of course that all 4 sequences are equally likely to happen. :) Most people will choose the third option, though, as it does not consist of any particular pattern.

A lot of games do what is being discussed here and dampens the randomizer. When players get a lucky streak due to randomness, they feel like it was their own luck and/or skill that gave them the win. When players suffer the AI getting a lucky streak, they blame the AI for cheating or the randomizer for not being random enough. A lot of games try to detect streaks (usually not just 2 in a row – that's way too low) and then alter the results to break the streak and make it appear more random… even though in actuality, it's reducing the randomness of the system.

Anyways, the summary of all that is: "people are stupid and don't understand probability." :)
16 Oct, 2008, quixadhal wrote in the 97th comment:
Votes: 0
Question about error handling!

Errors on user input or things like that are obviously recoverable errors, but how do we want to handle errors at a much lower level, like calloc() failing, or being unable to open a player file for write access?

Some places in the code appear to try to make a bug() entry and then exit(). I've used assert() for things like this in the past. Usually, trying to stumble on past the error only results in a bigger mess.

I'm pondering the idea of a proper_exit() function that won't do much currently, but would give a place where future database handles or similar things could be cleanly shut down.
16 Oct, 2008, quixadhal wrote in the 98th comment:
Votes: 0
elanthis said:
HHHHHHHHHH

Curse you! Now I'm going to have to go watch Rosencrantz ... again!
16 Oct, 2008, David Haley wrote in the 99th comment:
Votes: 0
elanthis said:
It's fairly common. Humans are pattern creatures. The entirety of our mental faculties are based on pattern recognition. When we notice a pattern – such as a streak of numbers – it stands out to us, and the average person will then assume it is not random.

Well, sure, but I'd assume that people have seen dice before and realize that you can get the same number in a row…

elanthis said:
TTTTTHHHHH
TTHHTTHHTT
THHTTHTTHH
HHHHHHHHHH

The correct answer is of course that all 4 sequences are equally likely to happen. :)

The interesting thing about this is that the equal likeliness is only the case if you take them as sequences. Taken as a collection of occurrences, the probabilities are not equal at all. That's tricky to wrap your head around the first time you encounter it…

quixadhal said:
Question about error handling!

I tend to make liberal use of assertions for errors when I believe that I cannot reasonably recover from them. In many cases, not being able to allocate memory is such an error (but not always).

Why do you need to worry about closing handles? When the process dies, those will all disappear. I suppose that you might have to worry about corrupting the database's state, but shouldn't it handle that when a connection suddenly dies? I'm also worried that if you're already in a Very Bad State, it's unclear that you'll be able to clean up properly anyhow.
16 Oct, 2008, quixadhal wrote in the 100th comment:
Votes: 0
Most SQL databases use transactions. If you kill the connection, those transactions are aborted, which may or may not be what you want, depending on what fatal error you encountered. If I was in the middle of saving a player file, yes, a rollback is probably the right thing to do. If I was logging some complex process in steps, and failed in the middle of it, I might want those log entries to be commited before blowing up.
80.0/267