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