nzscq 0.10.0

Core logic for NZSCQ.
Documentation
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Config {
    pub player_count: u8,
    pub points_to_win: u8,
    pub max_character_repetitions: u8,
    pub max_arsenal_items: u8,
}

impl Config {
    pub(super) fn deductions(&self, points: Vec<u8>) -> Vec<u8> {
        if let Some(max_points) = points.iter().max() {
            if *max_points < self.points_to_win {
                vec![0; points.len()]
            } else {
                let diff = max_points - self.points_to_win;
                #[allow(clippy::naive_bytecount)]
                let tie_exists = points.iter().filter(|p| p == &max_points).count() > 1;
                if tie_exists {
                    vec![diff + 1; points.len()]
                } else {
                    vec![diff; points.len()]
                }
            }
        } else {
            vec![]
        }
    }
}

impl Default for Config {
    fn default() -> Config {
        Config {
            player_count: 2,
            points_to_win: 5,
            max_character_repetitions: 3,
            max_arsenal_items: 2,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn config_default_works() {
        let _ = Config::default();
    }

    #[test]
    fn deducts_nothing_if_all_players_points_less_than_winning_amount() {
        const PLAYER_COUNT: u8 = 3;
        let config = Config {
            player_count: PLAYER_COUNT,
            ..Config::default()
        };
        let one_less = config.points_to_win - 1;

        assert_eq!(
            vec![0; PLAYER_COUNT as usize],
            config.deductions(vec![one_less; PLAYER_COUNT as usize])
        );
    }

    #[test]
    fn deducts_diff_if_one_player_has_points_greater_than_winning_amount() {
        const PLAYER_COUNT: u8 = 3;
        let config = Config {
            player_count: PLAYER_COUNT,
            ..Config::default()
        };
        let winning = config.points_to_win;
        let diff = 1;
        let diff_more = winning + diff;

        assert_eq!(
            vec![diff; PLAYER_COUNT as usize],
            config.deductions(vec![winning, winning, diff_more])
        );
    }

    #[test]
    fn deducts_zero_if_one_player_has_points_equal_to_winning_amount() {
        const PLAYER_COUNT: u8 = 3;
        let config = Config {
            player_count: PLAYER_COUNT,
            ..Config::default()
        };
        let winning = config.points_to_win;
        let diff = 0;
        let one_less = winning - 1;

        assert_eq!(
            vec![diff; PLAYER_COUNT as usize],
            config.deductions(vec![winning, one_less, one_less])
        );
    }

    #[test]
    fn deducts_diff_plus_one_if_multiple_players_have_more_points_than_winning_amount() {
        const PLAYER_COUNT: u8 = 3;
        let config = Config {
            player_count: PLAYER_COUNT,
            ..Config::default()
        };
        let winning = config.points_to_win;
        let diff = 1;
        let diff_more = winning + diff;

        assert_eq!(
            vec![diff + 1; PLAYER_COUNT as usize],
            config.deductions(vec![winning, diff_more, diff_more])
        );
    }

    #[test]
    fn deducts_one_if_multiple_players_are_tied_for_first_and_have_points_equal_to_winning_amount()
    {
        const PLAYER_COUNT: u8 = 3;
        let config = Config {
            player_count: PLAYER_COUNT,
            ..Config::default()
        };
        let winning = config.points_to_win;
        let diff = 0;
        let one_less = winning - 1;

        assert_eq!(
            vec![diff + 1; PLAYER_COUNT as usize],
            config.deductions(vec![winning, winning, one_less])
        );
    }
}