diff --git a/src/bin/problem_26.rs b/src/bin/problem_26.rs index 293e39a..c9d4d97 100644 --- a/src/bin/problem_26.rs +++ b/src/bin/problem_26.rs @@ -1,19 +1,144 @@ -use utils::fraction::Fraction; +use std::collections::{HashMap, HashSet}; + +use utils::{ + fraction::Fraction, + number::{Number, Sign}, +}; fn main() { println!("Start"); let mut longest = (0, 0); - for denominator in 7..13 { - println!("1/{denominator}:"); + for denominator in 2..1000 { let f = Fraction { numerator: 1.into(), denominator: denominator.into(), }; - let rep = f.get_repeating(); - if longest.1 < rep.digits.len() { - longest = (denominator, rep.digits.len()); + if let Some(rep) = get_recurring(&f) { + if longest.1 < rep.digits.len() { + longest = (denominator, rep.digits.len()); + } } - println!("{rep}"); } println!("longest {}", longest.0); } + +pub fn get_recurring(fraction: &Fraction) -> Option { + let mut div_memory = HashMap::new(); + let mut rem_memory = HashSet::new(); + rem_memory.insert(1.into()); + let mut div_with = fraction.numerator.clone(); + let mut rational = Vec::new(); + if div_with < fraction.denominator { + div_with = div_with * 10; + } + loop { + while div_with < fraction.denominator { + rational.push(0); + div_memory + .entry(0) + .and_modify(|value| *value += 1) + .or_insert(1); + div_with = div_with * 10; + rem_memory.insert(div_with.clone()); + } + let (div, rem) = + Number::div_with_rem(div_with.clone(), fraction.denominator.clone()).unwrap(); + if rem == 0.into() { + return None; + } + let next_digit = div.digits[0]; + if div_memory.contains_key(&next_digit) && rem_memory.contains(&rem) && next_digit != 0 { + let mut digits = vec![]; + if div_memory.values().min() != div_memory.values().max() { + rational.push(div.digits[0]); + digits = rational; + let (l, r) = digits.split_at(digits.len() / 2); + if l == r { + digits = l.to_vec(); + } + } else { + let idx = rational + .iter() + .position(|digit| digit == &div.digits[0]) + .unwrap(); + if idx == rational.len() - 1 { + digits.push(div.digits[0]); + } else { + for digit in &rational[idx..] { + if digits.contains(digit) { + break; + } + digits.push(*digit); + } + } + } + return Some(Number { + digits, + sign: Sign::Positif, + }); + } + div_memory + .entry(next_digit) + .and_modify(|count| *count += 1) + .or_insert(1); + rem_memory.insert(rem.clone()); + rational.push(div.digits[0]); + div_with = rem * 10; + } +} + +#[cfg(test)] +mod test { + use utils::{fraction::Fraction, number::Number}; + + use crate::get_recurring; + + #[test] + fn test_1_div_2() { + let f = Fraction::new(1.into(), 2.into()).unwrap(); + let rep = get_recurring(&f); + assert_eq!(rep, None); + } + + #[test] + fn test_1_div_6() { + let f = Fraction::new(1.into(), 6.into()).unwrap(); + let rep = get_recurring(&f); + assert_eq!(rep, Some(Number::from("6"))); + } + + #[test] + fn test_1_div_7() { + let f = Fraction::new(1.into(), 7.into()).unwrap(); + let rep = get_recurring(&f); + assert_eq!(rep, Some(Number::from("142857"))); + } + + #[test] + fn test_1_div_11() { + let f = Fraction::new(1.into(), 11.into()).unwrap(); + let rep = get_recurring(&f); + assert_eq!(rep, Some(Number::from("09"))); + } + + #[test] + fn test_1_div_12() { + let f = Fraction::new(1.into(), 12.into()).unwrap(); + let rep = get_recurring(&f); + assert_eq!(rep, Some(Number::from("3"))); + } + + #[test] + fn test_1_div_14() { + let f = Fraction::new(1.into(), 14.into()).unwrap(); + let rep = get_recurring(&f); + assert_eq!(rep, Some(Number::from("714285"))); + } + + #[test] + fn test_1_div_101() { + let f = Fraction::new(1.into(), 101.into()).unwrap(); + let rep = get_recurring(&f); + assert_eq!(rep, Some(Number::from("0099"))); + } +}