Problem Statement:
Write a program that converts a number to a string, the contents of
which depends on the number's prime factors.
- If the number contains 3 as a prime factor, output 'Pling'.
- If the number contains 5 as a prime factor, output 'Plang'.
- If the number contains 7 as a prime factor, output 'Plong'.
- If the number does not contain 3, 5, or 7 as a prime factor, just pass the number's digits straight through.
Code:
public class Raindrops {
private Raindrops() {}
public static String convert(int number) {
// Pre-condition.
if (number < 0) {
throw new IllegalArgumentException("Input cannot be negative.");
}
String result = "";
for (Raindrop drop : Raindrop.values()) {
if (drop.hasPrimeFactor(number)) {
result += drop.toString();
}
}
//if (result % 3 == 0)
//result += "Pling";
//if (number % 5 == 0)
//result += "Plang";
//if (number % 7 == 0)
//result += "Plong";
if (result.isEmpty()) {
result = "" + number;
}
checkPostCondition(result, number);
return result;
}
private static void checkPostCondition(String result, int number) {
assert(result.contains("Pling") ||
result.contains("Plang") ||
result.contains("Plong") ||
result.contains("" + number));
}
private enum Raindrop {
Pling(3),
Plang(5),
Plong(7);
private final int primeFactor;
private Raindrop(int primeFactor) {
this.primeFactor = primeFactor;
}
public boolean hasPrimeFactor(int number) {
return number % primeFactor == 0;
}
}
}
Test Suite:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
@RunWith(Parameterized.class)
public class RaindropsTest {
private int input;
private String expectedOutput;
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
// Non-primes
{1, "1"},
{52, "52"},
{12121, "12121"},
// Numbers with 3 as a prime factor
{3, "Pling"},
{6, "Pling"},
{9, "Pling"},
// Numbers with 5 as a prime factor
{5, "Plang"},
{10, "Plang"},
{25, "Plang"},
// Numbers with 7 as a prime factor
{7, "Plong"},
{14, "Plong"},
{49, "Plong"},
// Numbers with multiple activating prime factors
{15, "PlingPlang"},
{21, "PlingPlong"},
{35, "PlangPlong"},
{105, "PlingPlangPlong"},
});
}
public RaindropsTest(int input, String expectedOutput) {
this.input = input;
this.expectedOutput = expectedOutput;
}
@Test
public void test() {
assertEquals(expectedOutput, Raindrops.convert(input));
}
}
Notes:
Although the solution was quite simple(see my commented code) but I am trying to push myself and experiment with program correctness and flexibility hence the final solution may seem over engineered.
Reference:
http://exercism.io/exercises/java/raindrops/readme