Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions extras/ai-battle/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "QuickStartGame.h"
#include "RTTR_Version.h"
#include "RttrConfig.h"
#include "ai/random.h"
#include "files.h"
#include "random/Random.h"
#include "s25util/System.h"
Expand All @@ -30,6 +31,7 @@ int main(int argc, char** argv)
boost::optional<std::string> replay_path;
boost::optional<std::string> savegame_path;
unsigned random_init = static_cast<unsigned>(std::chrono::high_resolution_clock::now().time_since_epoch().count());
unsigned random_ai_init = random_init;

po::options_description desc("Allowed options");
// clang-format off
Expand All @@ -41,6 +43,7 @@ int main(int argc, char** argv)
("replay", po::value(&replay_path),"Filename to write replay to (optional)")
("save", po::value(&savegame_path),"Filename to write savegame to (optional)")
("random_init", po::value(&random_init),"Seed value for the random number generator (optional)")
("random_ai_init", po::value(&random_ai_init),"Seed value for the AI random number generator (optional)")
("maxGF", po::value<unsigned>()->default_value(std::numeric_limits<unsigned>::max()),"Maximum number of game frames to run (optional)")
("version", "Show version information and exit")
;
Expand Down Expand Up @@ -85,10 +88,12 @@ int main(int argc, char** argv)
bnw::cout << argv[i] << " ";
bnw::cout << std::endl;
bnw::cout << "random_init: " << random_init << std::endl;
bnw::cout << "random_ai_init: " << random_ai_init << std::endl;
bnw::cout << std::endl;

RTTRCONFIG.Init();
RANDOM.Init(random_init);
AI::getRandomGenerator().seed(random_ai_init);

