Skip to content

Commit

Permalink
use the mersenne twister rng for random faction, side shuffling
Browse files Browse the repository at this point in the history
This is because players were able to notice problems when the
rand rng was used for random map pools, so it cannot hurt to use
the good rng for these things also.
  • Loading branch information
cbeck88 committed Mar 12, 2015
1 parent 8146c42 commit 8312cd1
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 17 deletions.
18 changes: 11 additions & 7 deletions src/game_initialization/connect_engine.cpp
Expand Up @@ -21,6 +21,7 @@
#include "map.hpp"
#include "multiplayer_ui.hpp"
#include "mp_game_utils.hpp"
#include "mt_rng.hpp"
#include "tod_manager.hpp"

#include <boost/foreach.hpp>
Expand Down Expand Up @@ -391,8 +392,9 @@ void connect_engine::start_game(LOAD_USERS load_users)
{
DBG_MP << "starting a new game" << std::endl;

// Resolves the "random faction", "random gender" and "random message"
// Must be done before shuffle sides, or some cases will cause errors
// Resolves the "random faction", "random gender" and "random message"
// Must be done before shuffle sides, or some cases will cause errors
rand_rng::mt_rng rng; // Make an RNG for all the shuffling and random faction operations
BOOST_FOREACH(side_engine_ptr side, side_engines_) {
std::vector<std::string> avoid_faction_ids;

Expand All @@ -415,7 +417,7 @@ void connect_engine::start_game(LOAD_USERS load_users)
}
}
}
side->resolve_random(avoid_faction_ids);
side->resolve_random(rng, avoid_faction_ids);
}

