/*

Rotiranje matrice:

- udesno za 90 stepeni, tri verzije
- ulevo  za 90 stepeni
- oko horizontalne ose, dve verzije
- oko vertikalne ose, dve verzije

*/


#include <stdio.h>
#include <stdlib.h> // zbog exit()

#define MAX_SIZE 100


// Prikazuje matricu M[][] koja ima r redova i k kolona
void prikazi_matricu( char *tekst, int M[][MAX_SIZE], int r, int k )
{
    int i, j;

    printf("\n%s\n\n",tekst);

    for(i=0;i<r;i++) {    // Stampamo matricu M[][]
        for(j=0;j<k;j++)
            printf(" %4d",M[i][j]);

        printf("\n\n");   // novi red matrice
    }
    printf("\n");
}


// Formira matricu M[][] koja ima r redova i k kolona
// Elementi su redni brojevi.
void formiraj_matricu( int M[][MAX_SIZE], int r, int k )
{
    int i, j;

    for(i=0;i<r;i++)
        for(j=0;j<k;j++)
            M[i][j] = i*k + j+1;
}


// Funkcije koje ne manjaju matricu M vec je samo prikazju izmenjenu


// Prikazuje matricu rotiranu oko horizontalne ose.
void prikazi_matricu_rotiranu_oko_horizontalne_ose( int M[][MAX_SIZE], int r, int k )
{
   int i,j;

    for(i=r-1;i>=0;i--){    // za sve redove matrice M
        for(j=0;j<k;j++){       // za sve kolone matrice M
            printf(" %4d",M[i][j]);
        }
        printf("\n\n");
    }
}


// Prikazuje matricu rotiranu oko horizontalne ose, verzija 1.
void prikazi_matricu_rotiranu_oko_horizontalne_ose_v1( int M[][MAX_SIZE], int r, int k )
{
   int i,j,ip=r-1,jp;       // ip i jp su indeksi za prikaz M[ip][jp]

    for(i=0;i<r;i++){       // za sve redove matrice M
        jp=0;
        for(j=0;j<k;j++)        // za sve kolone matrice M
            printf(" %4d",M[ip][jp++]);
        ip--;
        printf("\n\n"); // novi red matrice
    }
}


// Prikazuje matricu rotiranu oko vertikalne ose, verzija 1.
void prikazi_matricu_rotiranu_oko_vertikalne_ose_v1( int M[][MAX_SIZE], int r, int k )
{
   int i,j,ip=0,jp;     // ip i jp su indeksi za prikaz M[ip][jp]

    for(i=0;i<r;i++){       // za sve redove matrice M
        jp=k-1;
        for(j=0;j<k;j++)        // za sve kolone matrice M
            printf(" %4d",M[ip][jp--]);
        ip++;
        printf("\n\n"); // novi red matrice
    }
}


// Prikazuje matricu rotiranu oko vertikalne ose.
void prikazi_matricu_rotiranu_oko_vertikalne_ose( int M[][MAX_SIZE], int r, int k )
{
   int i,j;

    for(i=0;i<r;i++){       // za sve redove matrice M
        for(j=k-1;j>=0;j--)        // za sve kolone matrice M
            printf(" %4d",M[i][j]);
        printf("\n\n"); // novi red matrice
    }
}


// Prikazuje matricu rotiranu udesno za 90 stepeni, verzija 2.
// Prvi je donji levi element i njegova kolona se prikazuje unazad kao prvi red.
// Kolone postaju redovi i prikazuju se unazad.
void prikazi_matricu_rotiranu_udesno_za_90_stepeni_v2( int M[][MAX_SIZE], int r, int k )
{
   int i,j,ip,jp=0;     // ip i jp su indeksi za prikaz M[ip][jp]

    for(i=0;i<r;i++){       // za sve redove matrice M
        ip=r-1;
        for(j=0;j<k;j++)        // za sve kolone matrice M
            printf(" %4d",M[ip--][jp]);
        jp++;
        printf("\n\n"); // novi red matrice
    }
}


// Prikazuje matricu rotiranu udesno za 90 stepeni, verzija 1.
// Prvi je donji levi element i njegova kolona se prikazuje unazad kao prvi red.
// Kolone postaju redovi i prikazuju se unazad.
void prikazi_matricu_rotiranu_udesno_za_90_stepeni_v1( int M[][MAX_SIZE], int r, int k )
{
    int i,j;

    for(j=0;j<k;j++){
        for(i=r-1;i>=0;i--)
            printf(" %4d",M[i][j]);
        printf("\n\n"); // novi red matrice
    }
}


