Rehost company issue calendar packer

This commit is contained in:
Jan Petykiewicz 2026-04-17 22:20:54 -07:00
commit 9169d307a6
3 changed files with 162 additions and 0 deletions

View file

@ -142,6 +142,12 @@ pub struct ExpectedRuntimeSummary {
#[serde(default)]
pub selected_company_current_partial_year_weight_numerator: Option<i64>,
#[serde(default)]
pub selected_company_current_issue_absolute_counter: Option<u32>,
#[serde(default)]
pub selected_company_prior_issue_absolute_counter: Option<u32>,
#[serde(default)]
pub selected_company_current_issue_age_absolute_counter_delta: Option<i64>,
#[serde(default)]
pub selected_company_chairman_bonus_year: Option<u32>,
#[serde(default)]
pub selected_company_chairman_bonus_amount: Option<i32>,
@ -843,6 +849,30 @@ impl ExpectedRuntimeSummary {
));
}
}
if let Some(value) = self.selected_company_current_issue_absolute_counter {
if actual.selected_company_current_issue_absolute_counter != Some(value) {
mismatches.push(format!(
"selected_company_current_issue_absolute_counter mismatch: expected {value}, got {:?}",
actual.selected_company_current_issue_absolute_counter
));
}
}
if let Some(value) = self.selected_company_prior_issue_absolute_counter {
if actual.selected_company_prior_issue_absolute_counter != Some(value) {
mismatches.push(format!(
"selected_company_prior_issue_absolute_counter mismatch: expected {value}, got {:?}",
actual.selected_company_prior_issue_absolute_counter
));
}
}
if let Some(value) = self.selected_company_current_issue_age_absolute_counter_delta {
if actual.selected_company_current_issue_age_absolute_counter_delta != Some(value) {
mismatches.push(format!(
"selected_company_current_issue_age_absolute_counter_delta mismatch: expected {value}, got {:?}",
actual.selected_company_current_issue_age_absolute_counter_delta
));
}
}
if let Some(value) = self.selected_company_chairman_bonus_year {
if actual.selected_company_chairman_bonus_year != Some(value) {
mismatches.push(format!(

View file

@ -130,6 +130,12 @@ pub struct RuntimeCompanyAnnualFinanceState {
pub years_since_last_dividend: Option<u32>,
#[serde(default)]
pub current_partial_year_weight_numerator: Option<i64>,
#[serde(default)]
pub current_issue_absolute_counter: Option<u32>,
#[serde(default)]
pub prior_issue_absolute_counter: Option<u32>,
#[serde(default)]
pub current_issue_age_absolute_counter_delta: Option<i64>,
pub current_issue_calendar_word: u32,
#[serde(default)]
pub current_issue_calendar_word_2: u32,
@ -421,6 +427,17 @@ pub struct RuntimeWorldIssueState {
pub multiplier_value_f32_text: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimePackedCalendarTuple {
pub year_word: u16,
pub month_1_based: u8,
pub week_1_based: u8,
pub day_1_based: u8,
pub hour_0_based: u8,
pub quarter_day_1_based: u8,
pub minute_0_based: u8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeTerritoryMetric {
@ -1960,6 +1977,49 @@ pub fn runtime_world_partial_year_weight_numerator(state: &RuntimeState) -> Opti
Some(i64::from(state.world_restore.partial_year_progress_raw_u8?) * 5 - 5)
}
pub fn runtime_decode_packed_calendar_tuple(
word_0: u32,
word_1: u32,
) -> RuntimePackedCalendarTuple {
let bytes_0 = word_0.to_le_bytes();
let bytes_1 = word_1.to_le_bytes();
RuntimePackedCalendarTuple {
year_word: u16::from_le_bytes([bytes_0[0], bytes_0[1]]),
month_1_based: bytes_0[2],
week_1_based: bytes_0[3],
day_1_based: bytes_1[0],
hour_0_based: bytes_1[1],
quarter_day_1_based: bytes_1[2],
minute_0_based: bytes_1[3],
}
}
pub fn runtime_pack_packed_calendar_tuple_to_absolute_counter(
tuple: RuntimePackedCalendarTuple,
) -> Option<u32> {
if !(1..=12).contains(&tuple.month_1_based) {
return None;
}
if !(1..=28).contains(&tuple.day_1_based) {
return None;
}
if tuple.hour_0_based >= 24 {
return None;
}
if tuple.minute_0_based >= 60 {
return None;
}
let year = u64::from(tuple.year_word);
let month = u64::from(tuple.month_1_based);
let day = u64::from(tuple.day_1_based);
let hour = u64::from(tuple.hour_0_based);
let minute = u64::from(tuple.minute_0_based);
let absolute_counter =
((((year * 12 + month) * 28 + day).checked_sub(29)? * 24 + hour) * 60) + minute;
u32::try_from(absolute_counter).ok()
}
pub fn runtime_company_unassigned_share_pool(state: &RuntimeState, company_id: u32) -> Option<u32> {
let outstanding_shares = state
.service_state
@ -1996,6 +2056,25 @@ pub fn runtime_company_annual_finance_state(
);
let years_since_last_dividend =
derive_runtime_company_elapsed_years(state.calendar.year, market_state.last_dividend_year);
let current_issue_absolute_counter = runtime_pack_packed_calendar_tuple_to_absolute_counter(
runtime_decode_packed_calendar_tuple(
market_state.current_issue_calendar_word,
market_state.current_issue_calendar_word_2,
),
);
let prior_issue_absolute_counter = runtime_pack_packed_calendar_tuple_to_absolute_counter(
runtime_decode_packed_calendar_tuple(
market_state.prior_issue_calendar_word,
market_state.prior_issue_calendar_word_2,
),
);
let current_issue_age_absolute_counter_delta =
match (runtime_world_absolute_counter(state), current_issue_absolute_counter) {
(Some(world_counter), Some(issue_counter)) if world_counter >= issue_counter => {
Some(i64::from(world_counter - issue_counter))
}
_ => None,
};
Some(RuntimeCompanyAnnualFinanceState {
company_id,
outstanding_shares: market_state.outstanding_shares,
@ -2016,6 +2095,9 @@ pub fn runtime_company_annual_finance_state(
years_since_last_bankruptcy,
years_since_last_dividend,
current_partial_year_weight_numerator: runtime_world_partial_year_weight_numerator(state),
current_issue_absolute_counter,
prior_issue_absolute_counter,
current_issue_age_absolute_counter_delta,
current_issue_calendar_word: market_state.current_issue_calendar_word,
current_issue_calendar_word_2: market_state.current_issue_calendar_word_2,
prior_issue_calendar_word: market_state.prior_issue_calendar_word,
@ -4221,6 +4303,40 @@ mod tests {
assert_eq!(runtime_world_partial_year_weight_numerator(&state), Some(35));
}
#[test]
fn decodes_and_packs_company_issue_calendar_tuple() {
let tuple =
runtime_decode_packed_calendar_tuple(0x0101_0726, 0x0001_0001);
assert_eq!(
tuple,
RuntimePackedCalendarTuple {
year_word: 0x0726,
month_1_based: 1,
week_1_based: 1,
day_1_based: 1,
hour_0_based: 0,
quarter_day_1_based: 1,
minute_0_based: 0,
}
);
assert_eq!(
runtime_pack_packed_calendar_tuple_to_absolute_counter(tuple),
Some(885_427_200)
);
assert_eq!(
runtime_pack_packed_calendar_tuple_to_absolute_counter(RuntimePackedCalendarTuple {
year_word: 1830,
month_1_based: 13,
week_1_based: 1,
day_1_based: 1,
hour_0_based: 0,
quarter_day_1_based: 1,
minute_0_based: 0,
}),
None
);
}
#[test]
fn derives_company_unassigned_share_pool_from_market_state_and_holdings() {
let state = RuntimeState {
@ -4456,6 +4572,9 @@ mod tests {
years_since_last_bankruptcy: None,
years_since_last_dividend: None,
current_partial_year_weight_numerator: None,
current_issue_absolute_counter: None,
prior_issue_absolute_counter: None,
current_issue_age_absolute_counter_delta: None,
current_issue_calendar_word: 5,
current_issue_calendar_word_2: 6,
prior_issue_calendar_word: 4,

View file

@ -75,6 +75,9 @@ pub struct RuntimeSummary {
pub selected_company_years_since_last_bankruptcy: Option<u32>,
pub selected_company_years_since_last_dividend: Option<u32>,
pub selected_company_current_partial_year_weight_numerator: Option<i64>,
pub selected_company_current_issue_absolute_counter: Option<u32>,
pub selected_company_prior_issue_absolute_counter: Option<u32>,
pub selected_company_current_issue_age_absolute_counter_delta: Option<i64>,
pub selected_company_chairman_bonus_year: Option<u32>,
pub selected_company_chairman_bonus_amount: Option<i32>,
pub player_count: usize,
@ -337,6 +340,16 @@ impl RuntimeSummary {
selected_company_current_partial_year_weight_numerator: selected_company_annual_finance_state
.as_ref()
.and_then(|finance_state| finance_state.current_partial_year_weight_numerator),
selected_company_current_issue_absolute_counter: selected_company_annual_finance_state
.as_ref()
.and_then(|finance_state| finance_state.current_issue_absolute_counter),
selected_company_prior_issue_absolute_counter: selected_company_annual_finance_state
.as_ref()
.and_then(|finance_state| finance_state.prior_issue_absolute_counter),
selected_company_current_issue_age_absolute_counter_delta:
selected_company_annual_finance_state
.as_ref()
.and_then(|finance_state| finance_state.current_issue_age_absolute_counter_delta),
selected_company_chairman_bonus_year: selected_company_market_state
.map(|market_state| market_state.chairman_bonus_year)
.filter(|year| *year != 0),