Commit 11f32add authored by Chen Bill's avatar Chen Bill Committed by GitHub

Revert "Revert " Refactor random integer generation and shuffling (#760)" (#767)" (#768)

This reverts commit 6090f482.
parent 6090f482
......@@ -409,7 +409,7 @@ inline bool check_playerid(int32_t playerid) {
//Options
#define DUEL_TEST_MODE 0x01
#define DUEL_ATTACK_FIRST_TURN 0x02
#define DUEL_OLD_REPLAY 0x04
//#define DUEL_OLD_REPLAY 0x04
#define DUEL_OBSOLETE_RULING 0x08
#define DUEL_PSEUDO_SHUFFLE 0x10
#define DUEL_TAG_MODE 0x20
......
......@@ -143,10 +143,7 @@ void duel::set_responseb(byte* resp) {
std::memcpy(game_field->returns.bvalue, resp, SIZE_RETURN_VALUE);
}
int32_t duel::get_next_integer(int32_t l, int32_t h) {
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);
}
if (rng_version == 1)
return random.get_random_integer_v1(l, h);
return random.get_random_integer_v2(l, h);
}
......@@ -25,11 +25,13 @@ using card_set = std::set<card*, card_sort>;
class duel {
public:
char strbuffer[256];
std::vector<byte> message_buffer;
char strbuffer[256]{};
int32_t rng_version{ 2 };
interpreter* lua;
field* game_field;
mt19937 random;
mtrandom random;
std::vector<byte> message_buffer;
std::unordered_set<card*> cards;
std::unordered_set<card*> assumes;
std::unordered_set<group*> groups;
......
......@@ -957,10 +957,7 @@ void field::shuffle(uint8_t playerid, uint8_t location) {
if(location == LOCATION_EXTRA)
s = s - (int32_t)player[playerid].extra_p_count;
if(s > 1) {
if (core.duel_options & DUEL_OLD_REPLAY)
pduel->random.shuffle_vector_old(svector, 0, s - 1);
else
pduel->random.shuffle_vector(svector, 0, s - 1);
pduel->random.shuffle_vector(svector, 0, s, pduel->rng_version);
reset_sequence(playerid, location);
}
}
......
......@@ -12,60 +12,74 @@
#include <vector>
#include <utility>
class mt19937 {
class mtrandom {
public:
const unsigned int rand_max;
const unsigned int rand_max{ std::mt19937::max() };
mt19937() :
rng(), rand_max(rng.max()) {}
explicit mt19937(uint_fast32_t seed) :
rng(seed), rand_max(rng.max()) {}
mtrandom() :
rng() {}
mtrandom(uint32_t seq[], size_t len) {
std::seed_seq q(seq, seq + len);
rng.seed(q);
}
explicit mtrandom(uint_fast32_t value) :
rng(value) {}
mtrandom(std::seed_seq& q) :
rng(q) {}
mtrandom(const mtrandom& other) = delete;
void operator=(const mtrandom& other) = delete;
// mersenne_twister_engine
void reset(uint_fast32_t seed) {
rng.seed(seed);
void seed(uint32_t seq[], size_t len) {
std::seed_seq q(seq, seq + len);
rng.seed(q);
}
void seed(uint_fast32_t value) {
rng.seed(value);
}
void seed(std::seed_seq& q) {
rng.seed(q);
}
uint_fast32_t rand() {
return rng();
}
void discard(unsigned long long z) {
rng.discard(z);
}
// uniform_int_distribution
int get_random_integer(int l, int h) {
uint_fast32_t range = (uint_fast32_t)(h - l + 1);
uint_fast32_t secureMax = rng.max() - rng.max() % range;
// old vesion, discard too many numbers
int get_random_integer_v1(int l, int h) {
uint32_t range = (h - l + 1);
uint32_t secureMax = rand_max - rand_max % range;
uint_fast32_t x;
do {
x = rng();
} while (x >= secureMax);
return l + (int)(x % range);
}
int get_random_integer_old(int l, int h) {
int result = (int)((double)rng() / rng.max() * ((double)h - l + 1)) + l;
if (result > h)
result = h;
return result;
}
// Fisher-Yates shuffle v[a]~v[b]
template<typename T>
void shuffle_vector(std::vector<T>& v, int a = -1, int b = -1) {
if (a < 0)
a = 0;
if (b < 0)
b = (int)v.size() - 1;
for (int i = a; i < b; ++i) {
int r = get_random_integer(i, b);
std::swap(v[i], v[r]);
// N % k == (N - k) % k, discard the leftmost numbers
int get_random_integer_v2(int l, int h) {
uint32_t range = (h - l + 1);
uint32_t bound = -range % range;
auto x = rng();
while (x < bound) {
x = rng();
}
return l + (int)(x % range);
}
// Fisher-Yates shuffle [first, last)
template<typename T>
void shuffle_vector_old(std::vector<T>& v, int a = -1, int b = -1) {
if (a < 0)
a = 0;
if (b < 0)
b = (int)v.size() - 1;
for (int i = a; i < b; ++i) {
int r = get_random_integer_old(i, b);
void shuffle_vector(std::vector<T>& v, int first = 0, int last = INT32_MAX, int version = 2) {
if ((size_t)last > v.size())
last = v.size();
auto distribution = &mtrandom::get_random_integer_v2;
if (version == 1)
distribution = &mtrandom::get_random_integer_v1;
for (int i = first; i < last - 1; ++i) {
int r = (this->*distribution)(i, last - 1);
std::swap(v[i], v[r]);
}
}
......
......@@ -65,7 +65,15 @@ OCGCORE_API byte* default_script_reader(const char* script_name, int* slen) {
OCGCORE_API intptr_t create_duel(uint_fast32_t seed) {
duel* pduel = new duel();
duel_set.insert(pduel);
pduel->random.reset(seed);
pduel->random.seed(seed);
pduel->rng_version = 1;
return (intptr_t)pduel;
}
OCGCORE_API intptr_t create_duel_v2(uint32_t seed_sequence[]) {
duel* pduel = new duel();
duel_set.insert(pduel);
pduel->random.seed(seed_sequence, SEED_COUNT);
pduel->rng_version = 2;
return (intptr_t)pduel;
}
OCGCORE_API void start_duel(intptr_t pduel, uint32_t options) {
......
......@@ -22,6 +22,8 @@
#define OCGCORE_API EXTERN_C __attribute__ ((visibility ("default")))
#endif
#define SEED_COUNT 8
#define LEN_FAIL 0
#define LEN_EMPTY 4
#define LEN_HEADER 8
......@@ -42,6 +44,7 @@ uint32_t read_card(uint32_t code, card_data* data);
uint32_t handle_message(void* pduel, uint32_t message_type);
OCGCORE_API intptr_t create_duel(uint_fast32_t seed);
OCGCORE_API intptr_t create_duel_v2(uint32_t seed_sequence[]);
OCGCORE_API void start_duel(intptr_t pduel, uint32_t options);
OCGCORE_API void end_duel(intptr_t pduel);
OCGCORE_API void set_player_info(intptr_t pduel, int32_t playerid, int32_t lp, int32_t startcount, int32_t drawcount);
......
......@@ -41,7 +41,7 @@ workspace "ocgcoredll"
flags { "LinkTimeOptimization" }
end
staticruntime "On"
disablewarnings { "4334" }
disablewarnings { "4146", "4334" }
filter "action:vs*"
cdialect "C11"
......
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