#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>

#define STRLEN 1024
#define MIN 0
#define MAX 100
#define M_MIN 0.0
#define M_MAX 10.0
#define Q_MIN 0.0
#define Q_MAX 10.0
#define N_PROVE 500
#define SI 1
#define NO 0

#define ABS(X) ((X<0)?-X:X)

typedef int* pint;
typedef float* pfloat;
typedef FILE* pfile;

typedef struct _dot
  {
    double x;
    double y;
  }
dot;

typedef dot* pdot;

double randminmax(double min, double max)
  {
    return ((((double)rand())/RAND_MAX)*(max-min))+min;
  }

int conferma(void)
  {
    char input[STRLEN];
    printf("Confermi? [S,s,Y,y = conferma / ALTRO = non conferma]: ");
    scanf("%s",input);
    switch (input[0])
      {
        case 'y':
        case 'Y':
        case 's':
        case 'S':
            return SI;
        default:
            return NO;
      }
  }

int dotCounter(double m, double q, pdot array, int numero_punti, double epsilon)
  {
    pdot p,pmax;
    int i;
    for(p=array,pmax=array+numero_punti,i=0;p<pmax;p++)
      {
        if(ABS(p->y-(m*(p->x)+q))<epsilon) i++;
      }
    return i;
  }

int main(void)
  {
    int numero_punti;
    unsigned i_m,i_q,n,n_max;
    double epsilon,rumore,m,q,m_best,q_best,dm,dq;
    char input[STRLEN];
    pdot pcoord,p,pmax;
    srand(time(NULL));

    do
      {
        printf("Inserisci il numero di punti (strettamente positivo): ");
        scanf("%s",input); numero_punti=atoi(input);

        printf("Inserisci il valore per epsilon: ");
        scanf("%s",input); epsilon=atof(input);

        printf("Inserisci il valore per r: ");
        scanf("%s",input); rumore=atof(input);

        printf("Insersici il valore per m: ");
        scanf("%s",input); m=atof(input);

        printf("Inserisci il valore per q: ");
        scanf("%s",input); q=atof(input);

        printf("Ho ricevuto i seguenti valori:\nNumero punti: %d\nEpsilon: %f\nRumore: %f\nCoeff. angolare: %f\nIntercetta: %f\n",numero_punti,epsilon,rumore,m,q);
      }
    while(!conferma());

    if(numero_punti<0) goto err_num;

    if(NULL==(pcoord=(pdot)malloc(sizeof(dot)*numero_punti))) goto err_mem;

    for(p=pcoord,pmax=p+numero_punti;p<pmax;p++)
      {
        p->y=m*(p->x=randminmax(MIN,MAX))+q+randminmax(-rumore,rumore);
      }

    dm=(M_MAX-M_MIN)/(N_PROVE-1);
    dq=(Q_MAX-Q_MIN)/(N_PROVE-1);

    for(i_m=n=n_max=0,m_best=q_best=0,m=M_MIN;i_m<N_PROVE;i_m++,m+=dm)
      {
        for(i_q=0,q=Q_MIN;i_q<N_PROVE;i_q++,q+=dq)
          {
            //printf("Tentando m=%f, q=%f\n",m,q);
            if((n=dotCounter(m,q,pcoord,numero_punti,epsilon))>n_max)
              {
                n_max=n;
                m_best=m;
                q_best=q;
                printf("Dati aggiornati hits %d, mb=%f, qb=%f\n",n_max,m_best,q_best);
              }
            
          }
        
      }

    free(pcoord);

    printf("Ho trovato un coefficiente angolare di %f, un'intercetta di %f, con un numero di hit pari a %d.\n",m_best,q_best,n_max);

    return EXIT_SUCCESS;
    err_mem:
        printf("ERRORE: memoria insufficiente\n");
        return EXIT_FAILURE;
    err_num:
        printf("ERRORE: hai inserito un numero negativo\n");
        return EXIT_FAILURE;
}