// Shuffle sides (check settings and if it is a re-loaded game).
Expand All @@ -434,7 +436,7 @@ void connect_engine::start_game(LOAD_USERS load_users)
// Fisher-Yates shuffle.
for (int i = playable_sides.size(); i > 1; i--)
{
int j_side = playable_sides[rand() % i];
int j_side = playable_sides[rng.get_next_random() % i];
int i_side = playable_sides[i - 1];

if (i_side == j_side) continue; //nothing to swap
Expand Down Expand Up @@ -485,6 +487,8 @@ void connect_engine::start_game_commandline(

typedef boost::tuple<unsigned int, std::string> mp_option;

rand_rng::mt_rng rng;

unsigned num = 0;
BOOST_FOREACH(side_engine_ptr side, side_engines_) {
num++;
Expand Down Expand Up @@ -535,7 +539,7 @@ void connect_engine::start_game_commandline(

// Finally, resolve "random faction",
// "random gender" and "random message", if any remains unresolved.
side->resolve_random();
side->resolve_random(rng);
} // end top-level loop

update_and_send_diff(true);
Expand Down Expand Up @@ -1189,15 +1193,15 @@ bool side_engine::swap_sides_on_drop_target(const unsigned drop_target) {
return true;
}

void side_engine::resolve_random(const std::vector<std::string> & avoid_faction_ids)
void side_engine::resolve_random(rand_rng::mt_rng & rng, const std::vector<std::string> & avoid_faction_ids)
{
if (parent_.params_.saved_game) {
return;
}

chose_random_ = flg_.is_random_faction();

flg_.resolve_random(avoid_faction_ids);
flg_.resolve_random(rng, avoid_faction_ids);

LOG_MP << "side " << (index_ + 1) << ": faction=" <<
(flg_.current_faction())["name"] << ", leader=" <<
Expand Down
4 changes: 3 additions & 1 deletion src/game_initialization/connect_engine.hpp
Expand Up @@ -22,6 +22,8 @@
#include "saved_game.hpp"
#include <boost/scoped_ptr.hpp>

namespace rand_rng { class mt_rng; }

namespace ng {

enum controller {
Expand Down Expand Up @@ -157,7 +159,7 @@ class side_engine

bool swap_sides_on_drop_target(const unsigned drop_target);

void resolve_random(const std::vector<std::string> & avoid_faction_ids = std::vector<std::string>());
void resolve_random( rand_rng::mt_rng & rng, const std::vector<std::string> & avoid_faction_ids = std::vector<std::string>());

// Resets this side to its default state.
void reset();
Expand Down
9 changes: 5 additions & 4 deletions src/game_initialization/flg_manager.cpp
Expand Up @@ -16,6 +16,7 @@
#include "config.hpp"
#include "formula_string_utils.hpp"
#include "gettext.hpp"
#include "mt_rng.hpp"
#include "unit_types.hpp"
#include "wml_separators.hpp"

Expand Down Expand Up @@ -215,7 +216,7 @@ bool flg_manager::is_random_faction()
// assigning as we would have if it were off.
// If there is still no options we throw a config error because it means the
// era is misconfigured.
void flg_manager::resolve_random(const std::vector<std::string> & avoid) {
void flg_manager::resolve_random(rand_rng::mt_rng & rng, const std::vector<std::string> & avoid) {
if (is_random_faction()) {
std::vector<std::string> faction_choices, faction_excepts;

Expand Down Expand Up @@ -272,7 +273,7 @@ void flg_manager::resolve_random(const std::vector<std::string> & avoid) {
}

const int faction_index =
nonrandom_sides[rand() % nonrandom_sides.size()];
nonrandom_sides[rng.get_next_random() % nonrandom_sides.size()];
current_faction_ = available_factions_[faction_index];

update_available_leaders();
Expand All @@ -297,7 +298,7 @@ void flg_manager::resolve_random(const std::vector<std::string> & avoid) {
"Unable to find a leader type for faction $faction",
i18n_symbols));
} else {
const int lchoice = rand() % nonrandom_leaders.size();
const int lchoice = rng.get_next_random() % nonrandom_leaders.size();
current_leader_ = nonrandom_leaders[lchoice];

update_available_genders();
Expand All @@ -316,7 +317,7 @@ void flg_manager::resolve_random(const std::vector<std::string> & avoid) {
}
}

const int gchoice = rand() % nonrandom_genders.size();
const int gchoice = rng.get_next_random() % nonrandom_genders.size();
current_gender_ = nonrandom_genders[gchoice];
} else {
utils::string_map i18n_symbols;
Expand Down
3 changes: 2 additions & 1 deletion src/game_initialization/flg_manager.hpp
Expand Up @@ -20,6 +20,7 @@
#include <vector>

class config;
namespace rand_rng { class mt_rng; }

namespace ng {

Expand Down Expand Up @@ -55,7 +56,7 @@ class flg_manager
void reset_gender_combo(gui::combo& combo_gender) const;

bool is_random_faction();
void resolve_random(const std::vector<std::string> & avoid); //Argument is a list of faction ids we don't want to match, used to implement random faction modes. If it is not possible to resolve then we just proceed anyways rather than give an error.
void resolve_random(rand_rng::mt_rng & rng, const std::vector<std::string> & avoid); //Second Argument is a list of faction ids we don't want to match, used to implement random faction modes. If it is not possible to resolve then we just proceed anyways rather than give an error.

// Picks the first faction with the greater amount of data
// matching the criteria.
Expand Down
12 changes: 8 additions & 4 deletions src/tests/test_mp_connect.cpp
Expand Up @@ -21,6 +21,7 @@
#include "game_initialization/multiplayer_connect.hpp"
#include "game_initialization/multiplayer_ui.hpp"
#include "hotkey/hotkey_manager.hpp"
#include "mt_rng.hpp"
#include "saved_game.hpp"

#include <boost/foreach.hpp>
Expand Down Expand Up @@ -53,6 +54,7 @@ namespace {

boost::scoped_ptr<game_display> disp;
boost::scoped_ptr<saved_game> state;
boost::scoped_ptr<rand_rng::mt_rng> rng;

}

Expand Down Expand Up @@ -87,6 +89,8 @@ struct mp_connect_fixture {
game_config().find_child(lexical_cast<std::string>(game_classification::MULTIPLAYER), "id", state->mp_settings().name));

state->mp_settings().num_turns = state->get_starting_pos()["turns"];

rng.reset(new rand_rng::mt_rng());
}
~mp_connect_fixture()
{
Expand Down Expand Up @@ -299,7 +303,7 @@ BOOST_AUTO_TEST_CASE( flg_map_settings )
side.clear();
side["faction"] = "Random";
side_engine.reset(create_side_engine(side, connect_engine.get()));
side_engine->resolve_random();
side_engine->resolve_random(*rng);
BOOST_CHECK( side_engine->flg().current_faction()["id"] != "Random" );
BOOST_CHECK( side_engine->flg().current_leader() != "random" &&
side_engine->flg().current_leader() != "null");
Expand All @@ -311,7 +315,7 @@ BOOST_AUTO_TEST_CASE( flg_map_settings )
side["faction"] = "Random";
side["type"] = "Troll";
side_engine.reset(create_side_engine(side, connect_engine.get()));
side_engine->resolve_random();
side_engine->resolve_random(*rng);
BOOST_CHECK( side_engine->flg().current_faction()["id"] != "Random" );
BOOST_CHECK_EQUAL( side_engine->flg().current_leader(), "Troll" );
BOOST_CHECK( side_engine->flg().current_gender() != "random" &&
Expand All @@ -323,7 +327,7 @@ BOOST_AUTO_TEST_CASE( flg_map_settings )
side["type"] = "White Mage";
side["gender"] = "male";
side_engine.reset(create_side_engine(side, connect_engine.get()));
side_engine->resolve_random();
side_engine->resolve_random(*rng);
BOOST_CHECK( side_engine->flg().current_faction()["id"] != "Random" );
BOOST_CHECK_EQUAL( side_engine->flg().current_leader(), "White Mage" );
BOOST_CHECK_EQUAL( side_engine->flg().current_gender(), "male" );
Expand All @@ -332,7 +336,7 @@ BOOST_AUTO_TEST_CASE( flg_map_settings )
side.clear();
side["type"] = "random";
side_engine.reset(create_side_engine(side, connect_engine.get()));
side_engine->resolve_random();
side_engine->resolve_random(*rng);
BOOST_CHECK( side_engine->flg().current_leader() != "random" );
}

Expand Down

0 comments on commit 8312cd1

Please sign in to comment.