Skip to main content

wowlab_sentinel/strategy/factorial/
types.rs

1//! Factorial-screening shared types.
2
3#[derive(Clone, Debug)]
4pub struct FactorialSlot {
5    pub slot_index: u32,
6    pub items: Vec<FactorialItem>,
7}
8
9#[derive(Clone, Copy, Debug)]
10pub struct FactorialItem {
11    has_effect: bool,
12}
13
14impl FactorialItem {
15    pub(crate) fn new(has_effect: bool) -> Self {
16        Self { has_effect }
17    }
18
19    pub(crate) fn has_effect(self) -> bool {
20        self.has_effect
21    }
22}
23
24#[derive(Clone, Copy, Debug)]
25pub(crate) struct MainEffectEstimate {
26    pub slot_index: u32,
27    pub item_idx: u32,
28    pub effect_dps_x10: i32,
29}
30
31#[derive(Clone, Copy, Debug)]
32pub(crate) struct InteractionEstimate {
33    pub slot_a: u32,
34    pub item_idx_a: u32,
35    pub slot_b: u32,
36    pub item_idx_b: u32,
37    pub interaction_dps_x10: i32,
38}
39
40#[derive(Clone, Debug)]
41pub(crate) struct ScreeningResult {
42    pub survivors: Vec<u64>,
43}
44
45#[derive(Clone, Copy, Debug, Eq, PartialEq)]
46#[non_exhaustive]
47pub(crate) enum WorkUnitKind {
48    Tournament,
49    MainEffect,
50    Interaction,
51}
52
53// Tag layout: top 2 bits = kind (00 tournament, 01 main, 10 interaction), low 62 bits = payload.
54const KIND_SHIFT: u32 = 62;
55const KIND_MASK: u64 = 0b11 << KIND_SHIFT;
56const MAIN_EFFECT_KIND: u64 = 0b01 << KIND_SHIFT;
57const INTERACTION_KIND: u64 = 0b10 << KIND_SHIFT;
58const PAYLOAD_MASK: u64 = !KIND_MASK;
59const MAIN_SLOT_SHIFT: u32 = 16;
60const MAIN_INDEX_MASK: u64 = 0xFFFF;
61const INTERACTION_FIELD_MASK: u64 = 0xFFF;
62const INTERACTION_SLOT_A_SHIFT: u32 = 36;
63const INTERACTION_ITEM_A_SHIFT: u32 = 24;
64const INTERACTION_SLOT_B_SHIFT: u32 = 12;
65
66pub(crate) const fn encode_main_effect_tag(slot_idx: u32, item_idx: u32) -> u64 {
67    MAIN_EFFECT_KIND | ((slot_idx as u64) << MAIN_SLOT_SHIFT) | (item_idx as u64 & MAIN_INDEX_MASK)
68}
69
70pub(crate) const fn encode_interaction_tag(
71    slot_a: u32,
72    item_a: u32,
73    slot_b: u32,
74    item_b: u32,
75) -> u64 {
76    INTERACTION_KIND
77        | ((slot_a as u64 & INTERACTION_FIELD_MASK) << INTERACTION_SLOT_A_SHIFT)
78        | ((item_a as u64 & INTERACTION_FIELD_MASK) << INTERACTION_ITEM_A_SHIFT)
79        | ((slot_b as u64 & INTERACTION_FIELD_MASK) << INTERACTION_SLOT_B_SHIFT)
80        | (item_b as u64 & INTERACTION_FIELD_MASK)
81}
82
83pub(crate) const fn tag_kind(tag: u64) -> WorkUnitKind {
84    match tag & KIND_MASK {
85        INTERACTION_KIND => WorkUnitKind::Interaction,
86        MAIN_EFFECT_KIND => WorkUnitKind::MainEffect,
87        _ => WorkUnitKind::Tournament,
88    }
89}
90
91pub(crate) const fn decode_main_effect_tag(tag: u64) -> (u32, u32) {
92    let payload = tag & PAYLOAD_MASK;
93    let slot_idx = ((payload >> MAIN_SLOT_SHIFT) & MAIN_INDEX_MASK) as u32;
94    let item_idx = (payload & MAIN_INDEX_MASK) as u32;
95
96    (slot_idx, item_idx)
97}
98
99pub(crate) const fn decode_interaction_tag(tag: u64) -> (u32, u32, u32, u32) {
100    let payload = tag & PAYLOAD_MASK;
101    let slot_a = ((payload >> INTERACTION_SLOT_A_SHIFT) & INTERACTION_FIELD_MASK) as u32;
102    let item_a = ((payload >> INTERACTION_ITEM_A_SHIFT) & INTERACTION_FIELD_MASK) as u32;
103    let slot_b = ((payload >> INTERACTION_SLOT_B_SHIFT) & INTERACTION_FIELD_MASK) as u32;
104    let item_b = (payload & INTERACTION_FIELD_MASK) as u32;
105
106    (slot_a, item_a, slot_b, item_b)
107}