riichi_calc/
parser.rs

1use crate::constants::field::Field;
2use crate::constants::hand::{Mentsu, WinningHand};
3use crate::constants::status::Status;
4use crate::constants::tiles::Tile;
5use crate::parser::ValidationError::InvalidHand;
6
7mod field_input;
8mod pi_input;
9mod status_input;
10
11#[derive(Debug, PartialEq)]
12pub enum ValidationError {
13    InvalidHand(String),
14    InvalidTileNumber(String, u8),
15    InvalidWinCombination(String, String),
16    OutOfRange(String),
17}
18
19trait InputBase {
20    fn validate(&self) -> Result<(), ValidationError>;
21}
22
23#[derive(Debug)]
24pub struct ParsedHand {
25    pub field: Field,
26    pub winning_hand: WinningHand,
27    pub status: Status,
28}
29
30///
31/// # Fields
32///
33/// - `hand` - the hand including the hora tile (winning_tile)
34/// - `naki` - any mentsu created by naki
35/// - `hora` - the winning tile
36///
37#[derive(Clone)]
38pub struct PiInput {
39    pub hand: Vec<Tile>,
40    pub naki: Vec<Mentsu>,
41    pub hora: Tile,
42}
43
44///
45/// # Fields
46///
47/// - [pi_input](PiInput)
48/// - [field_input](Field)
49/// - [status_input](Status)
50///
51pub struct Input {
52    pub pi_input: PiInput,
53    pub field_input: Field,
54    pub status_input: Status,
55}
56
57impl Input {
58    pub fn new(pi_input: PiInput, field_input: Field, status_input: Status) -> Self {
59        Self {
60            pi_input,
61            field_input,
62            status_input,
63        }
64    }
65
66    pub fn parse_hand(self) -> Result<Vec<ParsedHand>, ValidationError> {
67        self.validate()?;
68
69        let hand_results = self.pi_input.to_mentsu();
70        if hand_results.is_none() {
71            return Err(InvalidHand("Not a valid winning hand".to_string()));
72        }
73        let (hands, red_tiles) = hand_results.unwrap();
74
75        let mut result = Vec::new();
76
77        for hand in hands {
78            result.push(ParsedHand {
79                field: self.field_input.clone(),
80                winning_hand: WinningHand {
81                    hand,
82                    winning_tile: self.pi_input.hora.clone(),
83                    red_tile: red_tiles,
84                },
85                status: self.status_input.clone(),
86            })
87        }
88
89        Ok(result)
90    }
91}
92
93impl InputBase for Input {
94    fn validate(&self) -> Result<(), ValidationError> {
95        self.pi_input.validate()?;
96        self.field_input.validate()?;
97        self.status_input.validate()?;
98
99        Ok(())
100    }
101}