1use crate::items::AttributeId;
2use crate::prelude::*;
3use std::collections::BTreeMap;
4
5#[derive(Copy, PartialEq, Eq, Hash, Debug, Clone, Serialize, Deserialize, Tsify, JsonSchema)]
8pub enum PlinkoDirection {
9 Left,
10 Right,
11}
12
13pub type PlinkoPath = Vec<PlinkoDirection>;
15
16#[derive(Copy, PartialEq, Eq, Hash, Debug, Clone, Serialize, Deserialize, Tsify, JsonSchema)]
19pub struct PlinkoPin {
20 pub row: i64,
21 pub column: i64,
22}
23
24pub fn pins_touched_by_path(path: &[PlinkoDirection]) -> Vec<PlinkoPin> {
29 let mut column = 0i64;
30 let mut pins = Vec::with_capacity(path.len());
31 for (row, step) in path.iter().enumerate() {
32 pins.push(PlinkoPin {
33 row: row as i64,
34 column,
35 });
36 if *step == PlinkoDirection::Right {
37 column += 1;
38 }
39 }
40 pins
41}
42
43pub fn slot_index_for_path(path: &[PlinkoDirection]) -> i64 {
45 path.iter()
46 .filter(|step| **step == PlinkoDirection::Right)
47 .count() as i64
48}
49
50#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Tsify)]
54pub struct PlinkoPinBonusesMap(pub BTreeMap<AttributeId, i64>);
55
56impl PlinkoPinBonusesMap {
57 pub fn get(&self, attribute_id: &AttributeId) -> i64 {
58 self.0.get(attribute_id).copied().unwrap_or(0)
59 }
60
61 pub fn set(&mut self, attribute_id: AttributeId, value: i64) {
62 self.0.insert(attribute_id, value);
63 }
64
65 pub fn is_empty(&self) -> bool {
66 self.0.is_empty()
67 }
68
69 pub fn iter(&self) -> impl Iterator<Item = (&AttributeId, &i64)> {
70 self.0.iter()
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn pins_are_one_per_row_and_follow_the_path() {
80 use PlinkoDirection::{Left as L, Right as R};
81 let path = vec![R, L, R, R, L, L, R];
82
83 let pins = pins_touched_by_path(&path);
84
85 assert_eq!(pins.len(), path.len(), "one pin per row");
86 assert_eq!(
87 pins,
88 vec![
89 PlinkoPin { row: 0, column: 0 },
90 PlinkoPin { row: 1, column: 1 },
91 PlinkoPin { row: 2, column: 1 },
92 PlinkoPin { row: 3, column: 2 },
93 PlinkoPin { row: 4, column: 3 },
94 PlinkoPin { row: 5, column: 3 },
95 PlinkoPin { row: 6, column: 3 },
96 ]
97 );
98 assert_eq!(slot_index_for_path(&path), 4);
99 for pin in &pins {
100 assert!(pin.column >= 0 && pin.column <= pin.row, "{pin:?}");
101 }
102 }
103
104 #[test]
105 fn same_path_always_yields_the_same_pins() {
106 use PlinkoDirection::{Left as L, Right as R};
107 let path = vec![L, L, R, L, R, R, L];
108
109 assert_eq!(pins_touched_by_path(&path), pins_touched_by_path(&path));
110 }
111}