riichi_calc/
core.rs

1use crate::calculator;
2use crate::calculator::result::{Points, ScoreResult};
3use crate::constants::hand::WinningHand;
4use crate::core::CalcError::{HandValidationError, NoYakuError};
5use crate::finder::finder;
6use crate::finder::result::FoundResult;
7use crate::parser::{Input, ValidationError};
8use std::collections::HashMap;
9
10#[derive(Debug)]
11pub enum CalcError {
12    HandValidationError(ValidationError),
13    NoYakuError(String),
14}
15
16#[derive(Debug)]
17#[allow(dead_code)]
18pub struct Output {
19    winning_hand: WinningHand,
20    found_result: FoundResult,
21    score_result: ScoreResult,
22}
23
24type Outputs = Vec<Output>;
25
26impl Input {
27    /// calculate the score of the hand
28    ///
29    /// outputs [Output] if success
30    ///
31    /// outputs [CalcError] if fails
32    pub fn calc_hand(self) -> Result<Output, CalcError> {
33        let hands = self.parse_hand();
34        if hands.is_err() {
35            return Err(HandValidationError(hands.unwrap_err()));
36        }
37
38        let mut outputs: Outputs = vec![];
39        for hand in hands.unwrap() {
40            let found = finder::Finder::find_hand(&hand);
41            if !found.is_valid_hora() {
42                continue;
43            }
44            let score = calculator::score::calc_score(
45                &found,
46                &hand.field,
47                &hand.winning_hand,
48                &hand.status,
49            );
50            outputs.push(Output {
51                winning_hand: hand.winning_hand,
52                found_result: found,
53                score_result: score,
54            });
55        }
56
57        if outputs.len() == 0 {
58            return Err(NoYakuError("No yaku found".to_string()));
59        }
60
61        Ok(get_highest(outputs))
62    }
63}
64
65fn get_highest(results: Outputs) -> Output {
66    let mut result_sum: HashMap<u32, Output> = HashMap::new();
67
68    for result in results {
69        let sum = match result.score_result.points {
70            Points::ChildTumo(x, y) => x * 2 + y,
71            Points::DealerTumo(x) | Points::Ron(x) => x,
72        };
73
74        result_sum.insert(sum, result);
75    }
76
77    let highest = result_sum.into_iter().max_by(|x, y| x.0.cmp(&y.0)).unwrap();
78
79    highest.1
80}