Commit 3fe5cbdd authored by salix5's avatar salix5 Committed by GitHub

update RNG and uniform distribution (#391)

DUEL_OLD_REPLAY
The duel created by old replay files.
It will use the original almost-uniform distribution.

Random Number Generator
C++11 has a built-in std::mersenne_twister_engine()
It can be replaced by std::mt19937.

class mt19937
rand()
mersenne_twister_engine std:mt19937

get_random_integer()
uniform_int_distribution based on std::mt19937

shuffle_vector()
Fisher–Yates shuffle based on get_random_integer()

* update RNG and uniform distribution

* add class mt19937

* typos

* avoid windows macro

* fix rand()
parent 5ec35ae0
......@@ -218,14 +218,14 @@ struct card_sort {
#define QUERY_LINK 0x800000
//Link markers
#define LINK_MARKER_BOTTOM_LEFT 0001
#define LINK_MARKER_BOTTOM 0002
#define LINK_MARKER_BOTTOM_RIGHT 0004
#define LINK_MARKER_LEFT 0010
#define LINK_MARKER_RIGHT 0040
#define LINK_MARKER_TOP_LEFT 0100
#define LINK_MARKER_TOP 0200
#define LINK_MARKER_TOP_RIGHT 0400
#define LINK_MARKER_BOTTOM_LEFT 0x001
#define LINK_MARKER_BOTTOM 0x002
#define LINK_MARKER_BOTTOM_RIGHT 0x004
#define LINK_MARKER_LEFT 0x008
#define LINK_MARKER_RIGHT 0x020
#define LINK_MARKER_TOP_LEFT 0x040
#define LINK_MARKER_TOP 0x080
#define LINK_MARKER_TOP_RIGHT 0x100
//Messages
#define MSG_RETRY 1
......@@ -385,7 +385,7 @@ struct card_sort {
//Options
#define DUEL_TEST_MODE 0x01
#define DUEL_ATTACK_FIRST_TURN 0x02
//#define DUEL_NO_CHAIN_HINT 0x04
#define DUEL_OLD_REPLAY 0x04
#define DUEL_OBSOLETE_RULING 0x08
#define DUEL_PSEUDO_SHUFFLE 0x10
#define DUEL_TAG_MODE 0x20
......
......@@ -139,5 +139,10 @@ void duel::set_responseb(byte* resp) {
std::memcpy(game_field->returns.bvalue, resp, 64);
}
int32 duel::get_next_integer(int32 l, int32 h) {
return (int32) (random.real() * (h - l + 1)) + l;
if (game_field->core.duel_options & DUEL_OLD_REPLAY) {
return random.get_random_integer_old(l, h);
}
else {
return random.get_random_integer(l, h);
}
}
......@@ -28,7 +28,7 @@ public:
byte* bufferp;
interpreter* lua;
field* game_field;
mtrandom random;
mt19937 random;
std::unordered_set<card*> cards;
std::unordered_set<card*> assumes;
std::unordered_set<group*> groups;
......
......@@ -950,13 +950,10 @@ void field::shuffle(uint8 playerid, uint8 location) {
if(location == LOCATION_EXTRA)
s = s - player[playerid].extra_p_count;
if(s > 1) {
uint32 i = 0, r;
for(i = 0; i < s - 1; ++i) {
r = pduel->get_next_integer(i, s - 1);
card* t = svector[i];
svector[i] = svector[r];
svector[r] = t;
}
if (core.duel_options & DUEL_OLD_REPLAY)
pduel->random.shuffle_vector_old(svector);
else
pduel->random.shuffle_vector(svector);
reset_sequence(playerid, location);
}
}
......
......@@ -8,6 +8,63 @@
#ifndef MTRANDOM_H_
#define MTRANDOM_H_
#include <random>
class mt19937 {
public:
mt19937() :
rng(), rand_max((rng.max)()) {}
explicit mt19937(unsigned int seed) :
rng(seed), rand_max((rng.max)()) {}
// mersenne_twister_engine
void reset(unsigned int seed) {
rng.seed(seed);
}
unsigned int rand() {
return rng();
}
// uniform_int_distribution
int get_random_integer(int l, int h) {
unsigned int range = (unsigned int)(h - l + 1);
unsigned int secureMax = rand_max - rand_max % range;
unsigned int x;
do {
x = rng();
} while (x >= secureMax);
return (int)(l + x % range);
}
int get_random_integer_old(int l, int h) {
int result = (int)((double)rng() / rand_max * (h - l + 1)) + l;
if (result > h)
result = h;
return result;
}
// Fisher-Yates shuffle
template<typename T>
void shuffle_vector(std::vector<T>& v) {
int n = (int)v.size();
for (int i = 0; i < n - 1; ++i) {
int r = get_random_integer(i, n - 1);
std::swap(v[i], v[r]);
}
}
template<typename T>
void shuffle_vector_old(std::vector<T>& v) {
int n = (int)v.size();
for (int i = 0; i < n - 1; ++i) {
int r = get_random_integer_old(i, n - 1);
std::swap(v[i], v[r]);
}
}
private:
std::mt19937 rng;
const unsigned int rand_max;
};
//Mersenne Twister
class mtrandom {
public:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment