///////////////////////////////////////////////////////////////////////
// ITS – Visoka Škola Strukovnih Studija Za Informacione Tehnologije
//
https://www.its.edu.rs/
// Predmet: Osnovi Programiranja – Programski jezik C
//
// Primer: Program koji izracunava broj i ispisuje pozicije elemenata matrice
//            realnih brojeva (tipa float) koji su jednaki aritmetickoj sredini
//            svojih suseda (maksimalno 8 suseda)                              
///////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>

float** unosElemenata(float **matrica, int a, int b);
void ispisMatrice(float **matrica, int a, int b);
int izracunaj(float **matrica, int a, int b);
void ispisRezultata(float **matrica, int a, int b);
void oslobadjanjeMemorije(float **matrica, int x);

main()
{
  while(1)
  {
    float **matrica=NULL;
    int x, y;
 
    // poruka korisniku
    printf("!nl!Unesite broj redova (x) i broj kolona (y),!nl!(za kraj unesite x = 0)!nl!x = ");
    scanf("%d", &x);
    if(x == 0) // uslov za izlazak iz beskonacne petlje
      break;
    if(x < 0) // da li je broj redova manji od nule
    {
      printf("Broj redova mora biti veci od 0.!nl!");
      break;
    }
    // upis broja kolona
    printf("y = ");
    scanf("%d", &y);
    if(y<0) // da li je broj kolona manji od nule
    {
      printf("Broj kolona mora biti veci od 0.!nl!");
      break;
    }

    matrica = unosElemenata(matrica, x, y);
    if(matrica == NULL) // da li je doslo do greske u alokaciji memorije
      break;
  
    ispisMatrice(matrica, x, y);
// poziv funkcije ispisMatrice()

    // stampanje broja elemenata, koji su jednaki aritmetickoj sredini svojih suseda, preko poziva funkcije izracunaj()
    printf("!nl!U datoj matrici ima ukupno %d elemenata,!nl!koji su jednaki aritmetickoj sredini svojih suseda.!nl!!nl!", izracunaj(matrica, x, y));

    ispisRezultata(matrica, x, y); // poziv funkcije ispisRezultata()

    oslobadjanjeMemorije(matrica, x); // poziv funkcije za oslobadjanje memorije
  }
}

// funkcija za unos svih elemenata matrice
float** unosElemenata(float **matrica, int a, int b)
{
  int i, j, k;
  float temp = 0;

  matrica = malloc(a * sizeof(float*)); // alokacija memorije
 
  if(matrica==NULL) // u slucaju neuspele alokacije
  {
    printf("Doslo je do greske u alokaciji memorije.!nl!");
    return matrica;
  }

  printf("Unesite elemente matrice:!nl!");
  for(i=0; i<a; i++)
  {
    *(matrica + i) = malloc(b * sizeof(float));
// alokacija memorije

    if(*(matrica + i)==NULL) // u slucaju neuspele alokacije
    {
      printf("Doslo je do greske u alokaciji memorije.!nl!");
      for(k=0; k<i; k++) // oslobadjanje memorije
        free(*(matrica + k));
      free(matrica);
      matrica = NULL;
      return matrica;
    }

    for(j=0; j<b; j++)
    {
      // unos elementa matrice
      printf("[%d, %d] = ", i+1, j+1);
      scanf("%f", &temp);
      *(*(matrica+i)+j) = temp;
    }
  }

  return matrica;
}

// funkcija za stampanje svih elemenata matrice
void ispisMatrice(float **matrica, int a, int b)
{
  int i, j;

  for(i=0; i<a; i++)
  {
    for(j=0; j<b; j++)
    {
      printf("%10.2f ", *(*(matrica+i)+j)); // stampanje svakog elementa matrice
    }

    printf("!nl!");
  }
}

