1 /** Pythogorean triple generators.
2  *
3  * See_Also: https://forum.dlang.org/post/q08qsm$22j3$1@digitalmars.com
4  */
5 module nxt.pythogorean_triples;
6 
7 /// Pythogorean triple generator rangeg.
8 struct PossiblePythagoreanTriples(T)
9 {
10     /// Pythogorean triple.
11     struct Triple
12     {
13         T x, y, z;
14         version(none)
15         @property void toString(scope void delegate(scope const(char)[]) @safe sink) const @safe
16         {
17             import std.conv : to;
18             sink(x.to!string);
19             sink(",");
20             sink(y.to!string);
21             sink(",");
22             sink(z.to!string);
23         }
24     }
25 
26     @property Triple front() const
27     {
28         return _front;
29     }
30 
31     void nextTriple()
32     {
33         if (++_front.y == _front.z)
34         {
35             if (++_front.x == _front.z)
36             {
37                 ++_front.z;     // if `_front.z` becomes 0 empty should be true
38                 _front.x = 1;
39             }
40             _front.y = _front.x;
41         }
42     }
43 
44     void popFront()
45     {
46         do
47         {
48             nextTriple();
49         } while (_front.x*_front.x + _front.y*_front.y != _front.z*_front.z);
50     }
51 
52     enum empty = false;
53 
54     private Triple _front = Triple(1, 1, 2);
55 }
56 
57 /// Get all Pythogorean triples in an infinite generator.
58 auto pythagoreanTriples(T = size_t)()
59 {
60     return PossiblePythagoreanTriples!T();
61 }
62 
63 ///
64 @safe pure nothrow @nogc unittest
65 {
66     auto t = pythagoreanTriples!size_t;
67     alias Triple = typeof(t.front);
68     assert(t.front == Triple(1,1,2)); t.popFront();
69     assert(t.front == Triple(3,4,5)); t.popFront();
70     assert(t.front == Triple(6,8,10)); t.popFront();
71     assert(t.front == Triple(5,12,13)); t.popFront();
72     assert(t.front == Triple(9,12,15)); t.popFront();
73     assert(t.front == Triple(8,15,17)); t.popFront();
74     assert(t.front == Triple(12,16,20)); t.popFront();
75 }