/*
 * Problema 1A
 *
 */

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

struct multime {
        unsigned char a;
};

void init(struct multime *m)
{
        m->a = 0;
}

void add(struct multime *m, int x)
{
        m->a = m->a | (1 << x);
}

void del(struct multime *m, int x)
{
        m->a = m->a & ~(1 << x);
}

int contains(struct multime *m, int x)
{
        return m->a & (1 << x);
}

void print(struct multime *m)
{
        int i;
        printf("{ ");
        for (i = 0; i < 8; i++)
                if (contains(m, i))
                        printf("%d ", i);
        printf("}\n");
}

int main()
{
        struct multime m;
        init(&m);
        add(&m, 3);
        add(&m, 5);
        add(&m, 2);
        add(&m, 7);
        print(&m);
        del(&m, 2);
        del(&m, 7);
        print(&m);
        return 0;
}

/*
 * Problema 1B
 *
 */

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

struct multime {
        int n;
        unsigned char *a;
};

void init(struct multime *m, int n)
{
        int i, size = n / (8 * sizeof(unsigned char));
        m->n = n;

        if (n % (8 * sizeof(unsigned char)) != 0)
                size++;
        m->a = (unsigned char *) malloc (size * sizeof(unsigned char));

        for (i = 0; i < size; i++)
                m->a[i] = 0;
}

void add(struct multime *m, int x)
{
        int idx, cnt;
        idx = x / (8 * sizeof(unsigned char));
        cnt = x % (8 * sizeof(unsigned char));
        m->a[idx] = m->a[idx] | (1 << cnt);
}

void del(struct multime *m, int x)
{                                
        int idx, cnt;
        idx = x / (8 * sizeof(unsigned char));
        cnt = x % (8 * sizeof(unsigned char));
        m->a[idx] = m->a[idx] & ~(1 << cnt);
}

int contains(struct multime *m, int x)
{  
        int idx, cnt;
        idx = x / (8 * sizeof(unsigned char));
        cnt = x % (8 * sizeof(unsigned char));
        return m->a[idx] & (1 << cnt);
}

void print(struct multime *m)
{
        int i;
        printf("{ ");
        for (i = 0; i < m->n; i++)
                if (contains(m, i))
                        printf("%d ", i);
        printf("}\n");
}

void delete(struct multime *m)
{
        free(m->a);
}

int main()
{
        struct multime m;
        init(&m, 200);
        add(&m, 3);
        add(&m, 35);
        add(&m, 112);
        add(&m, 199);
        print(&m);
        del(&m, 35);
        del(&m, 199);
        print(&m);
        delete(&m);
        return 0;
}

/*
 * Problema 2
 *
 */

#include <stdio.h>
#include <math.h>

double integrala(double (*func)(double x), double a, double b, int n)
{
        double sum = 0, x1, x2, pas = (a - b) / n;
        int i;
        for (i = 1; i < n; i++) {
                x1 = pas * (i - 1);
                x2 = pas * i;
                //aria trapezului = (b + B) * H / 2
                sum += (func(x1) + func(x2)) * pas / 2;
        }
        return sum;
}            

int main()
{
        printf("Integrala din sin(x) de la 0 la PI = %.2f\n",
                        integrala(sin, 0, M_PI, 100));
        printf("Integrala din cos(x) de la 0 la PI = %.2f\n",
                        integrala(cos, 0, M_PI, 100));
        return 0;
}

/*
 * Problema 3
 *
 */

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

#define MAX 100

typedef enum { C, S, A } tip;

typedef struct MATERIA {
        char nume[16];
        int ore_curs;
        tip tip_examen;
} MATERIA;

int citire_MAT(MATERIA *mat)
{
        int i, n;
        char ch;

        getchar(); // golim bufferul de "\n"

        printf("Nume: ");
        fgets(mat->nume, 16, stdin);
        n = strlen(mat->nume);
        mat->nume[n - 1] = '\0';
        n--;
        for (i = 0; i < n; i++)
                if (!isalpha(mat->nume[i]) && !isblank(mat->nume[i]))
                        return -1;

        printf("Ore curs: ");
        scanf("%d", &mat->ore_curs);
        if (mat->ore_curs <= 0)
                return -1;
        getchar(); // golim bufferul de "\n"
        printf("Tip examen (C / S / A): ");
        scanf("%c", &ch);
        switch (tolower(ch)) {
                case 'c': mat->tip_examen = C; break;
                case 's': mat->tip_examen = S; break;
                case 'a': mat->tip_examen = A; break;
                defaultreturn -1;
        }
        return 0;
}

void citire_PROGRAMA(MATERIA prog[], int n)
{
        int i, ok;
        for (i = 0; i < n; i++) {
                printf("Introduceti datele pentru materia %d.\n", i);
                ok = citire_MAT(&prog[i]);
                while (ok == -1) {
                        printf("Date gresite. Reintroduceti datele.\n");
                        ok = citire_MAT(&prog[i]);
                }
        }
}

