# Enigmatic Code

Programming Enigma Puzzles

## Enigma 364: Wrong-angled triangle

From New Scientist #1513, 19th June 1986 [link]

“We Yorkshireman,” said my friend Triptolemus, “like a puzzle as a cure for insomnia, instead of counting sheep. Have you got a nice simple question, without a mass of figures to remember?”

So I said, “If a wrong-angled triangle has whole-number sides and an area equal to its perimeter, how long are its sides?”

He slept on the the problem and gave me the answer next morning.

Can you?

(A wrong-angled triangle is of course the opposite of a right-angled triangle. Instead of two of its angles adding up to 90°, it has two angles differing by 90°).

There are now 1000 Enigma puzzles on the site, with a full archive of puzzles from Enigma 1 (February 1979) up to this puzzle, Enigma 364 (June 1986) and also all puzzles from Enigma 1148 (August 2001) up to the final puzzle Enigma 1780 (December 2013). Altogether that is about 56% of all the Enigma puzzles ever published.

I have been able to get hold of most of the remaining puzzles up to the end of 1989 and from 2000 onwards, so I’m missing sources for most of the puzzles originally published in from 1990 to 1999. Any help in sourcing these is appreciated.

[enigma364]

### 8 responses to “Enigma 364: Wrong-angled triangle”

1. Jim Randell 30 September 2016 at 8:52 am

This program considers increasing values for the perimeter and then decomposes that into possible integer values that can form a triangle. We then use Heron’s Formula to check that the area is the same as the perimeter. Then we can determine the sine and cosine of each internal angle of the triangle, and look for angles that differ by 90°.

This Python 3 program runs in 72ms.

from itertools import count
from fractions import Fraction as F
from enigma import irange, divf, multiply, printf

# decompose t into k numbers (min m)
def decompose(t, k, m=1, s=[]):
if k == 1:
if not(t < m):
yield s + [t]
else:
for x in irange(m, divf(t, k)):
yield from decompose(t - x, k - 1, x, s + [x])

# consider increasing values for the perimeter and area
for n in count(3):

# decompose the perimeter into three integer lengths
for (a, b, c) in decompose(n, 3):

# check this forms a triangle
ts = (a + b - c, a + c - b, b + c - a)
if not all(t > 0 for t in ts): continue

# check the area is the same as the perimeter
if multiply(ts) != 16 * n: continue

# we need two angles to differ by 90 degrees
# i.e. cos(a1 - a2) = 0
# sin(a1) * sin(a2) + cos(a1) * cos(a2) = 0

# sin can be determined from the area
sinx = F(2 * n, b * c)
siny = F(2 * n, a * c)
sinz = F(2 * n, a * b)

# cos can be determined from the cosine rule
cosx = F(b**2 + c**2 - a**2, 2 * b * c)
cosy = F(a**2 + c**2 - b**2, 2 * a * c)
cosz = F(a**2 + b**2 - c**2, 2 * a * b)

# and one of (x, y), (x, z), (y, z) must differ by 90 degrees
if all(x != 0 for x in (
sinx * siny + cosx * cosy,
sinx * sinz + cosx * cosz,
siny * sinz + cosy * cosz,
)): continue

printf("n={n}, a={a} b={b} c={c}")
exit()

Solution: The sides of the triangle are: 7, 15, 20.

The perimeter and area are both 42.

The internal angles of the triangle are (approximately): 16.26°, 36.87°, 126.87°, with the final two differing by 90°.

There are only 5 triangles with integer sides where the area and perimeter are equal:

n = 24, sides = (6, 8, 10), angles = (36.87°, 53.13°, 90°)
n = 30, sides = (5, 12, 13), angles = (22.62°, 67.38° 90°)
n = 36, sides = (9, 10, 17), angles = (25.06°, 28.07°, 126.87°)
n = 42, sides = (7, 15, 20), angles = (16.26°, 36.87°, 126.87°)
n = 60, sides = (6, 25, 29), angles = (9.53°, 43.60°, 126.87°)

