use crate::{Category, Dice};
fn has_run(dice: Dice, run: u8) -> bool {
let mut streak = 0;
(1..=6).any(|face| {
streak = if dice.count(face) > 0 { streak + 1 } else { 0 };
streak >= run
})
}
impl Category {
#[must_use]
pub fn score(self, dice: Dice) -> u8 {
let of_a_kind = |n| (1..=6).any(|face| dice.count(face) >= n);
match self {
Self::Aces | Self::Twos | Self::Threes | Self::Fours | Self::Fives | Self::Sixes => {
let face = self.upper_face().expect("an upper category");
dice.count(face) * face
}
Self::ThreeOfAKind => {
if of_a_kind(3) {
dice.sum()
} else {
0
}
}
Self::FourOfAKind => {
if of_a_kind(4) {
dice.sum()
} else {
0
}
}
Self::FullHouse => {
let counts = dice.counts();
if counts.contains(&3) && counts.contains(&2) {
25
} else {
0
}
}
Self::SmallStraight => {
if has_run(dice, 4) {
30
} else {
0
}
}
Self::LargeStraight => {
if has_run(dice, 5) {
40
} else {
0
}
}
Self::Yahtzee => {
if dice.yahtzee_face().is_some() {
50
} else {
0
}
}
Self::Chance => dice.sum(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn dice(s: &str) -> Dice {
s.parse().expect("a valid roll")
}
fn scores(s: &str) -> [u8; 13] {
Category::ALL.map(|c| c.score(dice(s)))
}
#[test]
fn upper_section_counts_one_face() {
assert_eq!(scores("13446")[..6], [1, 0, 3, 8, 0, 6]);
assert_eq!(scores("55555")[..6], [0, 0, 0, 0, 25, 0]);
}
#[test]
fn n_of_a_kind_pays_the_whole_roll() {
assert_eq!(Category::ThreeOfAKind.score(dice("33345")), 18);
assert_eq!(Category::ThreeOfAKind.score(dice("33445")), 0);
assert_eq!(Category::FourOfAKind.score(dice("33334")), 16);
assert_eq!(Category::FourOfAKind.score(dice("33345")), 0);
assert_eq!(Category::ThreeOfAKind.score(dice("66666")), 30);
assert_eq!(Category::FourOfAKind.score(dice("66666")), 30);
}
#[test]
fn full_house_is_exactly_three_and_two() {
assert_eq!(Category::FullHouse.score(dice("22333")), 25);
assert_eq!(Category::FullHouse.score(dice("22334")), 0);
assert_eq!(Category::FullHouse.score(dice("22223")), 0);
assert_eq!(Category::FullHouse.score(dice("33333")), 0);
}
#[test]
fn straights() {
assert_eq!(Category::SmallStraight.score(dice("12346")), 30);
assert_eq!(Category::SmallStraight.score(dice("23345")), 30);
assert_eq!(Category::SmallStraight.score(dice("12356")), 0);
assert_eq!(Category::LargeStraight.score(dice("12345")), 40);
assert_eq!(Category::LargeStraight.score(dice("23456")), 40);
assert_eq!(Category::LargeStraight.score(dice("12346")), 0);
assert_eq!(Category::SmallStraight.score(dice("23456")), 30);
}
#[test]
fn yahtzee_and_chance() {
assert_eq!(Category::Yahtzee.score(dice("44444")), 50);
assert_eq!(Category::Yahtzee.score(dice("44443")), 0);
assert_eq!(Category::Chance.score(dice("13446")), 18);
assert_eq!(Category::Chance.score(dice("66666")), 30);
}
}