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         void toString(Sink)(ref scope Sink 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 => _front;
27 
28     void nextTriple()
29     {
30         if (++_front.y == _front.z)
31         {
32             if (++_front.x == _front.z)
33             {
34                 ++_front.z;     // if `_front.z` becomes 0 empty should be true
35                 _front.x = 1;
36             }
37             _front.y = _front.x;
38         }
39     }
40 
41     void popFront()
42     {
43         do
44         {
45             nextTriple();
46         } while (_front.x*_front.x + _front.y*_front.y != _front.z*_front.z);
47     }
48 
49     enum empty = false;
50 
51     private Triple _front = Triple(1, 1, 2);
52 }
53 
54 /// Get all Pythogorean triples in an infinite generator.
55 auto pythagoreanTriples(T = size_t)()
56 	=> PossiblePythagoreanTriples!T();
57 
58 ///
59 @safe pure nothrow @nogc unittest
60 {
61     auto t = pythagoreanTriples!size_t;
62     alias Triple = typeof(t.front);
63     assert(t.front == Triple(1,1,2)); t.popFront();
64     assert(t.front == Triple(3,4,5)); t.popFront();
65     assert(t.front == Triple(6,8,10)); t.popFront();
66     assert(t.front == Triple(5,12,13)); t.popFront();
67     assert(t.front == Triple(9,12,15)); t.popFront();
68     assert(t.front == Triple(8,15,17)); t.popFront();
69     assert(t.front == Triple(12,16,20)); t.popFront();
70 }