1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use std::fmt::Display;

pub trait SolverEvent {
    #[inline] fn take_option(&mut self) {}
    #[inline] fn break_option(&mut self) {}
    #[inline] fn rebuilding_rc(&mut self, _nimbers_len: usize) {}
}

impl SolverEvent for () {}

#[derive(Default, Clone, Copy)]
pub struct SolverIterations {
    pub taking: usize,
    pub breaking: usize,
    pub rebuilding_rc: usize,
    pub rebuilding_rc_nimbers_len: usize
}

impl SolverEvent for SolverIterations {
    #[inline] fn take_option(&mut self) { self.taking += 1; }
    #[inline] fn break_option(&mut self) { self.breaking += 1; }
    #[inline] fn rebuilding_rc(&mut self, nimbers_len: usize) {
         self.rebuilding_rc += 1;
         self.rebuilding_rc_nimbers_len += nimbers_len
    }
}

impl Display for SolverIterations {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if self.taking != 0 { write!(f, "taking: {}, ", self.taking)?; }
        if self.breaking != 0 { write!(f, "breaking: {}, ", self.breaking)?; }
        write!(f, "total: {}", self.taking+self.breaking)?;
        if self.rebuilding_rc != 0 { write!(f, ", RC effort/rebuilds: {}/{}", self.rebuilding_rc_nimbers_len, self.rebuilding_rc)?; }
        Ok(())
    }
}

pub struct NimberStats {
    pub occurences: [u32; 1<<16],
    pub max: u16
}

impl Default for NimberStats {
    fn default() -> Self { Self { occurences: [0; 1<<16], max: 0 } }
}

impl NimberStats {
    pub fn count(&mut self, nimber: u16) {
        self.occurences[nimber as usize] += 1;
        if nimber > self.max { self.max = nimber; }
    }

    /// Returns sorted vector of nimbers, from the most to the less commmon, skip chosen nimber
    pub fn nimbers_from_most_common(&self, to_skip: u16) -> Vec<u16> {
        let mut result = Vec::with_capacity(self.max as usize);
        if to_skip == 0 {
            for nimber in 1..=self.max {
                if self.occurences[nimber as usize] != 0 {
                    result.push(nimber);
                }
            }
        } else {
            for nimber in 0..=self.max {
                if nimber != to_skip && self.occurences[nimber as usize] != 0 {
                    result.push(nimber);
                }
            }
        }
        // we use stable sort to lower nimber be the first in the case of tie
        result.sort_by(|a, b| self.occurences[*b as usize].cmp(&self.occurences[*a as usize]));
        result
    }
}

impl Display for NimberStats {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if f.sign_plus() {  // pairs:
            for nimber in (0..=self.max).step_by(2) {
                let occ = (self.occurences[nimber as usize], self.occurences[nimber as usize + 1]);
                if occ.0 != 0 || occ.1 != 0 {
                    if nimber != 0 { write!(f, "\t")?; }
                    write!(f, "{:>2}:{}+{}", nimber>>1, occ.0, occ.1)?;
                }
            }
        } else {
            for nimber in 0..=self.max {
                let occ = self.occurences[nimber as usize];
                if occ != 0 {
                    if nimber != 0 { write!(f, "\t")?; }
                    write!(f, "{:>2}:{}", nimber, occ)?;
                }
            }
        }
        Ok(())
    }
}