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
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::CollatzType;

pub type Collatz64 = CollatzType<u64>;

impl From<u64> for Collatz64 {
    fn from(n: u64) -> Collatz64 {
        if n == 0 {panic!("Input must be a positive integer!")}
        Collatz64 { start: n }
    }
}

impl Iterator for Collatz64 {
    type Item = u64;
    fn next(&mut self) -> Option<Self::Item> {
        if self.start % 2 == 0 {
            self.start = self.start / 2;
            return Some(self.start);
        }
        if self.start == 1 {
            return None;
        }
        self.start = self.start * 3 + 1;
        Some(self.start)
    }
}

pub fn count_collatz(n: u32, lengths: &mut [u16; 500_000]) -> u16 {
    if n < 500_000 && lengths[n as usize] > 0 {
        lengths[n as usize]
    } else {
        if n == 1 {
            return 1;
        } else {
            let val = 1 +
                match n % 2 {
                    0 => count_collatz(n / 2, lengths),
                    _ => count_collatz(n * 3 + 1, lengths),
                };
            if n < 500_000 {
                lengths[n as usize] = val;
            }
            val
        }
    }
}

pub fn longest_collatz_memo(highest: u32) -> u32 {
    let mut max_length = 0;
    let mut lengths: [u16; 500_000] = [0; 500_000];
    let mut cause = 0;
    for i in 1..highest + 1 {
        let length = count_collatz(i, &mut lengths);
        if length > max_length {
            cause = i;
            max_length = length;
        }
    }
    cause
}

pub fn longest_collatz(highest: usize) -> usize {
    let mut max_length = 0;
    let mut cause = 0;
    for i in 1..highest + 1 {
        let mut length = 1;
        let mut n = i;
        loop {
            if n == 1 {
                break;
            }
            n = match n % 2 {
                0 => n / 2,
                _ => n * 3 + 1,
            };
            length += 1;
        }
        if length > max_length {
            max_length = length;
            cause = i;
        }
    }
    cause
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    #[should_panic]
    fn collatz_0() {
        let mut collatz = Collatz64::from(0u64);
        assert_eq!(collatz.next(), None);
    }

    #[test]
    fn collatz_13() {
        let mut collatz = Collatz64::from(13u64);
        assert_eq!(collatz.next(), Some(40));
        assert_eq!(collatz.next(), Some(20));
        assert_eq!(collatz.next(), Some(10));
        assert_eq!(collatz.next(), Some(5));
        assert_eq!(collatz.next(), Some(16));
        assert_eq!(collatz.next(), Some(8));
        assert_eq!(collatz.next(), Some(4));
        assert_eq!(collatz.next(), Some(2));
        assert_eq!(collatz.next(), Some(1));
        assert_eq!(collatz.next(), None);
    }

    #[test]
    fn test_longest_collatz() {
        assert_eq!(longest_collatz(1), 1);
        assert_eq!(longest_collatz(2), 2);
        assert_eq!(longest_collatz(3), 3)
    }

    #[test]
    fn test_longest_collatz_memo() {
        assert_eq!(longest_collatz_memo(1), 1);
    }
}