So the solution is unique.

• Jim Randell 30 September 2016 at 9:21 am

We can save the program a bit of work (and the need to use Fractions) by just considering when the numerator of the expanded expression for cos(a1 − a2) is zero.

from itertools import count
from enigma import irange, divf, multiply, printf

# decompose t into k numbers (min m)
def decompose(t, k, m=1, s=[]):
if k == 1:
if not(t < m):
yield s + [t]
else:
for x in irange(m, divf(t, k)):
yield from decompose(t - x, k - 1, x, s + [x])

# consider increasing values for the perimeter and area
for n in count(3):

# decompose the perimeter into three integer lengths
for (a, b, c) in decompose(n, 3):

# check this forms a triangle
ts = (a + b - c, a + c - b, b + c - a)
if not all(t > 0 for t in ts): continue

# check the area is the same as the perimeter
if multiply(ts) != 16 * n: continue

# sin numerator (determined from area)
ns = 16 * n * n

# cos numerators (determined from the cosine rule)
ncx = b**2 + c**2 - a**2
ncy = a**2 + c**2 - b**2
ncz = a**2 + b**2 - c**2

# and one of (x, y), (x, z), (y, z) must differ by 90 degrees
if all(ns + nc != 0 for nc in (ncx * ncy, ncx * ncz, ncy * ncz)): continue

printf("n={n}, a={a} b={b} c={c}")
exit()

• Jim Randell 30 September 2016 at 3:35 pm

Here’s an analytical derivation of the 5 integer sided equable triangles:

If a, b, c are the sides of the triangle, then the perimeter and the area are the same when:

(a + b − c)(a + c − b)(b + c − a) = 16(a + b + c) … [1]

where the terms in parentheses on the left hand side correspond to the triangle inequality for the permutations of the sides.

Writing:

x = a + b − c
y = a + c − b
z = b + c − a

we note that x, y, z are all positive integers and that:

x + y + z = a + b + c

So we can re-write the equation [1] above as:

xyz = 16(x + y + z) … [2]

a, b, c can be recovered from x, y, z as follows:

a = (x + y) / 2
b = (x + z) / 2
c = (y + z) / 2

from which we deduce that x, y, z have the same parity, and as their product is even, then they are all even.

So we write:

x = 2p
y = 2q
z = 2r

The equation [2] then becomes:

pqr = 4(p + q + r)

For positive integers p, q, r.

We can suppose p ≤ q ≤ r, hence:

pqr = 4(p + q + r) ≤ 4(3r) = 12r
⇒ pq ≤ 12

and given p, q we can determine r from:

r = 4(p + q) / (pq − 4)

and as r is positive it follows that:

pq > 4

So we can consider possible values for (p, q) where 0 < p ≤ q and 4 < pq ≤ 12:

