codebreaker_solver/
peg.rs1use std::fmt::{self, Display, Formatter};
2
3use rand::{distributions::Standard, prelude::Distribution, Rng};
4pub const NUM_DIFFERENT_PEGS: u8 = 6;
5
6pub const POSSIBLE_COLORS: [Peg; NUM_DIFFERENT_PEGS as usize] = possible_pegs();
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct Peg(u8);
13
14impl Peg {
15 pub const fn new(n: u8) -> Self {
17 assert!(n < NUM_DIFFERENT_PEGS);
18 Peg(n)
19 }
20
21 pub fn from_char(c: char) -> Option<Self> {
22 match c {
23 '1' => Some(Peg(0)),
24 '2' => Some(Peg(1)),
25 '3' => Some(Peg(2)),
26 '4' => Some(Peg(3)),
27 '5' => Some(Peg(4)),
28 '6' => Some(Peg(5)),
29 _ => None,
30 }
31 }
32
33 pub fn to_char(self) -> char {
34 match self {
35 Peg(0) => '1',
36 Peg(1) => '2',
37 Peg(2) => '3',
38 Peg(3) => '4',
39 Peg(4) => '5',
40 Peg(5) => '6',
41 _ => unreachable!(),
42 }
43 }
44}
45
46impl Display for Peg {
47 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
48 write!(f, "{}", self.to_char())
49 }
50}
51
52impl Distribution<Peg> for Standard {
53 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Peg {
54 let byte = loop {
56 let candidate: u8 = rng.gen();
57 if candidate <= u8::MAX - ((u8::MAX - NUM_DIFFERENT_PEGS + 1) % NUM_DIFFERENT_PEGS) {
58 break candidate;
59 }
60 };
61 Peg(byte % NUM_DIFFERENT_PEGS)
62 }
63}
64
65const fn possible_pegs() -> [Peg; NUM_DIFFERENT_PEGS as usize] {
66 let mut pegs = [Peg(0); NUM_DIFFERENT_PEGS as usize];
67 let mut index = 0;
68 loop {
69 if index == NUM_DIFFERENT_PEGS {
70 break;
71 }
72 pegs[index as usize] = Peg::new(index);
73 index += 1;
74 }
75 pegs
76}