--- /dev/null
+245284-286195,797927-983972,4949410945-4949555758,115-282,8266093206-8266228431,1-21,483873-655838,419252-466133,6190-13590,3876510-4037577,9946738680-9946889090,99954692-100029290,2398820-2469257,142130432-142157371,9797879567-9798085531,209853-240025,85618-110471,35694994-35766376,4395291-4476150,33658388-33694159,680915-772910,4973452995-4973630970,52-104,984439-1009605,19489345-19604283,22-42,154149-204168,7651663-7807184,287903-402052,2244-5558,587557762-587611332,307-1038,16266-85176,422394377-422468141
--- /dev/null
+use std::error::Error;
+
+pub fn run(input: &str) -> Result<(), Box<dyn Error>> {
+ println!("part 1: {}", part1(input)?);
+ Ok(())
+}
+
+fn is_invalid(n: &str) -> bool {
+ if n.len() % 2 == 1 {
+ return false;
+ }
+ (0..(n.len() / 2)).all(|i| {
+ n.as_bytes()[i] == n.as_bytes()[i + n.len()/2]
+ })
+}
+
+fn next_value(s: &str) -> String {
+ if s.len() % 2 == 1 {
+ // increase by 1 digit and search the next value
+ let n = 10u64.pow(s.len().try_into().unwrap()).to_string();
+ return next_value(&n);
+ }
+ let mut out = String::new();
+ if !is_invalid(s) {
+ // duplicate the first part of the string
+ // 47 → 55
+ // 2279 → 2323
+ // 565653 → 566 653
+ let (p1, p2) = s.split_at(s.len()/2);
+ let n = p1.parse::<u64>().unwrap();
+ if n < p2.parse::<u64>().unwrap() {
+ out.push_str(&(n + 1).to_string());
+ out.push_str(&(n + 1).to_string());
+ } else {
+ out.push_str(p1);
+ out.push_str(p1);
+ }
+ return out;
+ }
+ // create the next invalid string
+ let (s1, _) = s.split_at(s.len() / 2);
+ let n = s1.parse::<u64>().unwrap() + 1;
+ out.push_str(&n.to_string());
+ out.push_str(&n.to_string());
+ out
+}
+
+fn part1(input: &str) -> Result<u64, Box<dyn Error>> {
+ let mut res: u64 = 0;
+ input.trim_end_matches("\n").split(',')
+ .map(|ranges| ranges.split_once('-').unwrap())
+ // keep only the ranges with an even number of digits
+ // => filter out when a and b have the same odd number of digits
+ .filter(|(a, b)| !(a.len() == b.len() && a.len() % 2 == 1))
+ .for_each(|(a, b)| {
+ //println!("{} → {}", a, b);
+ let bn = b.parse::<u64>().unwrap();
+ let mut n = a.to_string();
+ let mut nn = n.parse::<u64>().unwrap();
+ while nn <= bn {
+ if is_invalid(&n) {
+ //println!(" invalid: {}", n);
+ res += nn;
+ }
+ n = next_value(&n);
+ nn = n.parse::<u64>().unwrap();
+ }
+ });
+ Ok(res)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ static INPUT: &str = "\
+11-22,95-115,998-1012,1188511880-1188511890,222220-222224,\
+1698522-1698528,446443-446449,38593856-38593862,565653-565659,\
+824824821-824824827,2121212118-2121212124";
+
+ #[test]
+ fn test_is_invalid() {
+ assert_eq!(is_invalid("1"), false);
+ assert_eq!(is_invalid("10"), false);
+ assert_eq!(is_invalid("11"), true);
+ assert_eq!(is_invalid("55"), true);
+ assert_eq!(is_invalid("101"), false);
+ assert_eq!(is_invalid("446446"), true);
+ assert_eq!(is_invalid("2121212121"), false);
+ }
+ #[test]
+ fn test_next_value() {
+ assert_eq!(next_value("1"), "11");
+ assert_eq!(next_value("10"), "11");
+ assert_eq!(next_value("11"), "22");
+ assert_eq!(next_value("47"), "55");
+ assert_eq!(next_value("55"), "66");
+ assert_eq!(next_value("101"), "1010");
+ assert_eq!(next_value("2279"), "2323");
+ assert_eq!(next_value("446446"), "447447");
+ assert_eq!(next_value("565653"), "566566");
+ assert_eq!(next_value("2121212121"), "2121221212");
+ }
+ #[test]
+ fn test_part1() {
+ assert_eq!(1227775554, part1(INPUT).unwrap());
+ }
+}