Coded Triangle Numbers
The n -th triangle number is T_n = (n(n+1))/(2). By converting each letter in a word to its alphabetical position (A=1, B=2,..., Z=26) and summing, we obtain a word value. A word is a triangle word...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
The \(n^{th}\) term of the sequence of triangle numbers is given by, \(t_n = \frac 12n(n+1)\); so the first ten triangle numbers are: \[1, 3, 6, 10, 15, 21, 28, 36, 45, 55, \dots \] 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 = t_{10}\). If the word value is a triangle number then we shall call the word a triangle word.
Using
Problem 42: Coded Triangle Numbers
Mathematical Development
Definitions
Definition 1. The alphabetical value of a letter is .
Definition 2. The word value of a word is .
Definition 3. A positive integer is a triangular number if for some .
Theoretical Development
Theorem 1 (Triangular number characterization). A positive integer is triangular if and only if is a perfect square.
Proof. () Suppose for some . Then
which is a perfect square.
() Suppose for some . Since and even squares satisfy or , we conclude is odd. Write for some . Then
Since , we have , confirming is triangular.
Corollary 1 (Constant-time test). The triangular number test requires arithmetic operations: compute , take the integer square root , and verify .
Proof. Immediate from Theorem 1. The integer square root and one multiplication-comparison suffice.
Lemma 1 (Word value bounds). For a non-empty word of length , the word value satisfies .
Proof. Each letter contributes at least and at most . Summing over letters gives .
Remark. For the Project Euler word list, the maximum word length is (e.g., “SIMULTANEOUSLY”), giving . The largest triangle number not exceeding is , so we need only consider triangle numbers .
Editorial
We read the word list, compute the value of each word by summing the alphabetical positions of its letters, and test the resulting integer with the triangular-number criterion from Theorem 1. Every word whose value satisfies that criterion contributes one to the running count, and the final count is the number of triangle words in the file.
Pseudocode
Algorithm: Counting Triangle Words
Require: A finite word list over the alphabet {A, B, ..., Z}.
Ensure: The number of words whose alphabetical values are triangular numbers.
1: Read the word list and initialize count ← 0.
2: For each word w in the list, compute its word value v ← sum of the letter positions in w.
3: Test whether 8v + 1 is a perfect square.
4: If the test succeeds, increment count.
5: Return count.
Complexity Analysis
Proposition (Time complexity). The algorithm runs in time, where is the number of words and is the average word length.
Proof. For each of the words, computing the word value requires summing letter values, where is the length of the -th word. The triangular number test is by Corollary 1. Total time:
Proposition (Space complexity). The algorithm uses space for storing the word list, plus auxiliary space.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
bool is_triangular(int v) {
// v is triangular iff 8v+1 is a perfect square (Theorem 1).
if (v <= 0) return v == 0;
long long disc = 1 + 8LL * v;
long long s = (long long)sqrt((double)disc);
while (s * s < disc) s++;
while (s * s > disc) s--;
return s * s == disc;
}
int word_value(const string& w) {
int val = 0;
for (char c : w) {
if (c >= 'A' && c <= 'Z') val += c - 'A' + 1;
}
return val;
}
int main() {
vector<string> candidates = {
"words.txt",
"0042_words.txt",
"project_euler/problem_042/words.txt",
"project_euler/problem_042/0042_words.txt"
};
ifstream fin;
for (const auto& path : candidates) {
fin.open(path);
if (fin.is_open()) {
break;
}
fin.clear();
}
if (!fin.is_open()) {
cerr << "Could not locate the Problem 42 word list." << endl;
return 1;
}
string line;
getline(fin, line);
fin.close();
int count = 0;
stringstream ss(line);
string token;
while (getline(ss, token, ',')) {
string word;
for (char c : token) {
if (c != '"') word += c;
}
if (is_triangular(word_value(word))) {
count++;
}
}
cout << count << endl;
return 0;
}
import math
from pathlib import Path
def is_triangular(v):
"""Check if v is a triangular number using the discriminant criterion:
v = n(n+1)/2 iff 8v+1 is a perfect square.
"""
if v <= 0:
return v == 0
disc = 1 + 8 * v
s = math.isqrt(disc)
return s * s == disc
def word_value(word):
"""Compute the alphabetical value of a word: A=1, B=2, ..., Z=26."""
return sum(ord(c) - ord('A') + 1 for c in word.upper())
def load_words():
script_dir = Path(__file__).resolve().parent
candidates = [
script_dir / "words.txt",
script_dir / "0042_words.txt",
Path("words.txt"),
Path("0042_words.txt"),
Path("project_euler/problem_042/words.txt"),
Path("project_euler/problem_042/0042_words.txt"),
]
for path in candidates:
if path.exists():
return path.read_text().strip()
raise FileNotFoundError("Could not locate the Problem 42 word list.")
def solve():
content = load_words()
words = [w.strip('"') for w in content.split(',')]
return sum(1 for w in words if is_triangular(word_value(w)))
answer = solve()
assert answer == 162
print(answer)