From 80a7a917308a1cd422923e953ced86d66503906f Mon Sep 17 00:00:00 2001 From: rubidium Date: Sat, 17 Nov 2007 23:16:41 +0000 Subject: [PATCH] (svn r11454) -Fix: the CHANCE16 functions were biased; a 32768 in 65536 chance was really a 32769 in 65536 chance. --- src/macros.h | 15 +++++++++++---- src/town_cmd.cpp | 10 ++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/macros.h b/src/macros.h index 95af441237..cb2839c903 100644 --- a/src/macros.h +++ b/src/macros.h @@ -476,7 +476,7 @@ template static inline bool IS_INSIDE_1D(const T x, const int base, * @param b The denominator of the fraction, must of course not be null * @return True in (a/b) percent */ -#define CHANCE16(a, b) ((uint16)Random() <= (uint16)((65536 * (a)) / (b))) +#define CHANCE16(a, b) CHANCE16I(a, b, Random()) /** * Flips a coin with a given probability and saves the randomize-number in a variable. @@ -484,18 +484,25 @@ template static inline bool IS_INSIDE_1D(const T x, const int base, * This macro uses the same parameters as the CHANCE16 marco. The third parameter * must be a variable the randomize-number from Random() is saved in. * + * The low 16 bits of r will already be used and can therefor not be passed to + * CHANCE16I. One can only send the high 16 bits to CHANCE16I. + * * @param a The numerator of the fraction, see CHANCE16 * @param b The denominator of the fraction, see CHANCE16 * @param r The variable to save the randomize-number from Random() * @return True in (a/b) percent */ -#define CHANCE16R(a, b, r) ((uint16)(r = Random()) <= (uint16)((65536 * (a)) / (b))) +#define CHANCE16R(a, b, r) CHANCE16I(a, b, r = Random()) /** * Checks if a given randomize-number is below a given probability. * * This macro is used to check if the given probability by the fraction of (a/b) - * is greater than the given randomize-number v. + * is greater than low 16 bits of the given randomize-number v. + * + * Do not use this function twice on the same random 16 bits as it will yield + * the same result. One can use a random number for two calls to CHANCE16I, + * where one call sends the low 16 bits and the other the high 16 bits. * * @param a The numerator of the fraction, see CHANCE16 * @param b The denominator of the fraction, see CHANCE16 @@ -504,7 +511,7 @@ template static inline bool IS_INSIDE_1D(const T x, const int base, */ static inline bool CHANCE16I(const uint a, const uint b, const uint32 r) { - return (uint16)r <= (uint16)((65536 * a) / b); + return (uint16)r < (uint16)((65536 * a) / b); } diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index fa8e3ee829..8673792050 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -731,16 +731,14 @@ no_slope: * maybe terraform some. */ desired_slope = (dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? SLOPE_NW : SLOPE_NE; if (desired_slope != cur_slope && ComplementSlope(desired_slope) != cur_slope) { - uint32 r = Random(); - - if (CHANCE16I(1, 8, r)) { + if (CHANCE16(1, 8)) { CommandCost res = CMD_ERROR; - if (!_generating_world && CHANCE16I(1, 10, r >> 4)) { + if (!_generating_world && CHANCE16(1, 10)) { /* Note: Do not replace " ^ 0xF" with ComplementSlope(). The slope might be steep. */ - res = DoCommand(tile, CHANCE16I(1, 16, r >> 8) ? cur_slope : cur_slope ^ 0xF, 0, + res = DoCommand(tile, CHANCE16(1, 16) ? cur_slope : cur_slope ^ 0xF, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND); } - if (CmdFailed(res) && CHANCE16I(1, 3, r >> 16)) { + if (CmdFailed(res) && CHANCE16(1, 3)) { /* We can consider building on the slope, though. */ goto no_slope; }