codebreaker_solver/
code.rs1use std::{fmt::Display, str::FromStr};
2
3use rand::{distributions::Standard, prelude::Distribution, Rng};
4use thiserror::Error;
5
6use crate::peg::{Peg, NUM_DIFFERENT_PEGS};
7
8pub const NUMBER_OF_PEGS_IN_CODE: usize = 4;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct Code(pub [Peg; NUMBER_OF_PEGS_IN_CODE]);
13
14impl Distribution<Code> for Standard {
15 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Code {
16 let inner = rng.gen();
17 Code(inner)
18 }
19}
20
21impl Display for Code {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 for i in 0..NUMBER_OF_PEGS_IN_CODE {
24 write!(f, "{}", self.0[i])?;
25 }
26 Ok(())
27 }
28}
29
30impl FromStr for Code {
31 type Err = CodeParsingError;
32
33 fn from_str(s: &str) -> Result<Self, Self::Err> {
34 let mut pegs = [Peg::new(0); NUMBER_OF_PEGS_IN_CODE];
35 let mut it_c = s.chars();
36 for peg in &mut pegs {
37 let Some(c) = it_c.next() else {
38 return Err(CodeParsingError::TooFewPegs);
39 };
40 *peg = Peg::from_char(c).ok_or(CodeParsingError::InvalidPeg(c))?;
41 }
42 if it_c.next().is_some() {
43 return Err(CodeParsingError::TooManyPegs);
44 }
45 Ok(Code(pegs))
46 }
47}
48
49pub fn all_possible_codes() -> impl Iterator<Item = Code> {
51 let num_possible_codes = (NUM_DIFFERENT_PEGS as u32).pow(NUMBER_OF_PEGS_IN_CODE as u32);
52 (0..num_possible_codes).map(|n| {
53 let mut code = [Peg::new(0); NUMBER_OF_PEGS_IN_CODE];
54 let mut n = n;
55 for peg in &mut code {
56 *peg = Peg::new((n % NUM_DIFFERENT_PEGS as u32) as u8);
57 n /= NUM_DIFFERENT_PEGS as u32;
58 }
59 Code(code)
60 })
61}
62
63#[derive(Error, Debug)]
64pub enum CodeParsingError {
65 #[error("Too many pegs in code")]
66 TooManyPegs,
67 #[error("Too few pegs in code")]
68 TooFewPegs,
69 #[error("Invalid peg '{0}'")]
70 InvalidPeg(char),
71}