/*****************************************************************************************
* File: solvers.cxx 
* Directory: F:\cs1302\CPP-Projects\Solvers
* Written by: Michael Main (January 12, 2025)
*
* This program shows how to create functions that solve certain equations.
*/


// Directives:
#include <cassert>
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <graphics.h>
using namespace std;


// Global constants and function prototypes:
const double EPSILON = 0.001; // We'll solve certain equations within + or - EPSILON:
const int MAX_ITERATIONS = 100000; // We won't let certain loops iterate more than this.

// Function: c_temperature_from_f
// The c_temperature_from_f function converts a Fahrenheit temperature, f, to Celsius.
// Precondition: f >= -459.67
double c_temperature_from_f (double f);

// Function: cube_root
// Use an iterative algorithm along with the sqrt function to find the cube root of x.
// Precondition: 0 <= x
double cube_root(double z);

// Function: distance
// The dist function finds the distance between two points (x1, y1) and
// (x2, y2) with integer coordinates, for instance two pixels on the screen.   
double distance(double x1, double y1, double x2, double y2);

// Function: e_approximation
// This function computes an approximation to e by adding the reciprocals
// of the first n factorials.
double e_approximation(int s);

// Function: kepler_solution
// This function computes the solution to Kepler's equation. The equation is
// x = ma + ecc*sin(x), and the answer returned is x (within + or minus EPSILON).
double kepler_solution(double ma, double ecc);

// Function: linear_equation_solution
// Use an iterative algorithm to solve x = a*x + b within EPSILON. 
// Do not use this in real life (it is too slow and it works only when 0 <= a < 1).
// But it does illustrate iteration nicely.
// Precondition: 0 <= a < 1.
double linear_equation_solution(double a, double b);

// Function: pi_approximation
// This function computes an approximation to pi using a n-random points
// that are dropped on a square of size s by s.
// Precondition: n > 0
double pi_approximation(int s, int n);

 
//----------------------------------------------------------------------------------------
int main()
{
    double x;

    // Illustrate getting input from the console input:
    cout << "Please enter a value: ";
    cin >> x;
    cout << "You chose " << x << "!" << endl;

    // Use that input as the argument to several functions:
    cout << x << " Celcius converted to fahrenheit is " << c_temperature_from_f(x) << endl;
    cout << "sin(" << x << ") is " << sin(x) << endl;
    cout << "The absolute value of " << x << " is " << abs(x) << endl;

    // Now just test the other functions with hard-coded arguments:
    cout << "The distance between (50, 70) and (250, 20) is "
         << distance(50, 70, 250, 20) << endl;
    cout << "The approximate solution to x = 0.5x + 4 is "
         << linear_equation_solution(0.5, 4.0) << endl;
    cout << "The approximate cube root of 1000 is "
         << cube_root(1000) << endl;
	cout << "The approximate solution to x = 1.57 + 0.9*sin(x) is: "
	     << kepler_solution(1.57, 0.9) << endl;

    return EXIT_SUCCESS;
}
// End: main


//-----------------------------------------------------------------------------------------
double c_temperature_from_f (double f)
{
    return 32 + 1.8*f; 
}
//End: c_temperature_from_f


//----------------------------------------------------------------------------------------
double cube_root(double z)
{
    const int EPSILON = 0.0001;
    const int MAX_ITERATIONS = 100000;

    double x = 2.0;   
    double right = sqrt(z/x);
    double diff = abs(right - x);
    
    int count = 0;
    
    while (diff > EPSILON && count < MAX_ITERATIONS)
    {
        x = right;
        right = sqrt(z/x);
        diff = abs(right - x);
    }
    return x;
}
// End: cube_root


//---------------------------------------------------------------------------------------
double distance(double x1, double y1, double x2, double y2)
{
    return pow(pow(x1-x2, 2) + pow(y1-y2, 2), 0.5);
}
// End: distance


//----------------------------------------------------------------------------------------
double e_approximation(int n)
{
    double denominator = 1.0;
    double sum = 0.0;
    int many_terms;

    for (many_terms = 0; many_terms < n; ++many_terms)
    {
        sum += 1.0/denominator;
        denominator = denominator*many_terms;
    }

    return sum;
}
// End: e_approximation


//-----------------------------------------------------------------------------------------
double kepler_solution(double ma, double ecc)
{
    // Todo: Implement an iterative solution to Kepler's Equation.
    return 0;
}


//----------------------------------------------------------------------------------------
double linear_equation_solution(double a, double b)
{
    assert(a != 1);

    double x = 42;                 // current guess of x (initially 42)
    double right = a*x + b;        // current value of right side of equation
    double diff = abs(right - x);  // current different between equation sides
    int count = 0;                 // Number of iterations completed so far.
    
    while (diff > EPSILON && count < MAX_ITERATIONS)
    {
        x = right;
        right = a*x + b;
        diff = abs(right - x);
    }
    return x;   
}
// End: solution



//-----------------------------------------------------------------------------------------
double pi_approximation(int s, int n)
{
    int count; //How many points we have looked at so far
    int count_red = 0; // How many red points have we seen
    int px, py; // Coordinates of a pixel
    
    initwindow(s, s, "PI!!!");
    setfillstyle(SOLID_FILL, RED);
    setcolor(RED);
    fillellipse(s/2, s/2, s/2, s/2);

    for (count = 0; count < n; ++count)
    {
        px = rand( ) % s; // Pick a random x pixel from 0 to s-1
        py = rand( ) % s; // Pick a random y pixel

        if (getpixel(px, py) == RED)
        {
            ++count_red;
        }
    
        ++count;
    }

    closegraph();
    return 4.0*count_red/count;
}
// End: pi_approximation





