dezoomify_rs/generic/
dichotomy_2d.rs1#[derive(Default, Debug)]
2pub struct Dichotomy {
3 min: u32,
4 max: Option<u32>,
5}
6
7impl Dichotomy {
8 fn best_guess(&self) -> u32 {
9 if let Some(max) = self.max {
10 (max + self.min) / 2
11 } else {
12 self.min * 3 + 1
13 }
14 }
15 fn next(&mut self, previous_success: bool) -> Option<u32> {
16 let last_guess = self.best_guess();
17 if previous_success {
18 self.min = last_guess;
19 } else {
20 self.max = Some(last_guess)
21 }
22 let next_guess = self.best_guess();
23 if next_guess != last_guess { Some(next_guess) } else { None }
24 }
25}
26
27#[derive(Debug)]
28pub enum Dichotomy2d {
29 Diagonal(Dichotomy),
30 Orientation { diagonal: u32 },
31 LastDim { diagonal: u32, is_landscape: bool, last_dim: Dichotomy },
32}
33
34impl Dichotomy2d {
35 pub fn next(&mut self, previous_success: bool) -> Option<(u32, u32)> {
36 let mut next = None;
37 let res = match self {
38 Dichotomy2d::Diagonal(d) => {
39 if let Some(n) = d.next(previous_success) {
40 Some((n, n))
41 } else {
42 let diagonal = d.best_guess();
43 next = Some(Dichotomy2d::Orientation { diagonal });
44 Some((diagonal + 1, diagonal))
45 }
46 },
47 Dichotomy2d::Orientation { diagonal } => {
48 let dichotomy = Dichotomy {
49 min: *diagonal + previous_success as u32,
50 max: None,
51 };
52 let best = dichotomy.best_guess();
53 next = Some(Dichotomy2d::LastDim {
54 diagonal: *diagonal,
55 is_landscape: previous_success,
56 last_dim: dichotomy,
57 });
58 if previous_success {
59 Some((best, *diagonal))
60 } else {
61 Some((*diagonal, best))
62 }
63 },
64 Dichotomy2d::LastDim { diagonal, is_landscape, last_dim } => {
65 last_dim.next(previous_success).map(|next| if *is_landscape {
66 (next, *diagonal)
67 } else {
68 (*diagonal, next)
69 })
70 }
71 };
72 if let Some(next) = next {
73 *self = next;
74 }
75 res
76 }
77}
78
79impl Default for Dichotomy2d {
80 fn default() -> Self {
81 Dichotomy2d::Diagonal(Default::default())
82 }
83}
84
85#[test]
86fn test_dichotomy1d() {
87 for mystery in 0..1000 {
88 let mut d: Dichotomy = Default::default();
89 let mut tries = 1;
90 while let Some(prop) = d.next(d.best_guess() <= mystery) {
91 tries += 1;
92 assert!(tries <= 20, "guessed {} on {}th try", prop, tries);
93 }
94 assert_eq!(d.best_guess(), mystery,
95 "Guessed {} instead of {} in {} tries", d.best_guess(), mystery, tries);
96 }
97}
98
99#[test]
100fn test_dichotomy2d() {
101 for x in 0..10 {
102 for y in 0..10 {
103 let mut d: Dichotomy2d = Default::default();
104 let mut tries = 1;
105 let mut guess = (1, 1);
106 while let Some(g) = d.next(guess.0 <= x && guess.1 <= y) {
107 guess = g;
108 tries += 1;
109 assert!(tries <= 20, "guessed {:?} on {}th try", g, tries);
110 }
111 assert_eq!(guess, (x, y),
112 "Guessed {:?} instead of {:?} in {} tries", guess, (x, y), tries);
113 }
114 }
115}