Problem 139

completed January 18, 2021

Comments

I made a lot of wrong assumptions while working on this one. These all meant that I wasn’t actually producing all the Pythagorean triples as I should have been. I used the wikipedia article on Pythagorean triples as my guide, and had I just read it clearly the first time and followed their instructions, I wouldn’t have had any of these problems.

My errors were first that m and n cannot both be odd. They also cannot both be even because then their gcd would not be 1. Secondly, for some reason I assumed that a needed to be smaller than b, so I broke out of the n loop early. This was incorrect.

Code

def gcd(a, b):
    while b:
        a, b = b, a % b
    return a

def triples(perimeter):
    for m in range(1, int(perimeter**0.5) + 1):
        for n in range(m % 2 + 1, m, 2):
            if gcd(m, n) != 1:
                continue
            _a = m**2 - n**2
            _b = 2*m*n
            _c = m**2 + n**2
            if _a + _b + _c > perimeter:
                break
            for k in range(1, perimeter):
                a = k * _a
                b = k * _b
                c = k * _c
                if a + b + c >= perimeter:
                    break
                yield a, b, c

def solve(perimeter):
    count = 0
    for a, b, c in triples(perimeter):
        if c % (b - a) == 0:
            count += 1
    return count

if __name__ == '__main__':
    import sys
    n = eval(sys.argv[1])
    print(solve(n))

Tests

import pytest
from problem import solve

_test_solve = (
        (13, 1),
        (31, 2),
        (10**2, 9),
        (10**3, 99),
        (10**4, 1003),
)

@pytest.mark.parametrize('n,expect', _test_solve)
def test_solve(n, expect):
    assert expect == solve(n)