(1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (1, 11), (1, 12)
(2, 3), (2, 4), (2, 5), (2, 6)
(3, 3), (3, 4)

Computing the corresponding values for r, we reduce the possible values for (p, q, r) to:

(1, 5, 24), (1, 6, 14), (1, 8, 9)
(2, 3, 10), (2, 4, 6)

We then use these (p, q, r) values to determine (x, y, z) and finally (a, b, c):

(p, q, r) = (1, 5, 24) → (x, y, z) = (2, 10, 48) → (a, b, c) = (6, 25, 29)
(p, q, r) = (1, 6, 14) → (x, y, z) = (2, 12, 28) → (a, b, c) = (7, 15, 20)
(p, q, r) = (1, 8, 9) → (x, y, z) = (2, 16, 18) → (a, b, c) = (9, 10, 17)
(p, q, r) = (2, 3, 10) → (x, y, z) = (4, 6, 20) → (a, b, c) = (5, 12, 13)
(p, q, r) = (2, 4, 6) → (x, y, z) = (4, 8, 12) → (a, b, c) = (6, 8, 10)

And these are the sides of the 5 integer sided equable triangles previously mentioned.

2. geoffrounce 30 September 2016 at 10:02 am
from math import acos, pi

# Heron's formula
def area (a,b,c):
s = 1/2 * (a + b + c)
area = (s * (s-a) * (s-b) * (s-c)) ** 0.5
return area

# Cosine formula
def angles(a,b,c):
cosA = (b*b + c*c - a*a)/ (2*b*c)
A = acos(cosA) * 180/pi

cosB = (a*a + c*c - b*b)/ (2*a*c)
B = acos(cosB) * 180/pi

cosC = (b*b + a*a - c*c)/ (2*b*a)
C  = acos(cosC) * 180/pi

return A,B,C

# assume triangle sides of different lengths
for a in range(1, 50):
for b in range(a, 50):
for c in range(b, 50):

# sides a, b, c must form a valid triangle
if a + b > c and a + c > b and b + c > a:
ar = area(a, b ,c)
perim = a + b + c

# triangle area is same as perimeter in integer terms
if ar == perim:
ang1, ang2, ang3 = angles(b,c,a)

# 2 angles must differ by 90 degrees
if abs(ang1 - ang2) == 90  or abs(ang1 - ang3) == 90  \
or abs(ang2 - ang3) == 90 :
print('Triangle sides are : {}, {}, and {}'.format( a,b,c))

# Triangle sides are : 7, 15, and 20

If I change the last part of my code to : if abs(ang1 – ang2) – 90 < 0.0000001
then I get the five solutions you mention, but not sure why

3. Brian Gladman 30 September 2016 at 10:37 am
from itertools import count
from math import acos, pi

# let c be the longest side
for c in count(3):
# and a the shortest (or equal shortest)
for a in range(c):
# the third side b with a <= b < c
for b in range(a, c):

# find the perimeter and the area (squared) using Heron's formula
# and check that the area is equal to the perimeter
p = a + b + c
A2, r = divmod(p * (p - 2 * a) * (p - 2 * b) * (p - 2 * c), 16)
if not r and A2 == p * p:

# find the sign of the cosine of the angle opposite the longest
# side, which is negative for an angle is greater than 90 degrees
t = a * a + b * b - c * c
if t < 0:

# calculate the other angles (in radians) using the cosine rule
cc = acos(t / (2 * a * b))
aa = acos((b * b + c * c - a * a) / (2 * b * c))
bb = pi - aa - cc
# the largest angle must be 90 degrees larger than one of the others
if min(abs(cc - aa - pi / 2) , abs(cc - bb - pi / 2)) < 1e-14:
print('a = {}, b = {}, c = {}'.format(a, b, c))
exit()

4. Hugh Casement 30 September 2016 at 11:20 am

Congratulations on your 1000, Jim. Keep up the good work!
I intend to have another session in the library soon, when I should be able to fill in some, at least, from your “gap years”.

5. Tessa Fullwood 30 September 2016 at 4:09 pm

Congratulations also on your 1,000 also. I get much enjoyment from solving/ attempting them from time to time.

6. Julian Gray 1 October 2016 at 3:29 pm

Brilliant that you have done so much – my retirement is transformed by having access to 1000 Enigmas. I have done only a few hundred so far, so I hope to manage them for many more years and to begin to catch up with you eventually. Your programming is obviously very powerful but I can’t do that, I suspect like many others of your “customers” . However relying on pencil-and-paper obviously delivers solutions to most Enigmas and an occasional sortie into Excel helps with the rest. Just occasionally the foundations of the maths require a bit of research, but sometimes I feel quite chuffed that pencil-and-paper methods deliver results for the easy Enigmas in a fraction of the time that you must devote to your program.

This site uses Akismet to reduce spam. Learn how your comment data is processed.