Source:NetHack 3.4.3/src/rnd.c

From NetHackWiki
Revision as of 19:33, 3 August 2014 by 173.248.192.170 (talk) (rnl)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Below is the full text to src/rnd.c from NetHack 3.4.3. To link to a particular line, write [[rnd.c#line123]], for example.

This file contains the functions that power NetHack's RNG.

License

/*	SCCS Id: @(#)rnd.c	3.4	1996/02/07	*/
/* NetHack may be freely redistributed.  See license for details. */

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

Top of file

#include "hack.h"

/* "Rand()"s definition is determined by [OS]conf.h */

See, for example, unixconf.h#line303.

#if defined(LINT) && defined(UNIX)	/* rand() is long... */
extern int NDECL(rand);
#define RND(x)	(rand() % x)
#else /* LINT */
# if defined(UNIX) || defined(RANDOM)
#define RND(x)	(int)(Rand() % (long)(x))
# else
/* Good luck: the bottom order bits are cyclic. */
#define RND(x)	(int)((Rand()>>3) % (x))
# endif
#endif /* LINT */


The rest of the file does not worry about which implementation of Rand() is used, instead using the macro RND(x).

rn2

#ifdef OVL0

int
rn2(x)		/* 0 <= rn2(x) < x */
register int x;
{
#ifdef DEBUG
	if (x <= 0) {
		impossible("rn2(%d) attempted", x);
		return(0);
	}
	x = RND(x);
	return(x);
#else
	return(RND(x));
#endif
}

#endif /* OVL0 */


As line 22's comment suggests, rn2(x) returns an integer greater than or equal to zero and less than x.

This is used in the game in situations requiring a 50/50 chance of an event occurring: rn2(2) outputs 0 or 1 with equal probability.

rnl

#ifdef OVLB

int
rnl(x)		/* 0 <= rnl(x) < x; sometimes subtracting Luck */
register int x;	/* good luck approaches 0, bad luck approaches (x-1) */
{
	register int i;

#ifdef DEBUG
	if (x <= 0) {
		impossible("rnl(%d) attempted", x);
		return(0);
	}
#endif
	i = RND(x);

	if (Luck && rn2(50 - Luck)) {
	    i -= (x <= 15 && Luck >= -5 ? Luck/3 : Luck);
	    if (i < 0) i = 0;
	    else if (i >= x) i = x-1;
	}

	return i;
}

#endif /* OVLB */

rnl(x) is the same as rn2, with a chance of a proportion of your Luck being subtracted from the result. This means very lucky characters tend to see lower values and very unlucky characters tend to see higher values.

In-game, this is used to make saving throws against your Luck. For example, blessed armor has a saving throw against being eroded by a trap: if rnl(4) is zero, the armor escapes unscathed[1][2][3]:

First, i is a random integer from 0 to 3. A very lucky character (with +13 Luck) has a rn2(37) chance (36 in 37 ~= 97%) of this being reduced by Luck/3, which in this case rounds to 4. i cannot be reduced below 0, so it is set to 0. So the other 1 time in 37 there will be a 25% chance of i being 0. In total, that's a 145/148 chance (~=98%) that the armor will not be eroded.

In the worst case scenario (a very unlucky character with -13 Luck) there is a 251/252 (~=99.6%) of the armor being eroded.

When you have neutral (0) luck, rnl(x) is equal to rn2(x), so there is a 3/4 (75%) chance of the armor being eroded.

Moral: keep your Luck high.

rnd

#ifdef OVL0

int
rnd(x)		/* 1 <= rnd(x) <= x */
register int x;
{
#ifdef DEBUG
	if (x <= 0) {
		impossible("rnd(%d) attempted", x);
		return(1);
	}
	x = RND(x)+1;
	return(x);
#else
	return(RND(x)+1);
#endif
}

#endif /* OVL0 */

rnd(x) returns an integer from 1 to x, inclusive. This simulates the roll of an x-sided die.

d

#ifdef OVL1

int
d(n,x)		/* n <= d(n,x) <= (n*x) */
register int n, x;
{
	register int tmp = n;

#ifdef DEBUG
	if (x < 0 || n < 0 || (x == 0 && n != 0)) {
		impossible("d(%d,%d) attempted", n, x);
		return(1);
	}
#endif
	while(n--) tmp += RND(x);
	return(tmp); /* Alea iacta est. -- J.C. */
}

#endif /* OVL1 */
Probability graph of a roll of 3d6 and a normal distribution with the same mean and standard deviation.

d is NetHack's implementation of D notation from D&D. d(n,x) is equivalent to ndx (e.g. d(3,6) is like 3d6). This simulates the roll of n x-sided dice.

"Alea iacta est" is Latin for "the die is cast". "J.C." refers to Julius Caesar, from whom this quote originates.

rne

#ifdef OVLB

int
rne(x)
register int x;
{
	register int tmp, utmp;

	utmp = (u.ulevel < 15) ? 5 : u.ulevel/3;
	tmp = 1;
	while (tmp < utmp && !rn2(x))
		tmp++;
	return tmp;

	/* was:
	 *	tmp = 1;
	 *	while(!rn2(x)) tmp++;
	 *	return(min(tmp,(u.ulevel < 15) ? 5 : u.ulevel/3));
	 * which is clearer but less efficient and stands a vanishingly
	 * small chance of overflowing tmp
	 */
}
Probability graph of a call of rne(3) when experience level is less than 18.

rne returns an exponentially weighted random integer from 1 to a number depending on your experience level. It is used in-game for deciding the enchantment of randomly generated items.

rnz

int
rnz(i)
int i;
{
#ifdef LINT
	int x = i;
	int tmp = 1000;
#else
	register long x = i;
	register long tmp = 1000;
#endif
	tmp += rn2(1000);
	tmp *= rne(4);
	if (rn2(2)) { x *= tmp; x /= 1000; }
	else { x *= 1000; x /= tmp; }
	return((int)x);
}

#endif /* OVLB */

/*rnd.c*/
Probability graph of a call of rnz(100).

rnz produces a very strange distribution and is used for calculating prayer timeouts, among other things.

See Also

hack.h#line291 - rn1(x,y) #define

References