MojoでProject Euler 86

https://projecteuler.net/problem=86

例だと、またぐ辺が5と3だから8で、6と直角になって斜辺が10となります。直方体の最も長い辺が直角三角形の一つの辺で残りの辺の和で直角を成します。
なので、直角三角形を最も長い辺になる長さが小さいほうから列挙するとよいです。その際、(3, 4, 5), (4, 3, 5)と同じ直角三角形でもどちらが直方体の最も長い辺になるかで分けると組みやすくなります。

import sys


#################### library ####################

fn gcd(n: Int, m: Int) -> Int:
    if m == 0:
        return n
    else:
        return gcd(m, n % m)


#################### HeapQueue ####################

struct HeapQueue[T: ComparableCollectionElement]:
    var a: List[T]
    
    fn __init__(inout self):
        self.a = List[T]()
    
    fn is_empty(self) -> Bool:
        return len(self.a) == 0
    
    fn pop(inout self) -> T:
        var top = self.a[0]
        self.a[0] = self.a.pop()
        var N = self.a.size
        var i = 0
        while i < N-1:
            var j1 = i*2+1
            var j2 = i*2+2
            var j: Int = 0
            if j1 >= N:
                break
            elif j2 == N:
                j = j1
            else:
                if self.a[j1] <= self.a[j2]:
                    j = j1
                else:
                    j = j2
            if self.a[j] < self.a[i]:
                self.swap(i, j)
                i = j
            else:
                break
        
        return top
    
    fn push(inout self, e: T):
        self.a.append(e)
        var i = self.a.size - 1
        while i > 0:
            var j = (i-1) // 2
            if self.a[j] <= self.a[i]:
                break
            else:
                self.swap(i, j)
                i = j
    
    fn swap(inout self, i: Int, j: Int):
        var tmp = self.a[i]
        self.a[i] = self.a[j]
        self.a[j] = tmp^


#################### RightTriangle ####################

@value
struct RightTriangle(Comparable):
    var l: Int
    var m: Int
    var n: Int
    var is_b: Bool      # 2lmnが対象か
    
    fn a(self) -> Int:
        return self.l * (self.m**2 - self.n**2)
    
    fn b(self) -> Int:
        return 2 * self.l * self.m * self.n
    
    fn value(self) -> Int:
        return self.b() if self.is_b else self.a()
    
    fn __lt__(self, other: RightTriangle) -> Bool:
        return self.value() < other.value()
    
    fn __le__(self, other: RightTriangle) -> Bool:
        return self.value() <= other.value()
    
    fn __eq__(self, other: RightTriangle) -> Bool:
        return self.value() == other.value()
    
    fn __ne__(self, other: RightTriangle) -> Bool:
        return self.value() != other.value()
    
    fn __gt__(self, other: RightTriangle) -> Bool:
        return self.value() > other.value()
    
    fn __ge__(self, other: RightTriangle) -> Bool:
        return self.value() >= other.value()


#################### process ####################

fn nexts(tri: RightTriangle) -> List[RightTriangle]:
    var tris = List[RightTriangle]()
    tris.append(RightTriangle(tri.l+1, tri.m, tri.n, tri.is_b))
    if tri.l > 1:
        pass
    elif tri.is_b:
        if tri.n <= 2:
            tris.append(RightTriangle(1, tri.m+2, tri.n, True))
        for n in range(tri.n+2, tri.m, 2):
            if gcd(tri.m, n) == 1:
                tris.append(RightTriangle(tri.l, tri.m, n, True))
                break
    else:
        if tri.n == tri.m - 1 and tri.m >= 3:
            tris.append(RightTriangle(1, tri.m+1, tri.n+1, False))
        for n in range(tri.n-2, 0, -2):
            if gcd(tri.m, n) == 1:
                tris.append(RightTriangle(tri.l, tri.m, n, False))
                break
    return tris

fn count_cuboids(tri: RightTriangle) -> Int:
    if tri.is_b:
        if tri.b() > tri.a():
            return tri.a() // 2
        else:
            return max(0, tri.a() // 2 - (tri.a() - tri.b() - 1))
    else:
        if tri.a() > tri.b():
            return tri.b() // 2
        else:
            return max(0, tri.b() // 2 - (tri.b() - tri.a() - 1))

fn f(N: Int) -> Int:
    var counter = 0
    var pq = HeapQueue[RightTriangle]()
    pq.push(RightTriangle(1, 2, 1, True))
    pq.push(RightTriangle(1, 2, 1, False))
    pq.push(RightTriangle(1, 3, 2, True))
    pq.push(RightTriangle(1, 3, 2, False))
    var M = 0
    while counter < N:
        var tri = pq.pop()
        var a = tri.a()
        var b = tri.b()
        counter += count_cuboids(tri)
        M = tri.value()
        
        var tris = nexts(tri)
        for tri1 in tris:
            pq.push(tri1[])
    return M

fn main() raises:
    var args = sys.argv()
    var N = atol(args[1])
    print(f(N))