I've never did a real Project Euler in my life, so I figured it was about to do one.
And what better Project Euler to start with than Problem 42?
Project description from Project Euler:
By converting each letter in a word to a number corresponding to its alphabetical position and adding these values we form a word value. For example, the word value for SKY is 19 + 11 + 25 = 55 = t10. If the word value is a triangle number then we shall call the word a triangle word.
Using words.txt, a 16K text file containing nearly two-thousand common English words, how many are triangle words?
I realized quite quickly that to determine if a number is triangular, you can solve a quadratic equation.
The part that I'm the least proud of is how the words are read from the URL. Reading the whole line into memory (the whole text file is essentially one whole line) feels unnecessary, just to then split it into words, cut off the quotation marks, and read it.
Even though I could keep the quotation marks and add a filter in wordValue
, it feels like it makes more sense to change the string before passing it there.
I considered using StreamTokenizer to read the words, but that class felt old and ugly and not Java 8-ish at all.
The project euler assignment only asks to print the count of triangular numbers, I figured that it doesn't hurt to also write them and their word values - this can be easily disabled by removing the .peek(System.out::println)
lines.
public class ProjEuler42 {
public static int wordValue(String str) {
return str.toUpperCase().chars().map(ch -> ch - 'A' + 1).sum();
}
public static boolean isTriangular(int number) {
// The Nth triangular number, T(n), is n*(n+1)/2,
// by doing T(n) - number = 0 we get a quadratic equation.
// If the solution to this equation is an integer, it is a triangular number
double n = Math.round(-0.5 + Math.sqrt(0.25 + 2 * number));
return 0.5 * n * (n + 1) == number;
}
public static void main(String[] args) throws IOException {
URL url = new URL("https://projecteuler.net/project/resources/p042_words.txt");
InputStream in = url.openStream();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(in, StandardCharsets.UTF_8))) {
long count = reader.lines()
.flatMap(line -> Arrays.stream(line.split(",")))
.map(str -> str.substring(1, str.length() - 1))
.filter(str -> isTriangular(wordValue(str)))
.peek(System.out::println)
.mapToInt(ProjEuler42::wordValue)
.peek(System.out::println)
.count();
System.out.println("There are a total of " + count + " triangular words");
}
}
}
From a Project Euler perspective, and from a Java 8 perspective, is there anything to improve?