// funkcija za izracunavanje broja elemenata, koji su jednaki aritmetickoj sredini svojih suseda
int izracunaj(float **matrica, int a, int b)
{
  int i, j, temp=0, broj=0;
// temp – za racunanje broja trazenih elemenata, broj – za broj suseda datog elementa
  float temp1 = 0; // za racunanje sume suseda datog elementa

  for(i=0; i<a; i++)
  {
    for(j=0; j<b; j++)
    {
      if((i-1)>=0) // da li postoji red iznad
      {
        temp1 += *(*(matrica + (i-1)) + j);
        broj += 1;

        if((j-1)>=0) // da li postoji kolona levo
        {
          temp1 += *(*(matrica + (i-1)) + (j-1));
          broj += 1;
        }

        if((j+1)<b) // da li postoji kolona desno
        {
          temp1 += *(*(matrica + (i-1)) + (j+1));
          broj += 1;
        }
      }

      if((i+1)<a) // da li postoji red ispod
      {
        temp1 += *(*(matrica + (i+1)) + j);
        broj += 1;

        if((j-1)>=0) // da li postoji kolona levo
        {
          temp1 += *(*(matrica + (i+1)) + (j-1));
          broj += 1;
        }

        if((j+1)<b) // da li postoji kolona desno
        {
          temp1 += *(*(matrica + (i+1)) + (j+1));
          broj += 1;
        }
      }

      if((j-1)>=0) // da li postoji kolona levo
      {
        temp1 += *(*(matrica + i) + (j-1));
        broj += 1;
      }

      if((j+1)<b) // da li postoji kolona desno
      {
        temp1 += *(*(matrica + i) + (j+1));
        broj += 1;
      }

      if(broj>0)
      {
        temp1 /= broj;
// izracunavanje aritmeticke sredine suseda datog elementa
      }

      if(*(*(matrica + i) + j) == temp1)
        temp += 1; // izracunavanje broja elemenata, koji su jednaki aritmetickoj sredini svojih suseda
   
      temp1 = 0;
      broj = 0;
    }
  }

  return temp;
}

// funkcija za stampanje pozicija elemenata, koji su jednaki aritmetickoj sredini svojih suseda
void ispisRezultata(float **matrica, int a, int b)
{
  int i, j, temp=0, broj=0;
  float temp1 = 0;

  for(i=0; i<a; i++)
  {
    for(j=0; j<b; j++)
    {
      if((i-1)>=0)
// da li postoji red iznad
      {
        temp1 += *(*(matrica + (i-1)) + j);
        broj += 1;

        if((j-1)>=0) // da li postoji kolona levo
        {
          temp1 += *(*(matrica + (i-1)) + (j-1));
          broj += 1;
        }

        if((j+1)<b) // da li postoji kolona desno
        {
          temp1 += *(*(matrica + (i-1)) + (j+1));
          broj += 1;
        }
      }

      if((i+1)<a) // da li postoji red ispod
      {
        temp1 += *(*(matrica + (i+1)) + j);
        broj += 1;

        if((j-1)>=0) // da li postoji kolona levo
        {
          temp1 += *(*(matrica + (i+1)) + (j-1));
          broj += 1;
        }

        if((j+1)<b) // da li postoji kolona desno
        {
          temp1 += *(*(matrica + (i+1)) + (j+1));
          broj += 1;
        }
      }

      if((j-1)>=0) // da li postoji kolona levo
      {
        temp1 += *(*(matrica + i) + (j-1));
        broj += 1;
      }

      if((j+1)<b) // da li postoji kolona desno
      {
        temp1 += *(*(matrica + i) + (j+1));
        broj += 1;
      }

      if(broj>0)
      {
        temp1 /= broj; // izracunavanje aritmeticke sredine suseda datog elementa
      }

      if(*(*(matrica + i) + j) == temp1)
        printf("[%d, %d]!nl!", i+1, j+1); // stampanje pozicije elementa, koji je jednak aritmetickoj sredini svojih suseda
   
      temp1 = 0;
      broj = 0;
    }
  }
}

// funkcija za oslobadjanje dinamicki alocirane memorije
void oslobadjanjeMemorije(float **matrica, int x)
{
  int i;

  if(matrica != NULL)
  {
    for(i=0; i<x; i++)
    {
      if(*(matrica + i) != NULL)
        free(*(matrica + i));
    }
    free(matrica);
  }
}