hidden_number/
lib.rs

1//! Find a secret code from criteria
2
3#![deny(missing_docs, unsafe_code, unused_extern_crates, warnings)]
4
5use std::default::Default;
6use std::fmt;
7
8/// Criteria information
9#[derive(Debug)]
10pub enum Data {
11    /// None of numbers is in the final code
12    None,
13    /// Multiple number is in the code
14    Good(Position, u8)
15}
16
17/// Criteria numbers, where are they ?
18#[derive(Debug)]
19pub enum Position {
20    /// It's at the right place !
21    Good,
22    /// Not in the right digit
23    Bad
24}
25
26/// Every Values available
27#[derive(Debug)]
28pub struct Values(Vec<Value>);
29
30/// A possible code
31#[derive(Debug, Copy, Clone, PartialEq)]
32pub struct Value(u8, u8, u8);
33
34impl Default for Values {
35    fn default () -> Self {
36        let mut values: Vec<Value> = Vec::with_capacity(10 * 10 * 10);
37
38        for x in 0..10 {
39            for y in 0..10 {
40                for z in 0..10 {
41                    values.push(Value(x, y, z))
42                }
43            }
44        }
45
46        Values(values)
47    }
48}
49
50impl Value {
51    /// Find if your code contain a number
52    pub fn has_some (&self, number: u8) -> bool {
53        self.0 == number || self.1 == number || self.2 == number
54    }
55
56    /// Find if your code contain a number at same position or in other
57    pub fn occurences(&self, position: &Position, numbers: Value) -> u8 {
58        let &Value(a, b, c) = self;
59        let Value(x, y, z) = numbers;
60
61        match position {
62            &Position::Good => {
63                vec![a == x, b == y, c == z].iter().filter(|&b| *b).count() as u8
64            },
65            &Position::Bad => {
66                vec![a == y || a == z, b == x || b == z || c == x || c == y].iter()
67                    .filter(|&b| *b).count() as u8
68            }
69        }
70    }
71}
72
73impl Values {
74    /// Apply criteria to your values
75    pub fn apply (self, numbers: Value, data: Data) -> Self {
76        let Value(x, y, z) = numbers;
77        let Values(values) = self;
78
79        match data {
80            Data::None => {
81                let values: Vec<Value> = values.into_iter()
82                    .filter(|&value| !(value.has_some(x) || value.has_some(y) || value.has_some(z)))
83                    .collect();
84
85                Values(values)
86            },
87            Data::Good(position, number) => {
88                let values = values.into_iter()
89                    .filter(|&value| value.occurences(&position, numbers) == number)
90                    .collect();
91
92                Values(values)
93            }
94        }
95    }
96}
97
98impl fmt::Display for Value {
99    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
100        write!(f, "{}{}{}", self.0, self.1, self.2)
101    }
102}
103
104impl fmt::Display for Values {
105    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106        write!(f, "The following values correspond to your criteria: {}",
107               self.0.iter()
108               .fold(String::new(), |acc, &value| format!("{}{} ", acc, value)))
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115
116    #[test]
117    fn it_works() {
118        let values = Values::default()
119            .apply(Value(9,4,2), Data::None)
120            .apply(Value(0,8,4), Data::Good(Position::Good, 1))
121            .apply(Value(4,7,9), Data::Good(Position::Bad, 1))
122            .apply(Value(8,3,7), Data::Good(Position::Bad, 2))
123            .apply(Value(2,6,0), Data::Good(Position::Bad, 1));
124
125        println!("{}", values);
126        assert!(values.0[0] == Value(7, 8, 6))
127    }
128}