adopt github pull request #286 - rndmonst()

Eliminate the cache that was supporting rndmonst() and pick a random
monster in a single pass through mons[] via "weighted reservoir
sampling", a term I'm not familiar with.

It had a couple of bugs:  if the first monster examined happened to
be given a weighting of 0, rn2() would divide by 0.  I didn't try
to figure out how to trigger that.  But the second one was easy to
trigger:  if all eligible monsters were extinct or genocided, it
would issue a warning even though the situation isn't impossible.

Aside from fixing those, the rest is mostly as-is.  I included a bit
of formatting in decl.c, moved some declarations to not require C99,
and changed a couple of macros to not hide and duplicate a call to
level_difficulty().

Fixes #286
This commit is contained in:
PatR
2020-02-22 17:40:55 -08:00
parent 5d4b9784ac
commit cbdda9dc9d
10 changed files with 70 additions and 99 deletions

View File

@@ -886,18 +886,19 @@ struct instance_globals {
boolean chosen_symset_end;
int symset_which_set;
/* SAVESIZE, BONESSIZE, LOCKNAMESIZE are defined in "fnamesiz.h" */
char SAVEF[SAVESIZE]; /* holds relative path of save file from playground */
char SAVEF[SAVESIZE]; /* relative path of save file from playground */
#ifdef MICRO
char SAVEP[SAVESIZE]; /* holds path of directory for save file */
#endif
char bones[BONESSIZE];
char lock[LOCKNAMESIZE];
/* hack.c */
anything tmp_anything;
int wc; /* current weight_cap(); valid after call to inv_weight() */
/* insight.c */
/* invent.c */
int lastinvnr; /* 0 ... 51 (never saved&restored) */
unsigned sortlootmode; /* set by sortloot() for use by sortloot_cmp();
@@ -905,7 +906,7 @@ struct instance_globals {
char *invbuf;
unsigned invbufsiz;
/* for perm_invent when operating on a partial inventory display, so that
the persistent one doesn't get shrunk during filtering for item selection
persistent one doesn't get shrunk during filtering for item selection
then regrown to full inventory, possibly being resized in the process */
winid cached_pickinv_win;
/* query objlist callback: return TRUE if obj type matches "this_type" */
@@ -916,15 +917,10 @@ struct instance_globals {
/* light.c */
light_source *light_base;
/* lock.c */
struct xlock_s xlock;
/* makemon.c */
struct {
int choice_count;
char mchoices[SPECIAL_PM]; /* value range is 0..127 */
} rndmonst_state;
/* mhitm.c */
boolean vis;

View File

@@ -1216,7 +1216,6 @@ E void FDECL(dealloc_mextra, (struct monst *));
E struct monst *FDECL(makemon, (struct permonst *, int, int, int));
E boolean FDECL(create_critters, (int, struct permonst *, BOOLEAN_P));
E struct permonst *NDECL(rndmonst);
E void FDECL(reset_rndmonst, (int));
E struct permonst *FDECL(mkclass, (CHAR_P, int));
E struct permonst *FDECL(mkclass_aligned, (CHAR_P, int, ALIGNTYP_P));
E int FDECL(mkclass_poly, (int));

View File

@@ -201,4 +201,13 @@ struct monst {
#define is_obj_mappear(mon,otyp) (M_AP_TYPE(mon) == M_AP_OBJECT \
&& (mon)->mappearance == (otyp))
/* Get the maximum difficulty monsters that can currently be generated,
given the current level difficulty and the hero's level. */
#define monmax_difficulty(levdif) (((levdif) + u.ulevel) / 2)
#define monmin_difficulty(levdif) ((levdif) / 6)
/* Macros for whether a type of monster is too strong for a specific level. */
#define montoostrong(monindx, lev) (mons[monindx].difficulty > lev)
#define montooweak(monindx, lev) (mons[monindx].difficulty < lev)
#endif /* MONST_H */