Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
53 changes: 29 additions & 24 deletions src/openvic-simulation/country/CountryInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1928,7 +1928,7 @@ void CountryInstance::country_tick_before_map(
memory::vector<fixed_point_t>,
VECTORS_FOR_COUNTRY_TICK
> reusable_vectors,
memory::vector<size_t>& reusable_index_vector
memory::vector<good_index_t>& reusable_good_index_vector
) {
//TODO AI sliders
// + reparations + war subsidies
Expand Down Expand Up @@ -2015,7 +2015,7 @@ void CountryInstance::country_tick_before_map(
manage_national_stockpile(
reusable_goods_mask,
reusable_vectors,
reusable_index_vector,
reusable_good_index_vector,
available_funds
);

Expand Down Expand Up @@ -2052,22 +2052,26 @@ void CountryInstance::manage_national_stockpile(
memory::vector<fixed_point_t>,
VECTORS_FOR_COUNTRY_TICK
> reusable_vectors,
memory::vector<size_t>& reusable_index_vector,
memory::vector<good_index_t>& reusable_good_index_vector,
fixed_point_t& available_funds
) {
IndexedFlatMap<GoodDefinition, char>& wants_more_mask = reusable_goods_mask;
const size_t mask_size = wants_more_mask.get_keys().size();
memory::vector<fixed_point_t>& max_quantity_to_buy_per_good = reusable_vectors[0];
max_quantity_to_buy_per_good.resize(mask_size, 0);
memory::vector<fixed_point_t>& max_costs_per_good = reusable_vectors[1];
max_costs_per_good.resize(mask_size, 0);
memory::vector<fixed_point_t>& weights = reusable_vectors[2];
weights.resize(mask_size, 0);
memory::vector<size_t>& good_indices_to_buy = reusable_index_vector;

reusable_vectors[0].resize(mask_size, 0);
TypedSpan<good_index_t, fixed_point_t> max_quantity_to_buy_per_good { reusable_vectors[0] };

reusable_vectors[1].resize(mask_size, 0);
TypedSpan<good_index_t, fixed_point_t> max_costs_per_good { reusable_vectors[1] };

reusable_vectors[2].resize(mask_size, 0);
TypedSpan<good_index_t, fixed_point_t> weights { reusable_vectors[2] };

memory::vector<good_index_t>& good_indices_to_buy = reusable_good_index_vector;
fixed_point_t weights_sum = 0;

for (auto [good_instance, good_data] : goods_data) {
const size_t index = type_safe::get(good_instance.index);
const good_index_t good_index = good_instance.index;
if (good_data.is_automated || !good_data.is_selling) {
const fixed_point_t quantity_to_allocate_for = good_data.is_automated
? good_data.government_needs - good_data.stockpile_amount
Expand All @@ -2079,15 +2083,15 @@ void CountryInstance::manage_national_stockpile(
continue;
}

good_indices_to_buy.push_back(index);
max_quantity_to_buy_per_good[index] = max_quantity_to_buy;
good_indices_to_buy.push_back(good_index);
max_quantity_to_buy_per_good[good_index] = max_quantity_to_buy;

const fixed_point_t max_money_to_spend = max_costs_per_good[index] = market_instance.get_max_money_to_allocate_to_buy_quantity(
const fixed_point_t max_money_to_spend = max_costs_per_good[good_index] = market_instance.get_max_money_to_allocate_to_buy_quantity(
good_instance.good_definition,
quantity_to_allocate_for
);
wants_more_mask.set(good_instance.good_definition, true);
const fixed_point_t weight = weights[index] = fixed_point_t::usable_max / max_money_to_spend;
const fixed_point_t weight = weights[good_index] = fixed_point_t::usable_max / max_money_to_spend;
weights_sum += weight;
} else {
const fixed_point_t quantity_to_sell = good_data.stockpile_amount - good_data.stockpile_cutoff;
Expand All @@ -2097,7 +2101,7 @@ void CountryInstance::manage_national_stockpile(
market_instance.place_market_sell_order(
{
good_instance.good_definition,
this,
index,
quantity_to_sell,
this,
after_sell,
Expand All @@ -2108,13 +2112,14 @@ void CountryInstance::manage_national_stockpile(
}

if (weights_sum > 0) {
memory::vector<fixed_point_t>& money_to_spend_per_good = reusable_vectors[3];
money_to_spend_per_good.resize(mask_size, 0);
reusable_vectors[3].resize(mask_size, 0);
TypedSpan<good_index_t, fixed_point_t> money_to_spend_per_good { reusable_vectors[3] };

fixed_point_t cash_left_to_spend_draft = available_funds;
bool needs_redistribution = true;
while (needs_redistribution) {
needs_redistribution = false;
for (const size_t good_index : good_indices_to_buy) {
for (const good_index_t good_index : good_indices_to_buy) {
char& wants_more = wants_more_mask.at_index(good_index);
if (!wants_more) {
continue;
Expand All @@ -2138,7 +2143,7 @@ void CountryInstance::manage_national_stockpile(
break;
}

GoodInstance const& good_instance = goods_data.get_keys()[good_index];
GoodInstance const& good_instance = goods_data.get_key_at_index(good_index);
GoodDefinition const& good_definition = good_instance.good_definition;
const fixed_point_t max_possible_quantity_bought = cash_available_for_good / market_instance.get_min_next_price(good_definition);
if (max_possible_quantity_bought < fixed_point_t::epsilon) {
Expand All @@ -2149,20 +2154,20 @@ void CountryInstance::manage_national_stockpile(
}
}

for (const size_t good_index : good_indices_to_buy) {
for (const good_index_t good_index : good_indices_to_buy) {
const fixed_point_t max_quantity_to_buy = max_quantity_to_buy_per_good[good_index];
const fixed_point_t money_to_spend = money_to_spend_per_good[good_index];
if (money_to_spend <= 0) {
continue;
}

GoodInstance const& good_instance = goods_data.get_keys()[good_index];
GoodInstance const& good_instance = goods_data.get_key_at_index(good_index);
GoodDefinition const& good_definition = good_instance.good_definition;
available_funds -= money_to_spend;
market_instance.place_buy_up_to_order(
{
good_definition,
this,
index,
max_quantity_to_buy,
money_to_spend,
this,
Expand All @@ -2176,7 +2181,7 @@ void CountryInstance::manage_national_stockpile(
for (auto& reusable_vector : reusable_vectors) {
reusable_vector.clear();
}
reusable_index_vector.clear();
reusable_good_index_vector.clear();
}

void CountryInstance::country_tick_after_map(const Date today) {
Expand Down
4 changes: 2 additions & 2 deletions src/openvic-simulation/country/CountryInstance.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ namespace OpenVic {
memory::vector<fixed_point_t>,
VECTORS_FOR_COUNTRY_TICK
> reusable_vectors,
memory::vector<size_t>& reusable_index_vector,
memory::vector<good_index_t>& reusable_good_index_vector,
fixed_point_t& available_funds
);

Expand Down Expand Up @@ -665,7 +665,7 @@ namespace OpenVic {
memory::vector<fixed_point_t>,
VECTORS_FOR_COUNTRY_TICK
> reusable_vectors,
memory::vector<size_t>& reusable_index_vector
memory::vector<good_index_t>& reusable_good_index_vector
);
void country_tick_after_map(const Date today);

Expand Down
1 change: 1 addition & 0 deletions src/openvic-simulation/economy/GoodInstance.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "openvic-simulation/economy/trading/GoodMarket.hpp"
#include "openvic-simulation/types/HasIndex.hpp"
#include "openvic-simulation/types/HasIdentifier.hpp"
#include "openvic-simulation/types/IndexedFlatMap.hpp"
#include "openvic-simulation/types/TypedIndices.hpp"

namespace OpenVic {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "openvic-simulation/population/PopType.hpp"
#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
#include "openvic-simulation/types/PopSize.hpp"
#include "openvic-simulation/types/TypedIndices.hpp"
#include "openvic-simulation/utility/Logger.hpp"
#include "openvic-simulation/utility/Containers.hpp"

Expand Down Expand Up @@ -147,7 +148,9 @@ void ResourceGatheringOperation::rgo_tick(memory::vector<fixed_point_t>& reusabl
market_instance.place_market_sell_order(
{
production_type.output_good,
country_to_report_economy_nullable,
country_to_report_economy_nullable == nullptr
? std::nullopt
: std::optional<country_index_t>{country_to_report_economy_nullable->index},
output_quantity_yesterday,
this,
after_sell,
Expand Down
15 changes: 8 additions & 7 deletions src/openvic-simulation/economy/trading/BuyUpToOrder.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#pragma once

#include <optional>

#include "openvic-simulation/economy/trading/BuyResult.hpp"
#include "openvic-simulation/types/TypedIndices.hpp"

namespace OpenVic {
struct CountryInstance;

struct GoodBuyUpToOrder {
using actor_t = void*;
using callback_t = void(*)(const actor_t, BuyResult const&);
Expand All @@ -14,17 +15,17 @@ namespace OpenVic {
const callback_t after_trade;

public:
CountryInstance const* const country_nullable;
const std::optional<country_index_t> country_index_optional;
const fixed_point_t max_quantity;
const fixed_point_t money_to_spend;

constexpr GoodBuyUpToOrder(
CountryInstance const* const new_country_nullable,
const std::optional<country_index_t> new_country_index_optional,
const fixed_point_t new_max_quantity,
const fixed_point_t new_money_to_spend,
const actor_t new_actor,
const callback_t new_after_trade
) : country_nullable { new_country_nullable },
) : country_index_optional { new_country_index_optional },
max_quantity { new_max_quantity },
money_to_spend { new_money_to_spend },
actor { new_actor },
Expand All @@ -47,13 +48,13 @@ namespace OpenVic {

constexpr BuyUpToOrder(
GoodDefinition const& new_good,
CountryInstance const* const new_country_nullable,
const std::optional<country_index_t> new_country_index_optional,
const fixed_point_t new_max_quantity,
const fixed_point_t new_money_to_spend,
const actor_t new_actor,
const callback_t new_after_trade
) : GoodBuyUpToOrder {
new_country_nullable,
new_country_index_optional,
new_max_quantity,
new_money_to_spend,
new_actor,
Expand Down
71 changes: 37 additions & 34 deletions src/openvic-simulation/economy/trading/GoodMarket.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "GoodMarket.hpp"
#include <algorithm>

#include "openvic-simulation/country/CountryInstance.hpp"
#include "openvic-simulation/economy/GoodDefinition.hpp"
#include "openvic-simulation/economy/trading/BuyUpToOrder.hpp"
#include "openvic-simulation/economy/trading/MarketSellOrder.hpp"
Expand Down Expand Up @@ -66,9 +66,9 @@ void GoodMarket::add_market_sell_order(GoodMarketSellOrder&& market_sell_order)
}

void GoodMarket::execute_orders(
IndexedFlatMap<CountryInstance, fixed_point_t>& reusable_country_map_0,
IndexedFlatMap<CountryInstance, fixed_point_t>& reusable_country_map_1,
utility::forwardable_span<
TypedSpan<country_index_t, fixed_point_t> reusable_country_map_0,
TypedSpan<country_index_t, fixed_point_t> reusable_country_map_1,
std::span<
memory::vector<fixed_point_t>,
VECTORS_FOR_EXECUTE_ORDERS
> reusable_vectors
Expand Down Expand Up @@ -120,12 +120,12 @@ void GoodMarket::execute_orders(
}
}
} else {
IndexedFlatMap<CountryInstance, fixed_point_t>& supply_per_country = reusable_country_map_0;
IndexedFlatMap<CountryInstance, fixed_point_t>& actual_bought_per_country = reusable_country_map_1;
TypedSpan<country_index_t, fixed_point_t> supply_per_country = reusable_country_map_0;
TypedSpan<country_index_t, fixed_point_t> actual_bought_per_country = reusable_country_map_1;
for (GoodMarketSellOrder const& market_sell_order : market_sell_orders) {
CountryInstance const* const country_nullable = market_sell_order.country_nullable;
if (country_nullable != nullptr) {
supply_per_country.at(*country_nullable) += market_sell_order.quantity;
const std::optional<country_index_t> country_index_optional = market_sell_order.country_index_optional;
if (country_index_optional.has_value()) {
supply_per_country[country_index_optional.value()] += market_sell_order.quantity;
}
supply_sum += market_sell_order.quantity;
}
Expand Down Expand Up @@ -191,10 +191,10 @@ void GoodMarket::execute_orders(
continue;
}

CountryInstance const* const country_nullable = buy_up_to_order.country_nullable;
if (country_nullable != nullptr) {
const std::optional<country_index_t> country_index_optional = buy_up_to_order.country_index_optional;
if (country_index_optional.has_value()) {
//subtract as it might be updated below
actual_bought_per_country.at(*country_nullable) -= distributed_supply;
actual_bought_per_country[country_index_optional.value()] -= distributed_supply;
}

distributed_supply = fixed_point_t::mul_div(
Expand All @@ -210,8 +210,8 @@ void GoodMarket::execute_orders(
purchasing_power_sum -= purchasing_power_per_order[i];
}

if (country_nullable != nullptr) {
actual_bought_per_country.at(*country_nullable) += distributed_supply;
if (country_index_optional.has_value()) {
actual_bought_per_country[country_index_optional.value()] += distributed_supply;
}

if (someone_bought_max_quantity) {
Expand Down Expand Up @@ -280,9 +280,9 @@ void GoodMarket::execute_orders(
buy_up_to_order.money_to_spend / new_price
);

CountryInstance const* const country_nullable = buy_up_to_order.country_nullable;
if (country_nullable != nullptr) {
actual_bought_per_country.at(*country_nullable) += quantity_bought_per_order[i];
const std::optional<country_index_t> country_index_optional = buy_up_to_order.country_index_optional;
if (country_index_optional.has_value()) {
actual_bought_per_country[country_index_optional.value()] += quantity_bought_per_order[i];
}
}

Expand Down Expand Up @@ -324,8 +324,9 @@ void GoodMarket::execute_orders(
} else {
//quantity is evenly divided after taking domestic buyers into account
fixed_point_t total_quantity_traded_domestically = 0;
for (auto const& [country, actual_bought] : actual_bought_per_country) {
const fixed_point_t supply = supply_per_country.at(country);
for (country_index_t country_index(0); country_index < actual_bought_per_country.size(); ++country_index) {
const fixed_point_t actual_bought = actual_bought_per_country[country_index];
const fixed_point_t supply = supply_per_country[country_index];
const fixed_point_t traded_domestically = std::min(supply, actual_bought);
total_quantity_traded_domestically += traded_domestically;
}
Expand All @@ -337,13 +338,14 @@ void GoodMarket::execute_orders(

fixed_point_t quantity_sold_domestically;
fixed_point_t quantity_offered_as_export;
CountryInstance const* const country_nullable = market_sell_order.country_nullable;
if (country_nullable == nullptr) {
const std::optional<country_index_t> country_index_optional = market_sell_order.country_index_optional;
if (!country_index_optional.has_value()) {
quantity_sold_domestically = 0;
quantity_offered_as_export = quantity_offered;
} else {
const fixed_point_t total_bought_domestically = actual_bought_per_country.at(*country_nullable);
const fixed_point_t total_domestic_supply = supply_per_country.at(*country_nullable);
const country_index_t country_index = country_index_optional.value();
const fixed_point_t total_bought_domestically = actual_bought_per_country[country_index];
const fixed_point_t total_domestic_supply = supply_per_country[country_index];
quantity_sold_domestically = total_bought_domestically >= total_domestic_supply
? quantity_offered
: fixed_point_t::mul_div(
Expand Down Expand Up @@ -381,11 +383,11 @@ void GoodMarket::execute_orders(
}
}

reusable_country_map_0.fill(0);
reusable_country_map_1.fill(0);
std::fill(reusable_country_map_0.begin(), reusable_country_map_0.end(), 0);
std::fill(reusable_country_map_1.begin(), reusable_country_map_1.end(), 0);
market_sell_orders.clear();
supply_per_country.fill(0);
actual_bought_per_country.fill(0);
std::fill(supply_per_country.begin(), supply_per_country.end(), 0);
std::fill(actual_bought_per_country.begin(), actual_bought_per_country.end(), 0);
}

price_change_yesterday = new_price - price;
Expand All @@ -400,8 +402,8 @@ void GoodMarket::execute_orders(

void GoodMarket::execute_buy_orders(
const fixed_point_t new_price,
IndexedFlatMap<CountryInstance, fixed_point_t> const& actual_bought_per_country,
IndexedFlatMap<CountryInstance, fixed_point_t> const& supply_per_country,
TypedSpan<country_index_t, const fixed_point_t> actual_bought_per_country,
TypedSpan<country_index_t, const fixed_point_t> supply_per_country,
std::span<const fixed_point_t> quantity_bought_per_order
) {
quantity_traded_yesterday = 0;
Expand All @@ -418,15 +420,16 @@ void GoodMarket::execute_buy_orders(
fixed_point_t::epsilon //we know from purchasing power that you can afford it.
);

fixed_point_t money_spent_on_imports;
CountryInstance const* const country_nullable = buy_up_to_order.country_nullable;
if (country_nullable == nullptr) {
fixed_point_t money_spent_on_imports;
const std::optional<country_index_t> country_index_optional = buy_up_to_order.country_index_optional;
if (!country_index_optional.has_value()) {
//could be trade between native Americans and tribal Africa, so it's all imported
money_spent_on_imports = money_spent_total;
} else {
const country_index_t country_index = country_index_optional.value();
//must be > 0, since quantity_bought > 0
const fixed_point_t actual_bought_in_my_country = actual_bought_per_country.at(*country_nullable);
const fixed_point_t supply_in_my_country = supply_per_country.at(*country_nullable);
const fixed_point_t actual_bought_in_my_country = actual_bought_per_country[country_index];
const fixed_point_t supply_in_my_country = supply_per_country[country_index];

if (supply_in_my_country >= actual_bought_in_my_country) {
//no imports
Expand Down
Loading