mahjong_core/round/
decide_dealer.rs

1use crate::{Wind, WINDS_ROUND_ORDER};
2use rustc_hash::FxHashSet;
3use serde::{Deserialize, Serialize};
4use strum_macros::EnumIter;
5
6// https://stackoverflow.com/a/24257996
7#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
8pub struct DecideDealerWinds(Option<[Wind; 4]>);
9
10#[derive(Debug, EnumIter, Eq, PartialEq, Clone)]
11pub enum SetInitialWindsError {
12    Duplicate,
13}
14
15const FACTORIALS: [usize; 4] = [6, 2, 1, 1];
16
17// Uses lehmer codes to map from permutation to number
18impl DecideDealerWinds {
19    pub fn new(list: Option<[Wind; 4]>) -> Result<Self, SetInitialWindsError> {
20        if list.is_none() {
21            return Ok(Self(None));
22        }
23
24        let mut picked_winds: FxHashSet<Wind> = FxHashSet::default();
25        let winds_list = list.unwrap();
26        for wind in winds_list.iter() {
27            if picked_winds.contains(wind) {
28                return Err(SetInitialWindsError::Duplicate);
29            }
30            picked_winds.insert(wind.clone());
31        }
32
33        Ok(Self(Some(winds_list)))
34    }
35
36    pub fn from_number(n: Option<u8>) -> Self {
37        if n.is_none() {
38            return Self(None);
39        }
40
41        let mut lehmer_codes = Vec::new();
42        let mut n = n.unwrap();
43
44        for factorial in FACTORIALS {
45            let remainder = n % (factorial as u8);
46            let base_number = n - remainder;
47            let lehmer_code = (base_number / (factorial as u8)) as usize;
48            lehmer_codes.push(lehmer_code);
49            n = remainder;
50        }
51
52        let mut winds = WINDS_ROUND_ORDER.clone().to_vec();
53        let mut winds_list = Vec::new();
54        for lehmer_code in lehmer_codes {
55            let wind = winds.remove(lehmer_code);
56            winds_list.push(wind);
57        }
58
59        Self(Some(winds_list.try_into().unwrap()))
60    }
61
62    pub fn to_number(&self) -> Option<u8> {
63        self.0.as_ref()?;
64
65        let mut lehmer_codes = Vec::new();
66        let mut winds = self.0.as_ref().unwrap().to_vec();
67        let mut ordered_winds = WINDS_ROUND_ORDER.clone().to_vec();
68
69        for _ in 0..4 {
70            let wind = winds.remove(0);
71            let idx = ordered_winds.iter().position(|w| w == &wind).unwrap();
72            ordered_winds.remove(idx);
73            lehmer_codes.push(idx);
74        }
75
76        let mut n = 0;
77        for i in 0..4 {
78            n += lehmer_codes[i] * FACTORIALS[i];
79        }
80        Some(n as u8)
81    }
82
83    pub fn iter(&self, func: impl FnMut((usize, &Wind))) {
84        self.0.as_ref().unwrap().iter().enumerate().for_each(func);
85    }
86}