// Prikazuje matricu rotiranu udesno za 90 stepeni.
// Prvi je donji levi element i njegova kolona se prikazuje unazad kao prvi red.
// Kolone postaju redovi i prikazuju se unazad.
void prikazi_matricu_rotiranu_udesno_za_90_stepeni( int M[][MAX_SIZE], int r, int k )
{
    int i,j;

    for(i=0;i<k;i++){
        for(j=k-1;j>=0;j--)
            printf(" %4d",M[j][i]); // PAZNJA, indeksi su zamenili mesta M[j][i]
        printf("\n\n"); // novi red matrice
    }
}


// Prikazuje matricu rotiranu ulevo za 90 stepeni.
// Prvi je gornji desni element i njegova prva desna kolona se prikazuje kao prvi red.
// Kolone postaju redovi.
void prikazi_matricu_rotiranu_ulevo_za_90_stepeni( int M[][MAX_SIZE], int r, int k )
{
   int i,j,ip,jp=k-1;   // ip i jp su indeksi za prikaz M[ip][jp]

    for(i=0;i<r;i++){       // za sve redove matrice M
        ip=0;
        for(j=0;j<k;j++)        // za sve kolone matrice M
            printf(" %4d",M[ip++][jp]);
        jp--;
        printf("\n\n"); // novi red matrice
    }
}


// Kopira matricu M u matricu M1, r je broj redova, k je broj kolona
void kopiraj_matricu( int M1[][MAX_SIZE], int M[][MAX_SIZE], int r, int k )
{
    int i,j;

    for(i=0;i<r;i++)        // za sve redove matrice M
        for(j=0;j<k;j++)        // za sve kolone matrice M
            M1[i][j] = M[i][j];
}


// Funkcije koje manjaju matricu M


// Rotira matricu udesno za 90 stepeni.
void rotiraj_matricu_udesno_za_90_stepeni( int M[][MAX_SIZE], int r, int k )
{
    int M1[MAX_SIZE][MAX_SIZE]; // deklarisemo novu matricu M1
    int i,j;

    // Matricu M kopiramo u matricu M1
    kopiraj_matricu(M1,M,r,k);  // kopira matricu M u matricu M1

    // Ponovo formiramo matricu M tako sto iz matrice M1 uzimamo
    // odgovarajuce elemente i stavljamo ih u matricu M.
    for(i=0;i<r;i++)        // za sve redove matrice M
        for(j=0;j<k;j++)        // za sve kolone matrice M
            M[i][j] = M1[k-1-j][i];
}


// Rotira matricu ulevo za 90 stepeni.
void rotiraj_matricu_ulevo_za_90_stepeni( int M[][MAX_SIZE], int r, int k )
{
    int M1[MAX_SIZE][MAX_SIZE]; // deklarisemo novu matricu M1
    int i,j;

    // Matricu M kopiramo u matricu M1
    kopiraj_matricu(M1,M,r,k);  // kopira matricu M u matricu M1

    // Ponovo formiramo matricu M tako sto iz matrice M1 uzimamo
    // odgovarajuce elemente i stavljamo ih u matricu M.
    for(i=0;i<r;i++)        // za sve redove matrice M
        for(j=0;j<k;j++)        // za sve kolone matrice M
            M[i][j] = M1[j][r-1-i];
}


// Rotira matricu oko horizontalne ose.
void rotiraj_matricu_oko_horizontalne_ose( int M[][MAX_SIZE], int r, int k )
{
    int M1[MAX_SIZE][MAX_SIZE]; // deklarisemo novu matricu M1
    int i,j;

    // Matricu M kopiramo u matricu M1
    kopiraj_matricu(M1,M,r,k);  // kopira matricu M u matricu M1

    // Ponovo formiramo matricu M tako sto iz matrice M1 uzimamo
    // odgovarajuce elemente i stavljamo ih u matricu M.
    for(i=0;i<r;i++)        // za sve redove matrice M
        for(j=0;j<k;j++)        // za sve kolone matrice M
            M[i][j] = M1[r-i-1][j];
}


