Commit 675dcf64 authored by mercury233's avatar mercury233 Committed by GitHub

Revert "Revert "Revert " Refactor random integer generation and shuffling (#7…" (#769)

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