Project Euler Problem 42

Coded triangle numbers

The n-th term of the sequence of triangle numbers is given by, tn = ½n(n+1); so the first ten triangle numbers are:

        1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...

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?

Link to original description
Source code examples on Github

At first butforce python solution:

Python version 1

1
2
3
4
5
6
7
8
9
#!/usr/bin/python

def worth(word): return sum(ord(letter) - ord('A') + 1 for letter in word)

words = open("/home/mkh/work/mblog/pr_euler/p42/p042_words.txt").read().replace('"', '').split(',')
triangle_numbers = dict.fromkeys(list(n*(n+1)/2 for n in xrange(1, 100)), 1)

print sum(1 for word in words if worth(word) in triangle_numbers)

lets try to find another way without searching in generated results of sequence.

                t = n(n-1)/2
                t = n^2/2 - n/2
                n^2 + n - 2t = 0  -- it is quadratic equation
and it have 2 roots: (-1 +/- sqrt(1+8t))/2, but n shoukd be positive, so

                n = (sqrt(1+8t)-1)/2

and we have new python version:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/python3

import math

words = open("/home/mkh/work/mblog/pr_euler/p42/p042_words.txt").read().replace('"', '').split(',')

def is_triangle(w):
    t = sum(ord(letter) - ord('A') + 1 for letter in w)
    n = (math.sqrt(1+8*t)-1) / 2
    return n.is_integer()

print(sum([1 for w in words if is_triangle(w)]))

and same with erlang:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable -sname p42
% vim:syn=erlang

is_trangle(X) ->
    T = lists:sum([C-96||C<-string:to_lower(binary_to_list(X))]),
    N = (math:sqrt(1+8*T)-1)/2, 
    case round(N) == N of
        true -> 1
        ;_   -> 0
    end.

main(_) -> 
    {ok, C} = file:read_file("/home/mkh/work/mblog/pr_euler/p42/p042_words.txt"),
    W = [binary:part(X,1,size(X)-2)||X<-binary:split(C,<<",">>,[global])],
    Answer = lists:sum([is_trangle(X)||X<-W]),
    io:format("Answer: ~p ~n", [Answer]).