void afisare(char ch, int nr, MATERIA prog[], int n)
{
        int i;
        tip tp;
        switch (tolower(ch)) {
                case 'c': tp = C; break;
                case 's': tp = S; break;
                case 'a': tp = A; break;
        }
        printf("Materiile care au tipul %c si numarul de ore egal cu %d:\n", ch, nr);
        for (i = 0; i < n; i++)
                if (prog[i].tip_examen == tp && prog[i].ore_curs == nr)
                        printf("%s\n", prog[i].nume);
}

int main()
{
        MATERIA PROGRAMA[MAX];
        int n, nr;
        char ch;
        printf("Introduceti numarul de materii: ");
        scanf("%d", &n);
        citire_PROGRAMA(PROGRAMA, n);
        getchar(); //golim bufferul de "\n"
        printf("Tipul examenului: ");
        scanf("%c", &ch);
        printf("Numarul de ore: ");
        scanf("%d", &nr);
        afisare(ch, nr, PROGRAMA, n);
        return 0;
}

/*
 * Problema 4
 *
 */

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

typedef struct MATRICE {
        int n, m;
        int **a;
} MATRICE;

MATRICE *creaza_MATRICE(int n, int m)
{
        int i;
        MATRICE *mat;

        mat = (MATRICE*) malloc (sizeof(MATRICE)); // alocam memorie pentru structura

        mat->n = n;
        mat->m = m;  

        // si pentru matricea propriu-zisa
        mat->a = (int**) malloc (n * sizeof(int*)); // pentru pointerii la linii
        for (i = 0; i < n; i++)
                mat->a[i] = (int*) malloc (m * sizeof(int)); // si pentru elementele de pe fiecare linie
        return mat;
}

void sterge_MATRICE(MATRICE *a)
{
        int i;
        for (i = 0; i < a->n; i++)
                free(a->a[i]);
        free(a->a);
}

MATRICE *citeste_MATRICE(MATRICE *a)
{
        int i, j;
        for (i = 0; i < a->n; i++)
                for (j = 0; j < a->m; j++) {
                        printf("a[%d][%d] = ", i, j);
                        scanf("%d", &a->a[i][j]);
                }
        return a;
}

void scrie_MATRICE(MATRICE *a)
{
        int i, j;
        for (i = 0; i < a->n; i++) {
                for (j = 0; j < a->m; j++)
                        printf("%d ", a->a[i][j]);
                printf("\n");
        }
        printf("\n");
}

MATRICE *aduna_MATRICE(MATRICE *a, MATRICE *b)
{
        MATRICE *s;
        int i, j;

        if (a->n != b->n || a->m != b->m)
                return NULL;

        s = creaza_MATRICE(a->n, a->m);
        for (i = 0; i < a->n; i++)
                for (j = 0; j < a->m; j++)
                        s->a[i][j] = a->a[i][j] + b->a[i][j];

        return s;
}

MATRICE *inmulteste_MATRICE(MATRICE *a, MATRICE *b)
{
        MATRICE *s;
        int i, j, k;

        if (a->m != b->n)
                return NULL;

        s = creaza_MATRICE(a->n, b->m);
        for (i = 0; i < s->n; i++)
                for (j = 0; j < s->m; j++) {
                        s->a[i][j] = 0;
                        for (k = 0; k < a->m; k++)
                                s->a[i][j] += a->a[i][k] * b->a[k][j];
                }

        return s;
}

int main()
{
        int n, m;
        MATRICE *a, *b, *s, *p;
        printf("Introduceti dimensiunea pentru prima matrice.\n");
        printf("n = ");
        scanf("%d", &n);
        printf("m = ");
        scanf("%d", &m);
        a = creaza_MATRICE(n, m);
        citeste_MATRICE(a);

        printf("Introduceti dimensiunea pentru cea de-a 2-a matrice.\n");
        printf("n = ");
        scanf("%d", &n);
        printf("m = ");
        scanf("%d", &m);
        b = creaza_MATRICE(n, m);
        citeste_MATRICE(b);

        s = aduna_MATRICE(a, b);
        if (s == NULL)
                printf("Nu s-a putut calcula suma.\n");
        else {
                printf("Suma lor este:\n");
                scrie_MATRICE(s);
        }

        p = inmulteste_MATRICE(a, b);
        if (p == NULL)
                printf("Nu s-a putut calcula produsul.\n");
        else {
                printf("Produsul lor este:\n");
                scrie_MATRICE(p);
        }

        sterge_MATRICE(a);
        sterge_MATRICE(b);
        sterge_MATRICE(s);
        sterge_MATRICE(p);

        return 0;
}