From 866ce5db5f7fccf4c0f4b22d7d3bbcc0229ec183 Mon Sep 17 00:00:00 2001 From: Hardik Pawar Date: Sun, 5 Oct 2025 15:49:10 +0530 Subject: [PATCH 1/2] refactor: Enhance docs, code, add tests in `PageRank` --- .../thealgorithms/others/HappyNumbersSeq.java | 87 ++++++++- .../others/HappyNumbersSeqTest.java | 179 ++++++++++++++++++ 2 files changed, 258 insertions(+), 8 deletions(-) create mode 100644 src/test/java/com/thealgorithms/others/HappyNumbersSeqTest.java diff --git a/src/main/java/com/thealgorithms/others/HappyNumbersSeq.java b/src/main/java/com/thealgorithms/others/HappyNumbersSeq.java index 0ae1e451bc6a..f39cc98a5b03 100644 --- a/src/main/java/com/thealgorithms/others/HappyNumbersSeq.java +++ b/src/main/java/com/thealgorithms/others/HappyNumbersSeq.java @@ -5,12 +5,52 @@ import java.util.Scanner; import java.util.Set; +/** + * A utility class for working with Happy Numbers. + * + *

+ * A Happy Number is defined by the following process: + * Starting with any positive integer, replace the number by the sum of the + * squares of its digits. + * Repeat the process until the number equals 1 (where it will stay), or it + * loops endlessly in a + * cycle which does not include 1. + * Those numbers for which this process ends in 1 are happy numbers, while those + * that do not end + * in 1 are unhappy (or sad) numbers. + * + *

+ * For example: + *

+ * + * @see Happy Number - + * Wikipedia + * @see Happy Number - + * Wolfram MathWorld + */ public final class HappyNumbersSeq { private HappyNumbersSeq() { } + /** + * Known cycle numbers that indicate a sad number. + * If the sequence reaches any of these numbers, it will cycle indefinitely + * without reaching 1. + */ private static final Set CYCLE_NUMS = new HashSet<>(Arrays.asList(4, 16, 20, 37, 58, 145)); + /** + * Main method to demonstrate happy number detection. + * Reads a number from user input and displays the sequence until it reaches 1 + * (happy) + * or enters a cycle (sad). + * + * @param args command-line arguments (not used) + */ public static void main(String[] args) { Scanner in = new Scanner(System.in); System.out.print("Enter number: "); @@ -24,16 +64,47 @@ public static void main(String[] args) { in.close(); } - private static int sumSquares(int n) { - int s = 0; - for (; n > 0; n /= 10) { - int r = n % 10; - s += r * r; + /** + * Determines if a number is a happy number. + * + * @param n the number to check (must be positive) + * @return {@code true} if the number is happy, {@code false} otherwise + * @throws IllegalArgumentException if n is not positive + */ + public static boolean isHappy(int n) { + if (n <= 0) { + throw new IllegalArgumentException("Number must be positive"); } - return s; + while (n != 1 && !isSad(n)) { + n = sumSquares(n); + } + return n == 1; + } + + /** + * Computes the sum of the squares of the digits of a number. + * + * @param n the number whose digits will be squared and summed + * @return the sum of the squares of the digits + */ + static int sumSquares(int n) { + int sum = 0; + while (n > 0) { + int digit = n % 10; + sum += digit * digit; + n /= 10; + } + return sum; } - private static boolean isSad(int n) { + /** + * Checks if a number is part of the known cycle that indicates a sad number. + * + * @param n the number to check + * @return {@code true} if the number is in the sad cycle, {@code false} + * otherwise + */ + static boolean isSad(int n) { return CYCLE_NUMS.contains(n); } -} +} \ No newline at end of file diff --git a/src/test/java/com/thealgorithms/others/HappyNumbersSeqTest.java b/src/test/java/com/thealgorithms/others/HappyNumbersSeqTest.java new file mode 100644 index 000000000000..ea45dd5bdfde --- /dev/null +++ b/src/test/java/com/thealgorithms/others/HappyNumbersSeqTest.java @@ -0,0 +1,179 @@ +package com.thealgorithms.others; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** + * Test class for {@link HappyNumbersSeq}. + * + * @author Hardvan (https://github.com/Hardvan) + */ +class HappyNumbersSeqTest { + + @Test + void testIsHappyWithHappyNumbers() { + // Test known happy numbers + assertTrue(HappyNumbersSeq.isHappy(1)); + assertTrue(HappyNumbersSeq.isHappy(7)); + assertTrue(HappyNumbersSeq.isHappy(10)); + assertTrue(HappyNumbersSeq.isHappy(13)); + assertTrue(HappyNumbersSeq.isHappy(19)); + assertTrue(HappyNumbersSeq.isHappy(23)); + assertTrue(HappyNumbersSeq.isHappy(28)); + assertTrue(HappyNumbersSeq.isHappy(31)); + assertTrue(HappyNumbersSeq.isHappy(32)); + assertTrue(HappyNumbersSeq.isHappy(44)); + assertTrue(HappyNumbersSeq.isHappy(49)); + assertTrue(HappyNumbersSeq.isHappy(68)); + assertTrue(HappyNumbersSeq.isHappy(70)); + assertTrue(HappyNumbersSeq.isHappy(79)); + assertTrue(HappyNumbersSeq.isHappy(82)); + assertTrue(HappyNumbersSeq.isHappy(86)); + assertTrue(HappyNumbersSeq.isHappy(91)); + assertTrue(HappyNumbersSeq.isHappy(94)); + assertTrue(HappyNumbersSeq.isHappy(97)); + assertTrue(HappyNumbersSeq.isHappy(100)); + } + + @Test + void testIsHappyWithSadNumbers() { + // Test known sad numbers + assertFalse(HappyNumbersSeq.isHappy(2)); + assertFalse(HappyNumbersSeq.isHappy(3)); + assertFalse(HappyNumbersSeq.isHappy(4)); + assertFalse(HappyNumbersSeq.isHappy(5)); + assertFalse(HappyNumbersSeq.isHappy(6)); + assertFalse(HappyNumbersSeq.isHappy(8)); + assertFalse(HappyNumbersSeq.isHappy(9)); + assertFalse(HappyNumbersSeq.isHappy(11)); + assertFalse(HappyNumbersSeq.isHappy(12)); + assertFalse(HappyNumbersSeq.isHappy(14)); + assertFalse(HappyNumbersSeq.isHappy(15)); + assertFalse(HappyNumbersSeq.isHappy(16)); + assertFalse(HappyNumbersSeq.isHappy(17)); + assertFalse(HappyNumbersSeq.isHappy(18)); + assertFalse(HappyNumbersSeq.isHappy(20)); + } + + @Test + void testIsHappyWithLargeNumbers() { + // Test larger happy numbers + assertTrue(HappyNumbersSeq.isHappy(1000)); + assertFalse(HappyNumbersSeq.isHappy(999)); + assertFalse(HappyNumbersSeq.isHappy(1001)); + } + + @Test + void testIsHappyWithInvalidInput() { + // Test with zero + assertThrows(IllegalArgumentException.class, () -> HappyNumbersSeq.isHappy(0)); + + // Test with negative numbers + assertThrows(IllegalArgumentException.class, () -> HappyNumbersSeq.isHappy(-1)); + assertThrows(IllegalArgumentException.class, () -> HappyNumbersSeq.isHappy(-10)); + assertThrows(IllegalArgumentException.class, () -> HappyNumbersSeq.isHappy(-100)); + } + + @Test + void testSumSquaresSingleDigit() { + assertEquals(0, HappyNumbersSeq.sumSquares(0)); + assertEquals(1, HappyNumbersSeq.sumSquares(1)); + assertEquals(4, HappyNumbersSeq.sumSquares(2)); + assertEquals(9, HappyNumbersSeq.sumSquares(3)); + assertEquals(16, HappyNumbersSeq.sumSquares(4)); + assertEquals(25, HappyNumbersSeq.sumSquares(5)); + assertEquals(36, HappyNumbersSeq.sumSquares(6)); + assertEquals(49, HappyNumbersSeq.sumSquares(7)); + assertEquals(64, HappyNumbersSeq.sumSquares(8)); + assertEquals(81, HappyNumbersSeq.sumSquares(9)); + } + + @Test + void testSumSquaresMultipleDigits() { + // 10: 1^2 + 0^2 = 1 + assertEquals(1, HappyNumbersSeq.sumSquares(10)); + + // 23: 2^2 + 3^2 = 4 + 9 = 13 + assertEquals(13, HappyNumbersSeq.sumSquares(23)); + + // 82: 8^2 + 2^2 = 64 + 4 = 68 + assertEquals(68, HappyNumbersSeq.sumSquares(82)); + + // 130: 1^2 + 3^2 + 0^2 = 1 + 9 + 0 = 10 + assertEquals(10, HappyNumbersSeq.sumSquares(130)); + + // 999: 9^2 + 9^2 + 9^2 = 81 + 81 + 81 = 243 + assertEquals(243, HappyNumbersSeq.sumSquares(999)); + } + + @Test + void testSumSquaresLargeNumbers() { + // 1234: 1^2 + 2^2 + 3^2 + 4^2 = 1 + 4 + 9 + 16 = 30 + assertEquals(30, HappyNumbersSeq.sumSquares(1234)); + + // 9876: 9^2 + 8^2 + 7^2 + 6^2 = 81 + 64 + 49 + 36 = 230 + assertEquals(230, HappyNumbersSeq.sumSquares(9876)); + } + + @Test + void testIsSadWithCycleNumbers() { + // Test all known cycle numbers + assertTrue(HappyNumbersSeq.isSad(4)); + assertTrue(HappyNumbersSeq.isSad(16)); + assertTrue(HappyNumbersSeq.isSad(20)); + assertTrue(HappyNumbersSeq.isSad(37)); + assertTrue(HappyNumbersSeq.isSad(58)); + assertTrue(HappyNumbersSeq.isSad(145)); + } + + @Test + void testIsSadWithNonCycleNumbers() { + // Test numbers that are not in the cycle + assertFalse(HappyNumbersSeq.isSad(1)); + assertFalse(HappyNumbersSeq.isSad(7)); + assertFalse(HappyNumbersSeq.isSad(10)); + assertFalse(HappyNumbersSeq.isSad(13)); + assertFalse(HappyNumbersSeq.isSad(19)); + assertFalse(HappyNumbersSeq.isSad(23)); + } + + @Test + void testHappyNumberSequenceFor7() { + // Test the sequence for happy number 7: 7 → 49 → 97 → 130 → 10 → 1 + int n = 7; + assertEquals(49, HappyNumbersSeq.sumSquares(n)); + n = 49; + assertEquals(97, HappyNumbersSeq.sumSquares(n)); + n = 97; + assertEquals(130, HappyNumbersSeq.sumSquares(n)); + n = 130; + assertEquals(10, HappyNumbersSeq.sumSquares(n)); + n = 10; + assertEquals(1, HappyNumbersSeq.sumSquares(n)); + } + + @Test + void testHappyNumberSequenceFor19() { + // Test the sequence for happy number 19: 19 → 82 → 68 → 100 → 1 + int n = 19; + assertEquals(82, HappyNumbersSeq.sumSquares(n)); + n = 82; + assertEquals(68, HappyNumbersSeq.sumSquares(n)); + n = 68; + assertEquals(100, HappyNumbersSeq.sumSquares(n)); + n = 100; + assertEquals(1, HappyNumbersSeq.sumSquares(n)); + } + + @Test + void testSadNumberEntersCycle() { + // Test that sad number 2 eventually reaches a cycle number + int n = 2; + assertEquals(4, HappyNumbersSeq.sumSquares(n)); // 2 → 4 (cycle number) + assertTrue(HappyNumbersSeq.isSad(4)); + } +} From dc104b2322e85d1c6b24e674cebe2a8a15fedb59 Mon Sep 17 00:00:00 2001 From: Hardik Pawar Date: Sun, 5 Oct 2025 15:57:36 +0530 Subject: [PATCH 2/2] Fix --- src/main/java/com/thealgorithms/others/HappyNumbersSeq.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/others/HappyNumbersSeq.java b/src/main/java/com/thealgorithms/others/HappyNumbersSeq.java index f39cc98a5b03..589b5941c370 100644 --- a/src/main/java/com/thealgorithms/others/HappyNumbersSeq.java +++ b/src/main/java/com/thealgorithms/others/HappyNumbersSeq.java @@ -107,4 +107,4 @@ static int sumSquares(int n) { static boolean isSad(int n) { return CYCLE_NUMS.contains(n); } -} \ No newline at end of file +}