//

#include <chrono>
#include <iostream>
#include <vector>
#include <tuple>
#include <cassert>
#include <cmath>

using namespace std;
void benchmark();
void benchmark_proper();
int find_third_member_of_ptt(int z, int x);

int main()
{
	benchmark();
	benchmark_proper();

}

////////////////////////////////////////////////////////////////////////////////////////////////////
//  Benchmark Code
////////////////////////////////////////////////////////////////////////////////////////////////////

class timer
{
private:
    std::chrono::high_resolution_clock::time_point start_;
public:
    timer()
    {
        reset();
    }
    void reset()
    {
        start_ = std::chrono::high_resolution_clock::now();
    }
    std::chrono::milliseconds elapsed() const
    {
        return std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::high_resolution_clock::now() - start_);
    }
    friend std::ostream &operator<<(std::ostream &sout, timer const &t)
    {
        return sout << t.elapsed().count() << "ms";
    }
};
static constexpr int max_triples = 2000;

void benchmark()
{
    timer t;
    t.reset();
	vector<tuple<int,int,int>> ptt;
    for(int z = 1;; ++z)
    {
        for(int x = 1; x <= z; ++x)
        {
            for(int y = x; y <= z; ++y)
            {
                if(x*x + y*y == z*z)
                {
                    ptt.push_back(make_tuple(x,y,z));
                    if(ptt.size() == max_triples)
                        goto done;
                }
            }
        }
    }
done:
    std::cout << t << '\n';
	//for (const auto & triplet :  ptt)
	//	cout << get<0>(triplet) << " " << get<1>(triplet) << " " << get <2>(triplet) << endl;
}
// -1 == not found, yes boost optional would be better choice
int find_third_member_of_ptt(int z, int x)
{
	assert(z>x);
	const int diff  = z*z - x*x; 
	const double sqroot = sqrt(diff);
	const int candidate1 = (int)sqroot;
	const int candidate2 = (int)sqroot +1;
	// next 2 checks are the same and should be in a function
	if ( (candidate1 >= x) && //prevents duplicates
		 (z*z == x*x + candidate1*candidate1))
		return candidate1;
	if ((candidate2 >= x) && //prevents duplicates
	     (z*z == x*x + candidate2*candidate2))
		return candidate2; 
	return -1;
}

void benchmark_proper()
{
    timer t;
    t.reset();
	vector<tuple<int,int,int>> ptt;
    for(int z = 1;; ++z)
    {
        for(int x = 1; x < z; ++x)
        {
				if (find_third_member_of_ptt(z,x) !=-1)
                {
					ptt.push_back(make_tuple(x,find_third_member_of_ptt(z,x),z)); // we are so fast we dont need to remember the rv of a function...
                    if(ptt.size() == max_triples)
                        goto done; // so great that we have goto in if now, goto == maintainable code, we could put it outside if but *I* know check only needs to be done if push_back occured 
				}
        }
    }
done:
    std::cout << t << '\n';
	//for (const auto & triplet :  ptt)
	//	cout << get<0>(triplet) << " " << get<1>(triplet) << " " << get <2>(triplet) << endl;
}