// Rotira matricu oko vertikalne ose.
void rotiraj_matricu_oko_vertikalne_ose( int M[][MAX_SIZE], int r, int k )
{
    int M1[MAX_SIZE][MAX_SIZE]; // deklarisemo novu matricu M1
    int i,j;

    // Matricu M kopiramo u matricu M1
    kopiraj_matricu(M1,M,r,k);  // kopira matricu M u matricu M1

    // Ponovo formiramo matricu M tako sto iz matrice M1 uzimamo
    // odgovarajuce elemente i stavljamo ih u matricu M.
    for(i=0;i<r;i++)        // za sve redove matrice M
        for(j=0;j<k;j++)        // za sve kolone matrice M
            M[i][j] = M1[i][k-1-j];
}



int main(void)
{
    int M[MAX_SIZE][MAX_SIZE];

    int i, r=4, k=4;   // r je broj redova a k je broj kolona matrice M[][]

/*
    printf("\n Unesi broj redova matrice M[r][k] (manji od 21) : r = ");
    scanf("%d", &r);
    printf("\n");

    printf("\n Unesi broj kolona matrice M[%d][k] (manji od 21) : k = ",r);
    scanf("%d", &k);
    printf("\n");

    if ( r > 20 || k > 20 ) {
        printf("\n Zbog prikaza nema smisla da broj redova matrice bude veci od 20 \n");
        printf("\n ili broj kolona matrice bude veci od 20 !!! \n");
        exit(1);
    }
*/

    formiraj_matricu(M,r,k);
    prikazi_matricu(" Matrica M je: ",M,r,k);

    printf("\n Funkcije koje ne menjaju matricu M vec je samo prikazju izmenjenu : \n\n");

    printf(" \n Matrica rotirana udesno za 90 stepeni je: \n\n");
    prikazi_matricu_rotiranu_udesno_za_90_stepeni(M,r,k);

    printf(" \n Matrica rotirana udesno za 90 stepeni v1 je: \n\n");
    prikazi_matricu_rotiranu_udesno_za_90_stepeni_v1(M,r,k);

    printf(" \n Matrica rotirana udesno za 90 stepeni v2 je: \n\n");
    prikazi_matricu_rotiranu_udesno_za_90_stepeni_v2(M,r,k);

    printf(" \n Matrica rotirana ulevo za 90 stepeni je: \n\n");
    prikazi_matricu_rotiranu_ulevo_za_90_stepeni(M,r,k);

    printf(" \n Matrica rotirana oko horizontalne ose je: \n\n");
    prikazi_matricu_rotiranu_oko_horizontalne_ose(M,r,k);

    printf(" \n Matrica rotirana oko horizontalne ose v1 je: \n\n");
    prikazi_matricu_rotiranu_oko_horizontalne_ose_v1(M,r,k);

    printf(" \n Matrica rotirana oko vertikalne ose je: \n\n");
    prikazi_matricu_rotiranu_oko_vertikalne_ose(M,r,k);

    printf(" \n Matrica rotirana oko vertikalne ose v1 je: \n\n");
    prikazi_matricu_rotiranu_oko_vertikalne_ose_v1(M,r,k);

    prikazi_matricu(" Matrica M je: ",M,r,k);


    printf("\n Funkcije koje menjaju matricu M : \n\n");

    rotiraj_matricu_udesno_za_90_stepeni(M,r,k);
    prikazi_matricu(" Matrica rotirana udesno za 90 stepeni je: ",M,r,k);

    formiraj_matricu(M,r,k);    // resetujemo matricu M jer je bila izmenjena
    rotiraj_matricu_ulevo_za_90_stepeni(M,r,k);
    prikazi_matricu(" Matrica rotirana ulevo za 90 stepeni je: ",M,r,k);

    formiraj_matricu(M,r,k);    // resetujemo matricu M jer je bila izmenjena
    rotiraj_matricu_oko_horizontalne_ose(M,r,k);
    prikazi_matricu(" Matrica rotirana oko horizontalne ose je: ",M,r,k);

    formiraj_matricu(M,r,k);    // resetujemo matricu M jer je bila izmenjena
    rotiraj_matricu_oko_vertikalne_ose(M,r,k);
    prikazi_matricu(" Matrica rotirana oko vertikalne ose je: ",M,r,k);

    formiraj_matricu(M,r,k);    // resetujemo matricu M jer je bila izmenjena
    prikazi_matricu(" Matrica M je: ",M,r,k);


    return 0;
}