const bfs::path mapPath = RTTRCONFIG.ExpandPath(options["map"].as<std::string>());
const std::vector<AI::Info> ais = ParseAIOptions(options["ai"].as<std::vector<std::string>>());
Expand Down
12 changes: 7 additions & 5 deletions libs/s25main/ai/aijh/AIConstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "addons/const_addons.h"
#include "ai/AIInterface.h"
#include "ai/aijh/AIPlayerJH.h"
#include "ai/random.h"
#include "buildings/noBuildingSite.h"
#include "buildings/nobBaseMilitary.h"
#include "buildings/nobBaseWarehouse.h"
Expand Down Expand Up @@ -465,10 +466,12 @@ helpers::OptionalEnum<BuildingType> AIConstruction::ChooseMilitaryBuilding(const
const BuildingType biggestBld = GetBiggestAllowedMilBuilding().value();

const Inventory& inventory = aii.GetInventory();
if(((rand() % 3) == 0 || inventory.people[Job::Private] < 15)
uint8_t playerId = aii.GetPlayerId();
if((AI::randomValue<int>(0, 2) == 0 || inventory.people[Job::Private] < 15)
&& (inventory.goods[GoodType::Stones] > 6 || bldPlanner.GetNumBuildings(BuildingType::Quarry) > 0))
bld = BuildingType::Guardhouse;
if(aijh.getAIInterface().isHarborPosClose(pt, 19) && rand() % 10 != 0 && aijh.ggs.isEnabled(AddonId::SEA_ATTACK))
if(aijh.getAIInterface().isHarborPosClose(pt, 19) && AI::randomValue<int>(0, 9) != 0
&& aijh.ggs.isEnabled(AddonId::SEA_ATTACK))
{
if(aii.CanBuildBuildingtype(BuildingType::Watchtower))
return BuildingType::Watchtower;
Expand All @@ -478,13 +481,12 @@ helpers::OptionalEnum<BuildingType> AIConstruction::ChooseMilitaryBuilding(const
{
if(aijh.UpdateUpgradeBuilding() < 0 && bldPlanner.GetNumBuildingSites(biggestBld) < 1
&& (inventory.goods[GoodType::Stones] > 20 || bldPlanner.GetNumBuildings(BuildingType::Quarry) > 0)
&& rand() % 10 != 0)
&& AI::randomValue<int>(0, 9) != 0)
{
return biggestBld;
}
}

uint8_t playerId = aii.GetPlayerId();
sortedMilitaryBlds military = aii.gwb.LookForMilitaryBuildings(pt, 3);
for(const nobBaseMilitary* milBld : military)
{
Expand All @@ -493,7 +495,7 @@ helpers::OptionalEnum<BuildingType> AIConstruction::ChooseMilitaryBuilding(const
// Prüfen ob Feind in der Nähe
if(milBld->GetPlayer() != playerId && distance < 35)
{
int randmil = rand();
int randmil = AI::randomValue<int>(0, std::numeric_limits<int>::max());
bool buildCatapult = randmil % 8 == 0 && aii.CanBuildCatapult()
&& bldPlanner.GetNumAdditionalBuildingsWanted(BuildingType::Catapult) > 0;
// another catapult within "min" radius? ->dont build here!
Expand Down
19 changes: 9 additions & 10 deletions libs/s25main/ai/aijh/AIPlayerJH.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "RttrForeachPt.h"
#include "addons/const_addons.h"
#include "ai/AIEvents.h"
#include "ai/random.h"
#include "boost/filesystem/fstream.hpp"
#include "buildings/noBuildingSite.h"
#include "buildings/nobHarborBuilding.h"
Expand Down Expand Up @@ -39,7 +40,6 @@
#include <algorithm>
#include <array>
#include <memory>
#include <random>
#include <stdexcept>
#include <type_traits>

Expand Down Expand Up @@ -344,7 +344,7 @@ void AIPlayerJH::PlanNewBuildings(const unsigned gf)
DistributeGoodsByBlocking(GoodType::Boards, 30);
DistributeGoodsByBlocking(GoodType::Stones, 50);
// go to the picked random warehouse and try to build around it
int randomStore = rand() % (storehouses.size());
int randomStore = AI::randomValue<int>(0, storehouses.size() - 1);
auto it = storehouses.begin();
std::advance(it, randomStore);
const MapPoint whPos = (*it)->GetPos();
Expand All @@ -365,7 +365,7 @@ void AIPlayerJH::PlanNewBuildings(const unsigned gf)
const std::list<nobMilitary*>& militaryBuildings = aii.GetMilitaryBuildings();
if(militaryBuildings.empty())
return;
int randomMiliBld = rand() % militaryBuildings.size();
int randomMiliBld = AI::randomValue<int>(0, militaryBuildings.size() - 1);
auto it2 = militaryBuildings.begin();
std::advance(it2, randomMiliBld);
MapPoint bldPos = (*it2)->GetPos();
Expand Down Expand Up @@ -1209,7 +1209,7 @@ void AIPlayerJH::HandleExpedition(const noShip* ship)
aii.FoundColony(ship);
else
{
const unsigned offset = rand() % helpers::MaxEnumValue_v<ShipDirection>;
const unsigned offset = AI::randomValue<unsigned>(0, helpers::MaxEnumValue_v<ShipDirection> - 1);
for(auto dir : helpers::EnumRange<ShipDirection>{})
{
dir = ShipDirection((rttr::enum_cast(dir) + offset) % helpers::MaxEnumValue_v<ShipDirection>);
Expand Down Expand Up @@ -1254,9 +1254,7 @@ void AIPlayerJH::HandleTreeChopped(const MapPoint pt)

UpdateNodesAround(pt, 3);

int random = rand();

if(random % 2 == 0)
if(AI::randomValue<int>(0, 1) == 0)
AddMilitaryBuildJob(pt);
else // if (random % 12 == 0)
AddBuildJob(BuildingType::Woodcutter, pt);
Expand Down Expand Up @@ -1538,7 +1536,7 @@ void AIPlayerJH::TryToAttack()
// We skip the current building with a probability of limit/numMilBlds
// -> For twice the number of blds as the limit we will most likely skip every 2nd building
// This way we check roughly (at most) limit buildings but avoid any preference for one building over an other
if(rand() % numMilBlds > limit)
if(AI::randomValue<unsigned>(0, numMilBlds - 1) > limit)
continue;

if(milBld->GetFrontierDistance() == FrontierDistance::Far) // inland building? -> skip it
Expand Down Expand Up @@ -1571,7 +1569,7 @@ void AIPlayerJH::TryToAttack()

// shuffle everything but headquarters and harbors without any troops in them
std::shuffle(potentialTargets.begin() + hq_or_harbor_without_soldiers, potentialTargets.end(),
std::mt19937(std::random_device()()));
std::mt19937(AI::randomValue<unsigned>(0, 2047)));

// check for each potential attacking target the number of available attacking soldiers
for(const nobBaseMilitary* target : potentialTargets)
Expand Down Expand Up @@ -1704,7 +1702,8 @@ void AIPlayerJH::TrySeaAttack()
unsigned limit = 15;
unsigned skip = 0;
if(searcharoundharborspots.size() > 15)
skip = std::max<int>(rand() % (searcharoundharborspots.size() / 15 + 1) * 15, 1) - 1;
skip =
std::max<int>(AI::randomValue<int>(0, static_cast<int>(searcharoundharborspots.size() / 15) * 15), 1) - 1;
for(unsigned i = skip; i < searcharoundharborspots.size() && limit > 0; i++)
{
limit--;
Expand Down
16 changes: 16 additions & 0 deletions libs/s25main/ai/random.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (C) 2005 - 2025 Settlers Freaks (sf-team at siedler25.org)
//
// SPDX-License-Identifier: GPL-2.0-or-later

#include "ai/random.h"

namespace AI {

std::minstd_rand& getRandomGenerator()
{
std::random_device rnd_dev;
static std::minstd_rand rng(rnd_dev());
return rng;
}

} // namespace AI
20 changes: 20 additions & 0 deletions libs/s25main/ai/random.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (C) 2005 - 2025 Settlers Freaks (sf-team at siedler25.org)
//
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "helpers/random.h"
#include <random>

namespace AI {

std::minstd_rand& getRandomGenerator();

template<typename T>
T randomValue(T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>::max())
{
return helpers::randomValue(getRandomGenerator(), min, max);
}

} // namespace AI
Loading