diff --git a/justfile b/justfile index 82e65a6824..0a96a7e838 100644 --- a/justfile +++ b/justfile @@ -2,8 +2,12 @@ log := '0' export RUST_LOG := log -catalog: - cargo run catalog +all: clippy + cargo test --release + cargo test + +clippy: + cargo clippy watch +args='ltest --release': cargo watch --clear --exec '{{args}}' diff --git a/src/traits.rs b/src/traits.rs index 5af9709354..4c62c42839 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,10 +1,40 @@ use super::*; -pub(crate) fn run(n: u64) -> Result { - if n == 0 { - println!("zero"); +fn isqrt(x: u64) -> u64 { + let mut a = 1; + let mut b = ((x >> 5) + 8).min(65536); + loop { + let m = (a + b) >> 1; + if m * m > x { + b = m - 1; + } else { + a = m + 1; + } + + if b < a { + break; + } } + a - 1 +} +fn icbrt(mut x: u64) -> u64 { + let mut y = 0; + let mut s = 30; + while s >= 0 { + y *= 2; + let b = 3 * y * (y + 1) + 1; + let bs = b << s; + if x >= bs && b == (bs >> s) { + x -= b; + y += 1 + } + s -= 3; + } + y +} + +pub(crate) fn run(n: u64) -> Result { if n < subsidy(0) { println!("genesis"); } @@ -15,20 +45,42 @@ pub(crate) fn run(n: u64) -> Result { println!("odd"); } + if isqrt(n) * isqrt(n) == n { + println!("square"); + } + + if icbrt(n) * icbrt(n) * icbrt(n) == n { + println!("cube"); + } + + let digits = n.to_string().chars().collect::>(); + let pi = std::f64::consts::PI.to_string().replace('.', ""); let s = n.to_string(); if s == pi[..s.len()] { println!("pi"); } - if s.replace("69", "") == "" { + if digits.chunks(2).all(|chunk| chunk == ['6', '9']) { println!("nice"); } - if s.replace("7", "") == "" { + if digits.iter().all(|c| *c == '7') { println!("angelic"); } + println!( + "luck:{}/{}", + digits.iter().filter(|c| **c == '8').count(), + digits.len() + ); + + println!( + "population:{}", + (n.wrapping_mul(0x0002000400080010) & 0x1111111111111111).wrapping_mul(0x1111111111111111) + >> 60 + ); + println!("name:{}", name(n)); let mut block = 0; diff --git a/tests/traits.rs b/tests/traits.rs index 22fd5ce7f3..601ad81ac5 100644 --- a/tests/traits.rs +++ b/tests/traits.rs @@ -12,13 +12,6 @@ fn traits(n: u64) -> Result> { ) } -#[test] -fn zero() -> Result { - assert!(traits(0)?.contains("zero")); - assert!(!traits(1)?.contains("zero")); - Ok(()) -} - #[test] fn genesis() -> Result { assert!(traits(0)?.contains("genesis")); @@ -60,6 +53,7 @@ fn nice() -> Result { assert!(traits(6969)?.contains("nice")); assert!(traits(696969)?.contains("nice")); assert!(!traits(696968)?.contains("nice")); + assert!(!traits(6969698)?.contains("nice")); Ok(()) } @@ -92,6 +86,15 @@ fn block() -> Result { Ok(()) } +#[test] +fn lucky() -> Result { + assert!(traits(0)?.contains("luck:0/1")); + assert!(traits(8)?.contains("luck:1/1")); + assert!(traits(88)?.contains("luck:2/2")); + assert!(traits(89)?.contains("luck:1/2")); + Ok(()) +} + #[test] fn shiny() -> Result { assert!(traits(0)?.contains("shiny")); @@ -101,3 +104,35 @@ fn shiny() -> Result { assert!(!traits(50 * 100_000_000 + 1)?.contains("shiny")); Ok(()) } + +#[test] +fn population() -> Result { + assert!(traits(0)?.contains("population:0")); + assert!(traits(1)?.contains("population:1")); + assert!(traits(2)?.contains("population:1")); + assert!(traits(3)?.contains("population:2")); + assert!(traits(4)?.contains("population:1")); + Ok(()) +} + +#[test] +fn square() -> Result { + assert!(traits(0)?.contains("square")); + assert!(traits(1)?.contains("square")); + assert!(!traits(2)?.contains("square")); + assert!(traits(4)?.contains("square")); + assert!(!traits(5)?.contains("square")); + assert!(traits(9)?.contains("square")); + Ok(()) +} + +#[test] +fn cube() -> Result { + assert!(traits(0)?.contains("cube")); + assert!(traits(1)?.contains("cube")); + assert!(!traits(2)?.contains("cube")); + assert!(traits(8)?.contains("cube")); + assert!(!traits(9)?.contains("cube")); + assert!(traits(27)?.contains("cube")); + Ok(()) +}