#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub enum Shutout {
Double,
Flat(u16),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub struct Rules {
pub knock_limit: u8,
pub gin_bonus: u16,
pub big_gin_bonus: Option<u16>,
pub undercut_bonus: u16,
pub undercut_on_tie: bool,
pub box_bonus: u16,
pub immediate_boxes: bool,
pub game_bonus: u16,
pub game_target: u16,
pub shutout: Shutout,
}
impl Rules {
#[must_use]
#[inline]
pub const fn new() -> Self {
Self {
knock_limit: 10,
gin_bonus: 25,
big_gin_bonus: Some(31),
undercut_bonus: 25,
undercut_on_tie: true,
box_bonus: 25,
immediate_boxes: false,
game_bonus: 100,
game_target: 100,
shutout: Shutout::Double,
}
}
#[must_use]
#[inline]
pub const fn classic() -> Self {
Self {
gin_bonus: 20,
big_gin_bonus: None,
undercut_bonus: 10,
box_bonus: 20,
shutout: Shutout::Flat(100),
..Self::new()
}
}
#[must_use]
#[inline]
pub const fn palace() -> Self {
Self {
big_gin_bonus: None,
undercut_bonus: 20,
box_bonus: 10,
immediate_boxes: true,
game_bonus: 0,
shutout: Shutout::Flat(0),
..Self::new()
}
}
}
impl Default for Rules {
#[inline]
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn presets() {
let modern = Rules::default();
assert_eq!(modern, Rules::new());
assert_eq!(modern.knock_limit, 10);
assert_eq!(modern.gin_bonus, 25);
assert_eq!(modern.big_gin_bonus, Some(31));
assert_eq!(modern.undercut_bonus, 25);
assert_eq!(modern.box_bonus, 25);
assert!(!modern.immediate_boxes);
assert_eq!(modern.game_bonus, 100);
assert_eq!(modern.game_target, 100);
assert_eq!(modern.shutout, Shutout::Double);
let classic = Rules::classic();
assert_eq!(classic.gin_bonus, 20);
assert_eq!(classic.big_gin_bonus, None);
assert_eq!(classic.undercut_bonus, 10);
assert_eq!(classic.box_bonus, 20);
assert!(!classic.immediate_boxes);
assert_eq!(classic.shutout, Shutout::Flat(100));
let palace = Rules::palace();
assert_eq!(palace.gin_bonus, 25);
assert_eq!(palace.big_gin_bonus, None);
assert_eq!(palace.undercut_bonus, 20);
assert_eq!(palace.box_bonus, 10);
assert!(palace.immediate_boxes);
assert_eq!(palace.game_bonus, 0);
assert_eq!(palace.shutout, Shutout::Flat(0));
for rules in [modern, classic, palace] {
assert_eq!(rules.knock_limit, 10);
assert!(rules.undercut_on_tie);
assert_eq!(rules.game_target, 100);
}
}
}