mahjong_core/round/
decide_dealer.rs1use crate::{Wind, WINDS_ROUND_ORDER};
2use rustc_hash::FxHashSet;
3use serde::{Deserialize, Serialize};
4use strum_macros::EnumIter;
5
6#[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
17impl 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}