From fb78879fac4e11f0b320d2592d93afbc499e67ca Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Sat, 18 Apr 2026 05:38:37 -0700 Subject: [PATCH] Carry annual finance news family candidates --- crates/rrt-runtime/src/import.rs | 1 + crates/rrt-runtime/src/lib.rs | 3 +- crates/rrt-runtime/src/runtime.rs | 41 ++++++++++++ crates/rrt-runtime/src/step.rs | 106 ++++++++++++++++++++++++++++++ crates/rrt-runtime/src/summary.rs | 24 +++++++ 5 files changed, 174 insertions(+), 1 deletion(-) diff --git a/crates/rrt-runtime/src/import.rs b/crates/rrt-runtime/src/import.rs index 172b7c2..f506bcc 100644 --- a/crates/rrt-runtime/src/import.rs +++ b/crates/rrt-runtime/src/import.rs @@ -13997,6 +13997,7 @@ mod tests { annual_bond_last_issued_principal_total: 0, annual_stock_repurchase_last_share_count: 0, annual_stock_issue_last_share_count: 0, + annual_finance_last_news_family_candidates: BTreeMap::new(), chairman_issue_opinion_terms_raw_i32: BTreeMap::new(), chairman_personality_raw_u8: BTreeMap::new(), }, diff --git a/crates/rrt-runtime/src/lib.rs b/crates/rrt-runtime/src/lib.rs index 9ed1516..e0e736d 100644 --- a/crates/rrt-runtime/src/lib.rs +++ b/crates/rrt-runtime/src/lib.rs @@ -70,7 +70,8 @@ pub use runtime::{ RuntimeTerritory, RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts, RuntimeTrain, RuntimeWorldFinanceNeighborhoodCandidate, RuntimeWorldIssueState, RuntimeWorldRestoreState, - runtime_annual_bond_principal_flow_relation_label, runtime_company_annual_bond_policy_state, + runtime_annual_bond_principal_flow_relation_label, + runtime_annual_finance_news_family_candidate_label, runtime_company_annual_bond_policy_state, runtime_company_annual_creditor_pressure_state, runtime_company_annual_deep_distress_state, runtime_company_annual_dividend_policy_state, runtime_company_annual_finance_policy_action_label, diff --git a/crates/rrt-runtime/src/runtime.rs b/crates/rrt-runtime/src/runtime.rs index 39cffa8..61e3571 100644 --- a/crates/rrt-runtime/src/runtime.rs +++ b/crates/rrt-runtime/src/runtime.rs @@ -1245,6 +1245,8 @@ pub struct RuntimeServiceState { #[serde(default)] pub annual_stock_issue_last_share_count: u64, #[serde(default)] + pub annual_finance_last_news_family_candidates: BTreeMap, + #[serde(default)] pub chairman_issue_opinion_terms_raw_i32: BTreeMap>, #[serde(default)] pub chairman_personality_raw_u8: BTreeMap, @@ -2155,6 +2157,18 @@ impl RuntimeState { )); } } + for company_id in self + .service_state + .annual_finance_last_news_family_candidates + .keys() + { + if !seen_company_ids.contains(company_id) { + return Err(format!( + "service_state.annual_finance_last_news_family_candidates references unknown company_id {}", + company_id + )); + } + } for chairman_profile_id in self .service_state .chairman_issue_opinion_terms_raw_i32 @@ -3649,6 +3663,33 @@ pub fn runtime_annual_bond_principal_flow_relation_label( } } +pub fn runtime_annual_finance_news_family_candidate_label( + action: RuntimeCompanyAnnualFinancePolicyAction, + retired_principal_total: u64, + issued_principal_total: u64, + repurchased_share_count: u64, + issued_share_count: u64, +) -> Option<&'static str> { + match action { + RuntimeCompanyAnnualFinancePolicyAction::CreditorPressureBankruptcy + | RuntimeCompanyAnnualFinancePolicyAction::DeepDistressBankruptcyFallback => Some("2881"), + RuntimeCompanyAnnualFinancePolicyAction::BondIssue => { + runtime_annual_bond_principal_flow_relation_label( + retired_principal_total, + issued_principal_total, + ) + .map(|_| "2882_2886") + } + RuntimeCompanyAnnualFinancePolicyAction::StockRepurchase => { + (repurchased_share_count > 0).then_some("2887") + } + RuntimeCompanyAnnualFinancePolicyAction::StockIssue => { + (issued_share_count > 0).then_some("4053") + } + _ => None, + } +} + fn runtime_company_stock_issue_price_to_book_ratio_f64( pressured_support_adjusted_share_price_scalar: f64, book_value_per_share: f64, diff --git a/crates/rrt-runtime/src/step.rs b/crates/rrt-runtime/src/step.rs index 47e7669..789c5d0 100644 --- a/crates/rrt-runtime/src/step.rs +++ b/crates/rrt-runtime/src/step.rs @@ -15,6 +15,7 @@ use crate::{ RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecordTemplate, RuntimePlayerTarget, RuntimeState, RuntimeSummary, RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts, calendar::BoundaryEventKind, + runtime_annual_finance_news_family_candidate_label, runtime_company_annual_dividend_policy_state, runtime_company_annual_finance_policy_state, runtime_company_annual_stock_issue_state, runtime_company_annual_stock_repurchase_state, runtime_company_book_value_per_share, runtime_company_credit_rating, @@ -499,6 +500,10 @@ fn service_company_annual_finance_policy( .service_state .annual_finance_last_actions .retain(|company_id, _| active_company_id_set.contains(company_id)); + state + .service_state + .annual_finance_last_news_family_candidates + .retain(|company_id, _| active_company_id_set.contains(company_id)); state.service_state.annual_finance_service_calls += 1; state.service_state.annual_bond_last_retired_principal_total = 0; state.service_state.annual_bond_last_issued_principal_total = 0; @@ -517,6 +522,10 @@ fn service_company_annual_finance_policy( .service_state .annual_finance_last_actions .insert(company_id, policy_state.action); + state + .service_state + .annual_finance_last_news_family_candidates + .remove(&company_id); *state .service_state .annual_finance_action_counts @@ -554,6 +563,18 @@ fn service_company_annual_finance_policy( crate::RuntimeCompanyAnnualFinancePolicyAction::CreditorPressureBankruptcy | crate::RuntimeCompanyAnnualFinancePolicyAction::DeepDistressBankruptcyFallback => { if service_apply_company_bankruptcy(state, company_id) { + if let Some(label) = runtime_annual_finance_news_family_candidate_label( + policy_state.action, + state.service_state.annual_bond_last_retired_principal_total, + state.service_state.annual_bond_last_issued_principal_total, + state.service_state.annual_stock_repurchase_last_share_count, + state.service_state.annual_stock_issue_last_share_count, + ) { + state + .service_state + .annual_finance_last_news_family_candidates + .insert(company_id, label.to_string()); + } applied_effect_count += 1; mutated_company_ids.insert(company_id); } @@ -626,6 +647,18 @@ fn service_company_annual_finance_policy( market_state.current_issue_calendar_word = current_tuple_word_0; market_state.current_issue_calendar_word_2 = current_tuple_word_1; if mutated { + if let Some(label) = runtime_annual_finance_news_family_candidate_label( + policy_state.action, + state.service_state.annual_bond_last_retired_principal_total, + state.service_state.annual_bond_last_issued_principal_total, + state.service_state.annual_stock_repurchase_last_share_count, + state.service_state.annual_stock_issue_last_share_count, + ) { + state + .service_state + .annual_finance_last_news_family_candidates + .insert(company_id, label.to_string()); + } applied_effect_count += 1; mutated_company_ids.insert(company_id); } @@ -773,6 +806,18 @@ fn service_company_annual_finance_policy( .unwrap_or(company.debt); } if mutated { + if let Some(label) = runtime_annual_finance_news_family_candidate_label( + policy_state.action, + state.service_state.annual_bond_last_retired_principal_total, + state.service_state.annual_bond_last_issued_principal_total, + state.service_state.annual_stock_repurchase_last_share_count, + state.service_state.annual_stock_issue_last_share_count, + ) { + state + .service_state + .annual_finance_last_news_family_candidates + .insert(company_id, label.to_string()); + } applied_effect_count += 1; mutated_company_ids.insert(company_id); } @@ -850,6 +895,18 @@ fn service_company_annual_finance_policy( .saturating_add(u64::from(batch_size)); } if mutated { + if let Some(label) = runtime_annual_finance_news_family_candidate_label( + policy_state.action, + state.service_state.annual_bond_last_retired_principal_total, + state.service_state.annual_bond_last_issued_principal_total, + state.service_state.annual_stock_repurchase_last_share_count, + state.service_state.annual_stock_issue_last_share_count, + ) { + state + .service_state + .annual_finance_last_news_family_candidates + .insert(company_id, label.to_string()); + } applied_effect_count += 1; mutated_company_ids.insert(company_id); } @@ -2909,6 +2966,13 @@ mod tests { state.service_state.annual_finance_last_actions.get(&22), Some(&crate::RuntimeCompanyAnnualFinancePolicyAction::StockIssue) ); + assert_eq!( + state + .service_state + .annual_finance_last_news_family_candidates + .get(&22), + Some(&"4053".to_string()) + ); assert_eq!( state.service_state.annual_stock_issue_last_share_count, 4_000 @@ -3077,6 +3141,13 @@ mod tests { state.service_state.annual_finance_last_actions.get(&23), Some(&crate::RuntimeCompanyAnnualFinancePolicyAction::StockRepurchase) ); + assert_eq!( + state + .service_state + .annual_finance_last_news_family_candidates + .get(&23), + Some(&"2887".to_string()) + ); assert_eq!(state.service_state.annual_stock_issue_last_share_count, 0); assert_eq!( state.service_state.annual_stock_repurchase_last_share_count, @@ -3199,6 +3270,13 @@ mod tests { state.service_state.annual_finance_last_actions.get(&24), Some(&crate::RuntimeCompanyAnnualFinancePolicyAction::BondIssue) ); + assert_eq!( + state + .service_state + .annual_finance_last_news_family_candidates + .get(&24), + Some(&"2882_2886".to_string()) + ); assert_eq!(state.companies[0].current_cash, 100_000); assert_eq!(state.service_state.company_market_state[&24].bond_count, 1); assert_eq!( @@ -3356,6 +3434,13 @@ mod tests { state.service_state.annual_finance_last_actions.get(&25), Some(&crate::RuntimeCompanyAnnualFinancePolicyAction::BondIssue) ); + assert_eq!( + state + .service_state + .annual_finance_last_news_family_candidates + .get(&25), + Some(&"2882_2886".to_string()) + ); assert_eq!(state.companies[0].current_cash, 550_000); assert_eq!(state.companies[0].debt, 0); assert_eq!( @@ -3511,6 +3596,13 @@ mod tests { state.service_state.annual_finance_last_actions.get(&26), Some(&crate::RuntimeCompanyAnnualFinancePolicyAction::BondIssue) ); + assert_eq!( + state + .service_state + .annual_finance_last_news_family_candidates + .get(&26), + Some(&"2882_2886".to_string()) + ); assert_eq!(state.companies[0].current_cash, 250_000); assert_eq!(state.companies[0].debt, 1_000_000); assert_eq!( @@ -3691,6 +3783,13 @@ mod tests { state.service_state.annual_finance_last_actions.get(&31), Some(&crate::RuntimeCompanyAnnualFinancePolicyAction::CreditorPressureBankruptcy) ); + assert_eq!( + state + .service_state + .annual_finance_last_news_family_candidates + .get(&31), + Some(&"2881".to_string()) + ); assert_eq!(state.companies[0].current_cash, 0); assert_eq!(state.companies[0].debt, 250_000); assert!(state.companies[0].active); @@ -3859,6 +3958,13 @@ mod tests { state.service_state.annual_finance_last_actions.get(&32), Some(&crate::RuntimeCompanyAnnualFinancePolicyAction::DeepDistressBankruptcyFallback) ); + assert_eq!( + state + .service_state + .annual_finance_last_news_family_candidates + .get(&32), + Some(&"2881".to_string()) + ); assert_eq!(state.companies[0].current_cash, 0); assert_eq!(state.companies[0].debt, 125_000); assert!(state.companies[0].active); diff --git a/crates/rrt-runtime/src/summary.rs b/crates/rrt-runtime/src/summary.rs index a23635e..b30cc30 100644 --- a/crates/rrt-runtime/src/summary.rs +++ b/crates/rrt-runtime/src/summary.rs @@ -174,6 +174,7 @@ pub struct RuntimeSummary { pub selected_company_dividend_proposed_per_share_tenths: Option, pub selected_company_dividend_eligible_for_adjustment_branch: Option, pub selected_company_annual_finance_policy_action: Option, + pub selected_company_annual_finance_news_family_candidate: Option, pub selected_company_annual_finance_policy_creditor_pressure_bankruptcy_eligible: Option, pub selected_company_annual_finance_policy_deep_distress_bankruptcy_fallback_eligible: Option, @@ -808,6 +809,15 @@ impl RuntimeSummary { runtime_company_annual_finance_policy_action_label(policy_state.action) .to_string() }), + selected_company_annual_finance_news_family_candidate: state + .selected_company_id + .and_then(|company_id| { + state + .service_state + .annual_finance_last_news_family_candidates + .get(&company_id) + }) + .cloned(), selected_company_annual_finance_policy_creditor_pressure_bankruptcy_eligible: selected_company_annual_finance_policy_state .as_ref() @@ -3374,6 +3384,14 @@ mod tests { service_state: RuntimeServiceState { world_issue_opinion_base_terms_raw_i32: vec![0; 0x3b], chairman_personality_raw_u8: BTreeMap::from([(8, 20)]), + annual_finance_last_actions: BTreeMap::from([( + 14, + crate::RuntimeCompanyAnnualFinancePolicyAction::StockIssue, + )]), + annual_finance_last_news_family_candidates: BTreeMap::from([( + 14, + "4053".to_string(), + )]), company_market_state: BTreeMap::from([( 14, crate::RuntimeCompanyMarketState { @@ -3493,6 +3511,12 @@ mod tests { summary.selected_company_stock_issue_eligible_for_double_tranche, Some(true) ); + assert_eq!( + summary + .selected_company_annual_finance_news_family_candidate + .as_deref(), + Some("4053") + ); } #[test]